Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Mar 2010 00:00:54 +0000 (16:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Mar 2010 00:00:54 +0000 (16:00 -0800)
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (370 commits)
  ARM: S3C2443: Add set_rate and round_rate calls for armdiv clock
  ARM: S3C2443: Remove #if 0 for clk_mpll
  ARM: S3C2443: Update notes on MPLLREF clock
  ARM: S3C2443: Further clksrc-clk conversions
  ARM: S3C2443: Change to using plat-samsung clksrc-clk implementation
  USB: Fix s3c-hsotg build following Samsung platform header moves
  ARM: S3C64XX: Reintroduce unconditional build of audio device
  ARM: 5961/1: ux500: fix CLKRST addresses
  ARM: 5977/1: arm: Enable backtrace printing on oops when PC is corrupted
  ASoC: Fix S3C64xx IIS driver for Samsung header reorg
  ARM: S3C2440: Fix plat-s3c24xx move of s3c2440/s3c2442 support
  [ARM] pxa: fix typo in mxm8x10.h
  [ARM] pxa/raumfeld: set GPIO drive bits for LED pins
  [ARM] pxa/zeus: Add support for mcp2515 CAN bus
  [ARM] pxa/zeus: Add support for onboard max6369 watchdog
  [ARM] pxa/zeus: Add Eurotech as the manufacturer
  [ARM] pxa/zeus: Correct the USB host initialisation flags
  [ARM] pxa/zeus: Allow usage of 8250-compatible UART in uncompress
  [ARM] pxa: refactor uncompress.h for non-PXA uarts
  [ARM] mmp2: fix incorrect calling of chip->mask_ack() for 2nd level cascaded IRQs
  ...

581 files changed:
Documentation/DMA-API.txt
Documentation/HOWTO
Documentation/IPMI.txt
Documentation/Makefile
Documentation/PCI/PCI-DMA-mapping.txt
Documentation/SubmitChecklist
Documentation/cgroups/cgroup_event_listener.c [new file with mode: 0644]
Documentation/cgroups/cgroups.txt
Documentation/cgroups/memcg_test.txt
Documentation/cgroups/memory.txt
Documentation/email-clients.txt
Documentation/filesystems/00-INDEX
Documentation/filesystems/Makefile [new file with mode: 0644]
Documentation/filesystems/dnotify.txt
Documentation/filesystems/dnotify_test.c [new file with mode: 0644]
Documentation/kobject.txt
Documentation/laptops/00-INDEX
Documentation/laptops/Makefile [new file with mode: 0644]
Documentation/laptops/dslm.c [new file with mode: 0644]
Documentation/laptops/laptop-mode.txt
Documentation/serial/tty.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sysctl/vm.txt
Documentation/timers/00-INDEX
Documentation/timers/Makefile [new file with mode: 0644]
Documentation/timers/hpet.txt
Documentation/timers/hpet_example.c [new file with mode: 0644]
Documentation/vm/00-INDEX
Documentation/vm/Makefile
Documentation/vm/hugepage-mmap.c [new file with mode: 0644]
Documentation/vm/hugepage-shm.c [new file with mode: 0644]
Documentation/vm/hugetlbpage.txt
Documentation/vm/map_hugetlb.c
Documentation/voyager.txt [deleted file]
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/include/asm/dma-mapping.h
arch/alpha/include/asm/pci.h
arch/alpha/include/asm/ptrace.h
arch/alpha/kernel/pci-noop.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/ptrace.c
arch/arm/Kconfig
arch/arm/common/it8152.c
arch/arm/configs/nuc950_defconfig
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/pci.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/calls.S
arch/arm/kernel/ptrace.c
arch/arm/kernel/ptrace.h
arch/arm/kernel/sys_arm.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/mach-ep93xx/include/mach/ts72xx.h
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-ixp4xx/include/mach/hardware.h
arch/arm/mach-pxa/am300epd.c
arch/arm/mach-pxa/corgi_ssp.c
arch/arm/mach-pxa/include/mach/hardware.h
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-s3c2410/h1940-bluetooth.c
arch/arm/mach-sa1100/jornada720_ssp.c
arch/arm/mach-w90x900/cpu.h
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/include/mach/fb.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/regs-ldm.h [new file with mode: 0644]
arch/arm/mach-w90x900/mach-nuc950evb.c
arch/arm/mach-w90x900/nuc950.c
arch/avr32/include/asm/ptrace.h
arch/avr32/kernel/ptrace.c
arch/blackfin/include/asm/dma-mapping.h
arch/cris/arch-v10/kernel/entry.S
arch/cris/arch-v10/kernel/ptrace.c
arch/cris/arch-v32/kernel/entry.S
arch/cris/arch-v32/kernel/ptrace.c
arch/cris/include/arch-v32/arch/ptrace.h
arch/cris/include/asm/pci.h
arch/cris/include/asm/unistd.h
arch/cris/kernel/sys_cris.c
arch/frv/include/asm/dma-mapping.h
arch/frv/include/asm/pci.h
arch/frv/include/asm/ptrace.h
arch/frv/include/asm/unistd.h
arch/frv/kernel/sys_frv.c
arch/frv/mb93090-mb00/pci-dma-nommu.c
arch/frv/mb93090-mb00/pci-dma.c
arch/h8300/include/asm/ptrace.h
arch/h8300/include/asm/unistd.h
arch/h8300/kernel/ptrace.c
arch/h8300/kernel/sys_h8300.c
arch/h8300/kernel/syscalls.S
arch/h8300/platform/h8300h/ptrace_h8300h.c
arch/h8300/platform/h8s/ptrace_h8s.c
arch/ia64/Kconfig
arch/ia64/include/asm/compat.h
arch/ia64/include/asm/pci.h
arch/ia64/include/asm/ptrace.h
arch/ia64/kernel/topology.c
arch/m32r/include/asm/ptrace.h
arch/m32r/include/asm/unistd.h
arch/m32r/kernel/ptrace.c
arch/m32r/kernel/sys_m32r.c
arch/m68k/include/asm/ptrace.h
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/entry.S
arch/m68k/kernel/sys_m68k.c
arch/m68knommu/kernel/ptrace.c
arch/m68knommu/kernel/sys_m68k.c
arch/m68knommu/kernel/syscalltable.S
arch/microblaze/kernel/ptrace.c
arch/mips/Kconfig
arch/mips/include/asm/compat.h
arch/mips/include/asm/pci.h
arch/mips/include/asm/unistd.h
arch/mips/kernel/linux32.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mips/txx9/generic/7segled.c
arch/mn10300/include/asm/dma-mapping.h
arch/mn10300/include/asm/ptrace.h
arch/mn10300/include/asm/unistd.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/sys_mn10300.c
arch/parisc/Kconfig
arch/parisc/include/asm/compat.h
arch/parisc/include/asm/pci.h
arch/parisc/include/asm/ptrace.h
arch/parisc/kernel/sys_parisc.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/syscalls.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/cacheinfo.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/syscalls.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/s390/include/asm/compat.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/qdio.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/entry.h
arch/s390/kernel/smp.c
arch/s390/kernel/sys_s390.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/time.c
arch/s390/lib/Makefile
arch/s390/mm/cmm.c
arch/score/include/asm/ptrace.h
arch/sh/Kconfig
arch/sh/include/asm/pci.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/syscalls.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/sys_sh.c
arch/sparc/Kconfig
arch/sparc/include/asm/compat.h
arch/sparc/include/asm/dma-mapping.h
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pci_64.h
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/sys_sparc_32.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/systbls.h
arch/sparc/kernel/systbls_64.S
arch/um/include/asm/dma-mapping.h
arch/um/include/asm/ptrace-generic.h
arch/um/kernel/ptrace.c
arch/um/kernel/syscall.c
arch/um/sys-i386/shared/sysdep/syscalls.h
arch/um/sys-i386/sys_call_table.S
arch/um/sys-i386/syscalls.c
arch/um/sys-x86_64/syscall_table.c
arch/um/sys-x86_64/syscalls.c
arch/x86/Kconfig
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/compat.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/sys_i386_32.c
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/syscall_table_32.S
arch/xtensa/include/asm/pci.h
arch/xtensa/include/asm/ptrace.h
arch/xtensa/kernel/ptrace.c
block/Kconfig
block/Kconfig.iosched
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-integrity.c
block/blk-sysfs.c
block/elevator.c
drivers/acpi/system.c
drivers/auxdisplay/cfag12864bfb.c
drivers/base/Kconfig
drivers/base/bus.c
drivers/base/class.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/devtmpfs.c
drivers/base/firmware_class.c
drivers/base/memory.c
drivers/base/node.c
drivers/base/platform.c
drivers/base/power/main.c
drivers/base/sys.c
drivers/block/floppy.c
drivers/block/osdblk.c
drivers/block/pktcdvd.c
drivers/char/hvc_iucv.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mem.c
drivers/char/mmtimer.c
drivers/char/n_tty.c
drivers/char/tty_audit.c
drivers/cpufreq/cpufreq.c
drivers/cpuidle/sysfs.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma.h
drivers/edac/e752x_edac.c
drivers/edac/edac_device_sysfs.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mpc85xx_edac.h
drivers/firewire/core-device.c
drivers/firmware/edd.c
drivers/firmware/efivars.c
drivers/firmware/iscsi_ibft.c
drivers/firmware/memmap.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/i2c/busses/i2c-omap.c
drivers/ieee1394/nodemgr.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_main.c
drivers/macintosh/windfarm_core.c
drivers/macintosh/windfarm_smu_controls.c
drivers/md/dm-sysfs.c
drivers/md/md.c
drivers/media/video/omap24xxcam.c
drivers/misc/phantom.c
drivers/misc/sgi-gru/grutables.h
drivers/mmc/core/core.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/core/sdio_ops.h
drivers/mmc/host/mxcmmc.c
drivers/mtd/ubi/build.c
drivers/net/bonding/bond_sysfs.c
drivers/net/ibmveth.c
drivers/net/iseries_veth.c
drivers/parisc/pdc_stable.c
drivers/pci/bus.c
drivers/pci/hotplug/fakephp.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/slot.c
drivers/pcmcia/ds.c
drivers/platform/x86/Kconfig
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/msi-laptop.c
drivers/pps/Kconfig
drivers/pps/Makefile
drivers/pps/clients/Kconfig [new file with mode: 0644]
drivers/pps/clients/Makefile [new file with mode: 0644]
drivers/pps/clients/pps-ktimer.c [new file with mode: 0644]
drivers/pps/clients/pps-ldisc.c [new file with mode: 0644]
drivers/rtc/hctosys.c
drivers/rtc/rtc-sysfs.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/cio/device.c
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/qdio_main.c
drivers/s390/net/Kconfig
drivers/s390/net/Makefile
drivers/s390/net/qeth_core_main.c
drivers/s390/net/smsgiucv.c
drivers/s390/net/smsgiucv.h
drivers/s390/net/smsgiucv_app.c [new file with mode: 0644]
drivers/s390/scsi/zfcp_qdio.c
drivers/scsi/ses.c
drivers/scsi/sgiwd93.c
drivers/scsi/sni_53c710.c
drivers/serial/8250.c
drivers/serial/amba-pl010.c
drivers/staging/asus_oled/asus_oled.c
drivers/uio/Kconfig
drivers/uio/Makefile
drivers/uio/uio.c
drivers/uio/uio_netx.c [new file with mode: 0644]
drivers/uio/uio_smx.c [deleted file]
drivers/usb/core/driver.c
drivers/uwb/driver.c
drivers/uwb/umc-bus.c
drivers/uwb/uwb-internal.h
drivers/uwb/wlp/sysfs.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/acornfb.c
drivers/video/arcfb.c
drivers/video/asiliantfb.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-lq035q1-fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/broadsheetfb.c
drivers/video/cobalt_lcdfb.c
drivers/video/efifb.c
drivers/video/epson1355fb.c
drivers/video/gbefb.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/mb862xx/mb862xxfb.c
drivers/video/modedb.c
drivers/video/nuc900fb.c [new file with mode: 0644]
drivers/video/nuc900fb.h [new file with mode: 0644]
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/q40fb.c
drivers/video/s3c2410fb.c
drivers/video/sa1100fb.c
drivers/video/sgivwfb.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sis/sis_main.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/via/Makefile
drivers/video/via/chip.h
drivers/video/via/dvi.c
drivers/video/via/dvi.h
drivers/video/via/global.c
drivers/video/via/global.h
drivers/video/via/hw.c
drivers/video/via/hw.h
drivers/video/via/iface.c [deleted file]
drivers/video/via/iface.h [deleted file]
drivers/video/via/lcd.c
drivers/video/via/share.h
drivers/video/via/via_utility.c
drivers/video/via/via_utility.h
drivers/video/via/viafbdev.c
drivers/video/via/viafbdev.h
drivers/video/via/viamode.c
drivers/video/via/viamode.h
drivers/video/w100fb.c
drivers/w1/masters/ds2482.c
drivers/w1/masters/mxc_w1.c
drivers/w1/masters/omap_hdq.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/acquirewdt.c
drivers/watchdog/advantechwdt.c
drivers/watchdog/adx_wdt.c
drivers/watchdog/alim1535_wdt.c
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/ar7_wdt.c
drivers/watchdog/at32ap700x_wdt.c
drivers/watchdog/at91rm9200_wdt.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/bfin_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/coh901327_wdt.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/davinci_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/eurotechwdt.c
drivers/watchdog/gef_wdt.c
drivers/watchdog/geodewdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/ib700wdt.c
drivers/watchdog/indydog.c
drivers/watchdog/it8712f_wdt.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/ixp2000_wdt.c
drivers/watchdog/ixp4xx_wdt.c
drivers/watchdog/ks8695_wdt.c
drivers/watchdog/machzwd.c
drivers/watchdog/max63xx_wdt.c [new file with mode: 0644]
drivers/watchdog/mixcomwd.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/mv64x60_wdt.c
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pcwd.c
drivers/watchdog/pcwd_pci.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/pika_wdt.c
drivers/watchdog/pnx833x_wdt.c
drivers/watchdog/rc32434_wdt.c
drivers/watchdog/rdc321x_wdt.c
drivers/watchdog/riowd.c
drivers/watchdog/sbc_fitpc2_wdt.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/stmp3xxx_wdt.c
drivers/watchdog/ts72xx_wdt.c [new file with mode: 0644]
drivers/watchdog/txx9wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/w83977f_wdt.c
drivers/watchdog/wdrtas.c
drivers/watchdog/wdt.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/wm8350_wdt.c
drivers/xen/sys-hypervisor.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/extent_map.c
fs/btrfs/free-space-cache.c
fs/btrfs/ordered-data.h
fs/btrfs/ref-cache.h
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/transaction.c
fs/buffer.c
fs/compat.c
fs/dlm/lockspace.c
fs/ext4/super.c
fs/fscache/Kconfig
fs/gfs2/sys.c
fs/ocfs2/cluster/masklog.c
fs/ocfs2/cluster/tcp.c
fs/select.c
fs/sysfs/bin.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
fs/ufs/super.c
fs/ufs/ufs_fs.h
include/asm-generic/pci-dma-compat.h
include/linux/acct.h
include/linux/cgroup.h
include/linux/compat.h
include/linux/coredump.h
include/linux/decompress/mm.h
include/linux/device.h
include/linux/dma-mapping.h
include/linux/init_task.h
include/linux/iocontext.h
include/linux/ipc_namespace.h
include/linux/ipmi_smi.h
include/linux/kmod.h
include/linux/kobject.h
include/linux/lockdep.h
include/linux/memcontrol.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/module.h
include/linux/nodemask.h
include/linux/page_cgroup.h
include/linux/pci-dma.h [new file with mode: 0644]
include/linux/pci.h
include/linux/platform_device.h
include/linux/poll.h
include/linux/ptrace.h
include/linux/rcupdate.h
include/linux/reboot.h
include/linux/rtc.h
include/linux/rtmutex.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/signal.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/sysdev.h
include/linux/sysfs.h
include/linux/taskstats_kern.h
include/linux/tty.h
include/linux/tty_ldisc.h
include/linux/usb.h
include/linux/usb/audio.h
include/net/net_namespace.h
include/scsi/sg.h
include/sound/asound.h
include/video/broadsheetfb.h
init/Kconfig
ipc/Makefile
ipc/mqueue.c
ipc/shm.c
ipc/syscall.c [new file with mode: 0644]
kernel/acct.c
kernel/cgroup.c
kernel/fork.c
kernel/module.c
kernel/nsproxy.c
kernel/params.c
kernel/perf_event.c
kernel/pid_namespace.c
kernel/sched.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
lib/kobject.c
lib/kobject_uevent.c
lib/zlib_inflate/inffast.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mmap.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c
mm/page_cgroup.c
mm/slub.c
mm/swapfile.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/sco.c
net/bridge/br_private.h
net/bridge/br_sysfs_if.c
samples/kobject/kobject-example.c
samples/kobject/kset-example.c
scripts/kernel-doc
sound/core/timer.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/jazz16.c
sound/oss/coproc.h
sound/oss/v_midi.h
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_hdmi.c [new file with mode: 0644]
sound/pci/hda/patch_intelhdmi.c
sound/pci/hda/patch_nvhdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/oxygen/xonar_wm87x6.c
sound/pci/riptide/riptide.c
sound/soc/codecs/ak4104.c
sound/soc/soc-core.c
sound/usb/Kconfig
sound/usb/caiaq/midi.h
sound/usb/ua101.c
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbquirks.h

index 5aceb88..05e2ae2 100644 (file)
@@ -4,20 +4,18 @@
         James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
 
 This document describes the DMA API.  For a more gentle introduction
-phrased in terms of the pci_ equivalents (and actual examples) see
-Documentation/PCI/PCI-DMA-mapping.txt.
+of the API (and actual examples) see
+Documentation/DMA-API-HOWTO.txt.
 
-This API is split into two pieces.  Part I describes the API and the
-corresponding pci_ API.  Part II describes the extensions to the API
-for supporting non-consistent memory machines.  Unless you know that
-your driver absolutely has to support non-consistent platforms (this
-is usually only legacy platforms) you should only use the API
-described in part I.
+This API is split into two pieces.  Part I describes the API.  Part II
+describes the extensions to the API for supporting non-consistent
+memory machines.  Unless you know that your driver absolutely has to
+support non-consistent platforms (this is usually only legacy
+platforms) you should only use the API described in part I.
 
-Part I - pci_ and dma_ Equivalent API 
+Part I - dma_ API
 -------------------------------------
 
-To get the pci_ API, you must #include <linux/pci.h>
 To get the dma_ API, you must #include <linux/dma-mapping.h>
 
 
@@ -27,9 +25,6 @@ Part Ia - Using large dma-coherent buffers
 void *
 dma_alloc_coherent(struct device *dev, size_t size,
                             dma_addr_t *dma_handle, gfp_t flag)
-void *
-pci_alloc_consistent(struct pci_dev *dev, size_t size,
-                            dma_addr_t *dma_handle)
 
 Consistent memory is memory for which a write by either the device or
 the processor can immediately be read by the processor or device
@@ -53,15 +48,11 @@ The simplest way to do that is to use the dma_pool calls (see below).
 The flag parameter (dma_alloc_coherent only) allows the caller to
 specify the GFP_ flags (see kmalloc) for the allocation (the
 implementation may choose to ignore flags that affect the location of
-the returned memory, like GFP_DMA).  For pci_alloc_consistent, you
-must assume GFP_ATOMIC behaviour.
+the returned memory, like GFP_DMA).
 
 void
 dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
                           dma_addr_t dma_handle)
-void
-pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr,
-                          dma_addr_t dma_handle)
 
 Free the region of consistent memory you previously allocated.  dev,
 size and dma_handle must all be the same as those passed into the
@@ -89,10 +80,6 @@ for alignment, like queue heads needing to be aligned on N-byte boundaries.
        dma_pool_create(const char *name, struct device *dev,
                        size_t size, size_t align, size_t alloc);
 
-       struct pci_pool *
-       pci_pool_create(const char *name, struct pci_device *dev,
-                       size_t size, size_t align, size_t alloc);
-
 The pool create() routines initialize a pool of dma-coherent buffers
 for use with a given device.  It must be called in a context which
 can sleep.
@@ -108,9 +95,6 @@ from this pool must not cross 4KByte boundaries.
        void *dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags,
                        dma_addr_t *dma_handle);
 
-       void *pci_pool_alloc(struct pci_pool *pool, gfp_t gfp_flags,
-                       dma_addr_t *dma_handle);
-
 This allocates memory from the pool; the returned memory will meet the size
 and alignment requirements specified at creation time.  Pass GFP_ATOMIC to
 prevent blocking, or if it's permitted (not in_interrupt, not holding SMP locks),
@@ -122,9 +106,6 @@ pool's device.
        void dma_pool_free(struct dma_pool *pool, void *vaddr,
                        dma_addr_t addr);
 
-       void pci_pool_free(struct pci_pool *pool, void *vaddr,
-                       dma_addr_t addr);
-
 This puts memory back into the pool.  The pool is what was passed to
 the pool allocation routine; the cpu (vaddr) and dma addresses are what
 were returned when that routine allocated the memory being freed.
@@ -132,8 +113,6 @@ were returned when that routine allocated the memory being freed.
 
        void dma_pool_destroy(struct dma_pool *pool);
 
-       void pci_pool_destroy(struct pci_pool *pool);
-
 The pool destroy() routines free the resources of the pool.  They must be
 called in a context which can sleep.  Make sure you've freed all allocated
 memory back to the pool before you destroy it.
@@ -144,8 +123,6 @@ Part Ic - DMA addressing limitations
 
 int
 dma_supported(struct device *dev, u64 mask)
-int
-pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 
 Checks to see if the device can support DMA to the memory described by
 mask.
@@ -159,8 +136,14 @@ driver writers.
 
 int
 dma_set_mask(struct device *dev, u64 mask)
+
+Checks to see if the mask is possible and updates the device
+parameters if it is.
+
+Returns: 0 if successful and a negative error if not.
+
 int
-pci_set_dma_mask(struct pci_device *dev, u64 mask)
+dma_set_coherent_mask(struct device *dev, u64 mask)
 
 Checks to see if the mask is possible and updates the device
 parameters if it is.
@@ -187,9 +170,6 @@ Part Id - Streaming DMA mappings
 dma_addr_t
 dma_map_single(struct device *dev, void *cpu_addr, size_t size,
                      enum dma_data_direction direction)
-dma_addr_t
-pci_map_single(struct pci_dev *hwdev, void *cpu_addr, size_t size,
-                     int direction)
 
 Maps a piece of processor virtual memory so it can be accessed by the
 device and returns the physical handle of the memory.
@@ -198,14 +178,10 @@ The direction for both api's may be converted freely by casting.
 However the dma_ API uses a strongly typed enumerator for its
 direction:
 
-DMA_NONE               = PCI_DMA_NONE          no direction (used for
-                                               debugging)
-DMA_TO_DEVICE          = PCI_DMA_TODEVICE      data is going from the
-                                               memory to the device
-DMA_FROM_DEVICE                = PCI_DMA_FROMDEVICE    data is coming from
-                                               the device to the
-                                               memory
-DMA_BIDIRECTIONAL      = PCI_DMA_BIDIRECTIONAL direction isn't known
+DMA_NONE               no direction (used for debugging)
+DMA_TO_DEVICE          data is going from the memory to the device
+DMA_FROM_DEVICE                data is coming from the device to the memory
+DMA_BIDIRECTIONAL      direction isn't known
 
 Notes:  Not all memory regions in a machine can be mapped by this
 API.  Further, regions that appear to be physically contiguous in
@@ -268,9 +244,6 @@ cache lines are updated with data that the device may have changed).
 void
 dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
                 enum dma_data_direction direction)
-void
-pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                size_t size, int direction)
 
 Unmaps the region previously mapped.  All the parameters passed in
 must be identical to those passed in (and returned) by the mapping
@@ -280,15 +253,9 @@ dma_addr_t
 dma_map_page(struct device *dev, struct page *page,
                    unsigned long offset, size_t size,
                    enum dma_data_direction direction)
-dma_addr_t
-pci_map_page(struct pci_dev *hwdev, struct page *page,
-                   unsigned long offset, size_t size, int direction)
 void
 dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
               enum dma_data_direction direction)
-void
-pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
-              size_t size, int direction)
 
 API for mapping and unmapping for pages.  All the notes and warnings
 for the other mapping APIs apply here.  Also, although the <offset>
@@ -299,9 +266,6 @@ cache width is.
 int
 dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 
-int
-pci_dma_mapping_error(struct pci_dev *hwdev, dma_addr_t dma_addr)
-
 In some circumstances dma_map_single and dma_map_page will fail to create
 a mapping. A driver can check for these errors by testing the returned
 dma address with dma_mapping_error(). A non-zero return value means the mapping
@@ -311,9 +275,6 @@ reduce current DMA mapping usage or delay and try again later).
        int
        dma_map_sg(struct device *dev, struct scatterlist *sg,
                int nents, enum dma_data_direction direction)
-       int
-       pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-               int nents, int direction)
 
 Returns: the number of physical segments mapped (this may be shorter
 than <nents> passed in if some elements of the scatter/gather list are
@@ -353,9 +314,6 @@ accessed sg->address and sg->length as shown above.
        void
        dma_unmap_sg(struct device *dev, struct scatterlist *sg,
                int nhwentries, enum dma_data_direction direction)
-       void
-       pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-               int nents, int direction)
 
 Unmap the previously mapped scatter/gather list.  All the parameters
 must be the same as those and passed in to the scatter/gather mapping
@@ -365,21 +323,23 @@ Note: <nents> must be the number you passed in, *not* the number of
 physical entries returned.
 
 void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+                       enum dma_data_direction direction)
 void
-pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
-                          size_t size, int direction)
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+                          enum dma_data_direction direction)
 void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
-                         enum dma_data_direction direction)
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+                   enum dma_data_direction direction)
 void
-pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                      int nelems, int direction)
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+                      enum dma_data_direction direction)
 
-Synchronise a single contiguous or scatter/gather mapping.  All the
-parameters must be the same as those passed into the single mapping
-API.
+Synchronise a single contiguous or scatter/gather mapping for the cpu
+and device. With the sync_sg API, all the parameters must be the same
+as those passed into the single mapping API. With the sync_single API,
+you can use dma_handle and size parameters that aren't identical to
+those passed into the single mapping API to do a partial sync.
 
 Notes:  You must do this:
 
@@ -461,9 +421,9 @@ void whizco_dma_map_sg_attrs(struct device *dev, dma_addr_t dma_addr,
 Part II - Advanced dma_ usage
 -----------------------------
 
-Warning: These pieces of the DMA API have no PCI equivalent.  They
-should also not be used in the majority of cases, since they cater for
-unlikely corner cases that don't belong in usual drivers.
+Warning: These pieces of the DMA API should not be used in the
+majority of cases, since they cater for unlikely corner cases that
+don't belong in usual drivers.
 
 If you don't understand how cache line coherency works between a
 processor and an I/O device, you should not be using this part of the
@@ -513,16 +473,6 @@ line, but it will guarantee that one or more cache lines fit exactly
 into the width returned by this call.  It will also always be a power
 of two for easy alignment.
 
-void
-dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-
-Does a partial sync, starting at offset and continuing for size.  You
-must be careful to observe the cache alignment and width when doing
-anything like this.  You must also be extra careful about accessing
-memory you intend to sync partially.
-
 void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
               enum dma_data_direction direction)
index 8495fc9..f5395af 100644 (file)
@@ -221,8 +221,8 @@ branches.  These different branches are:
   - main 2.6.x kernel tree
   - 2.6.x.y -stable kernel tree
   - 2.6.x -git kernel patches
-  - 2.6.x -mm kernel patches
   - subsystem specific kernel trees and patches
+  - the 2.6.x -next kernel tree for integration tests
 
 2.6.x kernel tree
 -----------------
@@ -232,7 +232,7 @@ process is as follows:
   - As soon as a new kernel is released a two weeks window is open,
     during this period of time maintainers can submit big diffs to
     Linus, usually the patches that have already been included in the
-    -mm kernel for a few weeks.  The preferred way to submit big changes
+    -next kernel for a few weeks.  The preferred way to submit big changes
     is using git (the kernel's source management tool, more information
     can be found at http://git.or.cz/) but plain patches are also just
     fine.
@@ -293,84 +293,43 @@ daily and represent the current state of Linus' tree.  They are more
 experimental than -rc kernels since they are generated automatically
 without even a cursory glance to see if they are sane.
 
-2.6.x -mm kernel patches
-------------------------
-These are experimental kernel patches released by Andrew Morton.  Andrew
-takes all of the different subsystem kernel trees and patches and mushes
-them together, along with a lot of patches that have been plucked from
-the linux-kernel mailing list.  This tree serves as a proving ground for
-new features and patches.  Once a patch has proved its worth in -mm for
-a while Andrew or the subsystem maintainer pushes it on to Linus for
-inclusion in mainline.
-
-It is heavily encouraged that all new patches get tested in the -mm tree
-before they are sent to Linus for inclusion in the main kernel tree.  Code
-which does not make an appearance in -mm before the opening of the merge
-window will prove hard to merge into the mainline.
-
-These kernels are not appropriate for use on systems that are supposed
-to be stable and they are more risky to run than any of the other
-branches.
-
-If you wish to help out with the kernel development process, please test
-and use these kernel releases and provide feedback to the linux-kernel
-mailing list if you have any problems, and if everything works properly.
-
-In addition to all the other experimental patches, these kernels usually
-also contain any changes in the mainline -git kernels available at the
-time of release.
-
-The -mm kernels are not released on a fixed schedule, but usually a few
--mm kernels are released in between each -rc kernel (1 to 3 is common).
-
 Subsystem Specific kernel trees and patches
 -------------------------------------------
-A number of the different kernel subsystem developers expose their
-development trees so that others can see what is happening in the
-different areas of the kernel.  These trees are pulled into the -mm
-kernel releases as described above.
-
-Here is a list of some of the different kernel trees available:
-  git trees:
-    - Kbuild development tree, Sam Ravnborg <sam@ravnborg.org>
-       git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
-
-    - ACPI development tree, Len Brown <len.brown@intel.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
-
-    - Block development tree, Jens Axboe <jens.axboe@oracle.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
-
-    - DRM development tree, Dave Airlie <airlied@linux.ie>
-       git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
-
-    - ia64 development tree, Tony Luck <tony.luck@intel.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
-
-    - infiniband, Roland Dreier <rolandd@cisco.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
-
-    - libata, Jeff Garzik <jgarzik@pobox.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
-
-    - network drivers, Jeff Garzik <jgarzik@pobox.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
-
-    - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
-       git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
-
-    - SCSI, James Bottomley <James.Bottomley@hansenpartnership.com>
-       git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
-
-    - x86, Ingo Molnar <mingo@elte.hu>
-       git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-
-  quilt trees:
-    - USB, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
-       kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+The maintainers of the various kernel subsystems --- and also many
+kernel subsystem developers --- expose their current state of
+development in source repositories.  That way, others can see what is
+happening in the different areas of the kernel.  In areas where
+development is rapid, a developer may be asked to base his submissions
+onto such a subsystem kernel tree so that conflicts between the
+submission and other already ongoing work are avoided.
+
+Most of these repositories are git trees, but there are also other SCMs
+in use, or patch queues being published as quilt series.  Addresses of
+these subsystem repositories are listed in the MAINTAINERS file.  Many
+of them can be browsed at http://git.kernel.org/.
+
+Before a proposed patch is committed to such a subsystem tree, it is
+subject to review which primarily happens on mailing lists (see the
+respective section below).  For several kernel subsystems, this review
+process is tracked with the tool patchwork.  Patchwork offers a web
+interface which shows patch postings, any comments on a patch or
+revisions to it, and maintainers can mark patches as under review,
+accepted, or rejected.  Most of these patchwork sites are listed at
+http://patchwork.kernel.org/ or http://patchwork.ozlabs.org/.
+
+2.6.x -next kernel tree for integration tests
+---------------------------------------------
+Before updates from subsystem trees are merged into the mainline 2.6.x
+tree, they need to be integration-tested.  For this purpose, a special
+testing repository exists into which virtually all subsystem trees are
+pulled on an almost daily basis:
+       http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+       http://linux.f-seidel.de/linux-next/pmwiki/
+
+This way, the -next kernel gives a summary outlook onto what will be
+expected to go into the mainline kernel at the next merge period.
+Adventurous testers are very welcome to runtime-test the -next kernel.
 
-  Other kernel trees can be found listed at http://git.kernel.org/ and in
-  the MAINTAINERS file.
 
 Bug Reporting
 -------------
index bc38283..69dd29e 100644 (file)
@@ -365,6 +365,7 @@ You can change this at module load time (for a module) with:
        regshifts=<shift1>,<shift2>,...
        slave_addrs=<addr1>,<addr2>,...
        force_kipmid=<enable1>,<enable2>,...
+       kipmid_max_busy_us=<ustime1>,<ustime2>,...
        unload_when_empty=[0|1]
 
 Each of these except si_trydefaults is a list, the first item for the
@@ -433,6 +434,7 @@ kernel command line as:
        ipmi_si.regshifts=<shift1>,<shift2>,...
        ipmi_si.slave_addrs=<addr1>,<addr2>,...
        ipmi_si.force_kipmid=<enable1>,<enable2>,...
+       ipmi_si.kipmid_max_busy_us=<ustime1>,<ustime2>,...
 
 It works the same as the module parameters of the same names.
 
@@ -450,6 +452,16 @@ force this thread on or off.  If you force it off and don't have
 interrupts, the driver will run VERY slowly.  Don't blame me,
 these interfaces suck.
 
+Unfortunately, this thread can use a lot of CPU depending on the
+interface's performance.  This can waste a lot of CPU and cause
+various issues with detecting idle CPU and using extra power.  To
+avoid this, the kipmid_max_busy_us sets the maximum amount of time, in
+microseconds, that kipmid will spin before sleeping for a tick.  This
+value sets a balance between performance and CPU waste and needs to be
+tuned to your needs.  Maybe, someday, auto-tuning will be added, but
+that's not a simple thing and even the auto-tuning would need to be
+tuned to the user's desired performance.
+
 The driver supports a hot add and remove of interfaces.  This way,
 interfaces can be added or removed after the kernel is up and running.
 This is done using /sys/modules/ipmi_si/parameters/hotmod, which is a
index 94b9457..6fc7ea1 100644 (file)
@@ -1,3 +1,3 @@
 obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
-       filesystems/configfs/ ia64/ networking/ \
-       pcmcia/ spi/ video4linux/ vm/ watchdog/src/
+       filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
+       pcmcia/ spi/ timers/ video4linux/ vm/ watchdog/src/
index ecad88d..52618ab 100644 (file)
@@ -1,12 +1,12 @@
-                       Dynamic DMA mapping
-                       ===================
+                    Dynamic DMA mapping Guide
+                    =========================
 
                 David S. Miller <davem@redhat.com>
                 Richard Henderson <rth@cygnus.com>
                  Jakub Jelinek <jakub@redhat.com>
 
-This document describes the DMA mapping system in terms of the pci_
-API.  For a similar API that works for generic devices, see
+This is a guide to device driver writers on how to use the DMA API
+with example pseudo-code.  For a concise description of the API, see
 DMA-API.txt.
 
 Most of the 64bit platforms have special hardware that translates bus
@@ -26,12 +26,15 @@ mapped only for the time they are actually used and unmapped after the DMA
 transfer.
 
 The following API will work of course even on platforms where no such
-hardware exists, see e.g. arch/x86/include/asm/pci.h for how it is implemented on
-top of the virt_to_bus interface.
+hardware exists.
+
+Note that the DMA API works with any bus independent of the underlying
+microprocessor architecture. You should use the DMA API rather than
+the bus specific DMA API (e.g. pci_dma_*).
 
 First of all, you should make sure
 
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 
 is in your driver. This file will obtain for you the definition of the
 dma_addr_t (which can hold any valid DMA address for the platform)
@@ -78,44 +81,43 @@ for you to DMA from/to.
                        DMA addressing limitations
 
 Does your device have any DMA addressing limitations?  For example, is
-your device only capable of driving the low order 24-bits of address
-on the PCI bus for SAC DMA transfers?  If so, you need to inform the
-PCI layer of this fact.
+your device only capable of driving the low order 24-bits of address?
+If so, you need to inform the kernel of this fact.
 
 By default, the kernel assumes that your device can address the full
-32-bits in a SAC cycle.  For a 64-bit DAC capable device, this needs
-to be increased.  And for a device with limitations, as discussed in
-the previous paragraph, it needs to be decreased.
-
-pci_alloc_consistent() by default will return 32-bit DMA addresses.
-PCI-X specification requires PCI-X devices to support 64-bit
-addressing (DAC) for all transactions. And at least one platform (SGI
-SN2) requires 64-bit consistent allocations to operate correctly when
-the IO bus is in PCI-X mode. Therefore, like with pci_set_dma_mask(),
-it's good practice to call pci_set_consistent_dma_mask() to set the
-appropriate mask even if your device only supports 32-bit DMA
-(default) and especially if it's a PCI-X device.
-
-For correct operation, you must interrogate the PCI layer in your
-device probe routine to see if the PCI controller on the machine can
-properly support the DMA addressing limitation your device has.  It is
-good style to do this even if your device holds the default setting,
+32-bits.  For a 64-bit capable device, this needs to be increased.
+And for a device with limitations, as discussed in the previous
+paragraph, it needs to be decreased.
+
+Special note about PCI: PCI-X specification requires PCI-X devices to
+support 64-bit addressing (DAC) for all transactions.  And at least
+one platform (SGI SN2) requires 64-bit consistent allocations to
+operate correctly when the IO bus is in PCI-X mode.
+
+For correct operation, you must interrogate the kernel in your device
+probe routine to see if the DMA controller on the machine can properly
+support the DMA addressing limitation your device has.  It is good
+style to do this even if your device holds the default setting,
 because this shows that you did think about these issues wrt. your
 device.
 
-The query is performed via a call to pci_set_dma_mask():
+The query is performed via a call to dma_set_mask():
 
-       int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask);
+       int dma_set_mask(struct device *dev, u64 mask);
 
 The query for consistent allocations is performed via a call to
-pci_set_consistent_dma_mask():
+dma_set_coherent_mask():
 
-       int pci_set_consistent_dma_mask(struct pci_dev *pdev, u64 device_mask);
+       int dma_set_coherent_mask(struct device *dev, u64 mask);
 
-Here, pdev is a pointer to the PCI device struct of your device, and
-device_mask is a bit mask describing which bits of a PCI address your
-device supports.  It returns zero if your card can perform DMA
-properly on the machine given the address mask you provided.
+Here, dev is a pointer to the device struct of your device, and mask
+is a bit mask describing which bits of an address your device
+supports.  It returns zero if your card can perform DMA properly on
+the machine given the address mask you provided.  In general, the
+device struct of your device is embedded in the bus specific device
+struct of your device.  For example, a pointer to the device struct of
+your PCI device is pdev->dev (pdev is a pointer to the PCI device
+struct of your device).
 
 If it returns non-zero, your device cannot perform DMA properly on
 this platform, and attempting to do so will result in undefined
@@ -133,31 +135,30 @@ of your driver reports that performance is bad or that the device is not
 even detected, you can ask them for the kernel messages to find out
 exactly why.
 
-The standard 32-bit addressing PCI device would do something like
-this:
+The standard 32-bit addressing device would do something like this:
 
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+       if (dma_set_mask(dev, DMA_BIT_MASK(32))) {
                printk(KERN_WARNING
                       "mydev: No suitable DMA available.\n");
                goto ignore_this_device;
        }
 
-Another common scenario is a 64-bit capable device.  The approach
-here is to try for 64-bit DAC addressing, but back down to a
-32-bit mask should that fail.  The PCI platform code may fail the
-64-bit mask not because the platform is not capable of 64-bit
-addressing.  Rather, it may fail in this case simply because
-32-bit SAC addressing is done more efficiently than DAC addressing.
-Sparc64 is one platform which behaves in this way.
+Another common scenario is a 64-bit capable device.  The approach here
+is to try for 64-bit addressing, but back down to a 32-bit mask that
+should not fail.  The kernel may fail the 64-bit mask not because the
+platform is not capable of 64-bit addressing.  Rather, it may fail in
+this case simply because 32-bit addressing is done more efficiently
+than 64-bit addressing.  For example, Sparc64 PCI SAC addressing is
+more efficient than DAC addressing.
 
 Here is how you would handle a 64-bit capable device which can drive
 all 64-bits when accessing streaming DMA:
 
        int using_dac;
 
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+       if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
                using_dac = 1;
-       } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+       } else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
                using_dac = 0;
        } else {
                printk(KERN_WARNING
@@ -170,36 +171,36 @@ the case would look like this:
 
        int using_dac, consistent_using_dac;
 
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+       if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
                using_dac = 1;
                consistent_using_dac = 1;
-               pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-       } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+               dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+       } else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
                using_dac = 0;
                consistent_using_dac = 0;
-               pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
        } else {
                printk(KERN_WARNING
                       "mydev: No suitable DMA available.\n");
                goto ignore_this_device;
        }
 
-pci_set_consistent_dma_mask() will always be able to set the same or a
-smaller mask as pci_set_dma_mask(). However for the rare case that a
+dma_set_coherent_mask() will always be able to set the same or a
+smaller mask as dma_set_mask(). However for the rare case that a
 device driver only uses consistent allocations, one would have to
-check the return value from pci_set_consistent_dma_mask().
+check the return value from dma_set_coherent_mask().
 
 Finally, if your device can only drive the low 24-bits of
-address during PCI bus mastering you might do something like:
+address you might do something like:
 
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(24))) {
+       if (dma_set_mask(dev, DMA_BIT_MASK(24))) {
                printk(KERN_WARNING
                       "mydev: 24-bit DMA addressing not available.\n");
                goto ignore_this_device;
        }
 
-When pci_set_dma_mask() is successful, and returns zero, the PCI layer
-saves away this mask you have provided.  The PCI layer will use this
+When dma_set_mask() is successful, and returns zero, the kernel saves
+away this mask you have provided.  The kernel will use this
 information later when you make DMA mappings.
 
 There is a case which we are aware of at this time, which is worth
@@ -208,7 +209,7 @@ functions (for example a sound card provides playback and record
 functions) and the various different functions have _different_
 DMA addressing limitations, you may wish to probe each mask and
 only provide the functionality which the machine can handle.  It
-is important that the last call to pci_set_dma_mask() be for the
+is important that the last call to dma_set_mask() be for the
 most specific mask.
 
 Here is pseudo-code showing how this might be done:
@@ -217,17 +218,17 @@ Here is pseudo-code showing how this might be done:
        #define RECORD_ADDRESS_BITS     DMA_BIT_MASK(24)
 
        struct my_sound_card *card;
-       struct pci_dev *pdev;
+       struct device *dev;
 
        ...
-       if (!pci_set_dma_mask(pdev, PLAYBACK_ADDRESS_BITS)) {
+       if (!dma_set_mask(dev, PLAYBACK_ADDRESS_BITS)) {
                card->playback_enabled = 1;
        } else {
                card->playback_enabled = 0;
                printk(KERN_WARNING "%s: Playback disabled due to DMA limitations.\n",
                       card->name);
        }
-       if (!pci_set_dma_mask(pdev, RECORD_ADDRESS_BITS)) {
+       if (!dma_set_mask(dev, RECORD_ADDRESS_BITS)) {
                card->record_enabled = 1;
        } else {
                card->record_enabled = 0;
@@ -252,8 +253,8 @@ There are two types of DMA mappings:
   Think of "consistent" as "synchronous" or "coherent".
 
   The current default is to return consistent memory in the low 32
-  bits of the PCI bus space.  However, for future compatibility you
-  should set the consistent mask even if this default is fine for your
+  bits of the bus space.  However, for future compatibility you should
+  set the consistent mask even if this default is fine for your
   driver.
 
   Good examples of what to use consistent mappings for are:
@@ -285,9 +286,9 @@ There are two types of DMA mappings:
             found in PCI bridges (such as by reading a register's value
             after writing it).
 
-- Streaming DMA mappings which are usually mapped for one DMA transfer,
-  unmapped right after it (unless you use pci_dma_sync_* below) and for which
-  hardware can optimize for sequential accesses.
+- Streaming DMA mappings which are usually mapped for one DMA
+  transfer, unmapped right after it (unless you use dma_sync_* below)
+  and for which hardware can optimize for sequential accesses.
 
   This of "streaming" as "asynchronous" or "outside the coherency
   domain".
@@ -302,8 +303,8 @@ There are two types of DMA mappings:
   optimizations the hardware allows.  To this end, when using
   such mappings you must be explicit about what you want to happen.
 
-Neither type of DMA mapping has alignment restrictions that come
-from PCI, although some devices may have such restrictions.
+Neither type of DMA mapping has alignment restrictions that come from
+the underlying bus, although some devices may have such restrictions.
 Also, systems with caches that aren't DMA-coherent will work better
 when the underlying buffers don't share cache lines with other data.
 
@@ -315,33 +316,27 @@ you should do:
 
        dma_addr_t dma_handle;
 
-       cpu_addr = pci_alloc_consistent(pdev, size, &dma_handle);
-
-where pdev is a struct pci_dev *. This may be called in interrupt context.
-You should use dma_alloc_coherent (see DMA-API.txt) for buses
-where devices don't have struct pci_dev (like ISA, EISA).
+       cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);
 
-This argument is needed because the DMA translations may be bus
-specific (and often is private to the bus which the device is attached
-to).
+where device is a struct device *. This may be called in interrupt
+context with the GFP_ATOMIC flag.
 
 Size is the length of the region you want to allocate, in bytes.
 
 This routine will allocate RAM for that region, so it acts similarly to
 __get_free_pages (but takes size instead of a page order).  If your
 driver needs regions sized smaller than a page, you may prefer using
-the pci_pool interface, described below.
-
-The consistent DMA mapping interfaces, for non-NULL pdev, will by
-default return a DMA address which is SAC (Single Address Cycle)
-addressable.  Even if the device indicates (via PCI dma mask) that it
-may address the upper 32-bits and thus perform DAC cycles, consistent
-allocation will only return > 32-bit PCI addresses for DMA if the
-consistent dma mask has been explicitly changed via
-pci_set_consistent_dma_mask().  This is true of the pci_pool interface
-as well.
-
-pci_alloc_consistent returns two values: the virtual address which you
+the dma_pool interface, described below.
+
+The consistent DMA mapping interfaces, for non-NULL dev, will by
+default return a DMA address which is 32-bit addressable.  Even if the
+device indicates (via DMA mask) that it may address the upper 32-bits,
+consistent allocation will only return > 32-bit addresses for DMA if
+the consistent DMA mask has been explicitly changed via
+dma_set_coherent_mask().  This is true of the dma_pool interface as
+well.
+
+dma_alloc_coherent returns two values: the virtual address which you
 can use to access it from the CPU and dma_handle which you pass to the
 card.
 
@@ -354,54 +349,54 @@ buffer you receive will not cross a 64K boundary.
 
 To unmap and free such a DMA region, you call:
 
-       pci_free_consistent(pdev, size, cpu_addr, dma_handle);
+       dma_free_coherent(dev, size, cpu_addr, dma_handle);
 
-where pdev, size are the same as in the above call and cpu_addr and
-dma_handle are the values pci_alloc_consistent returned to you.
+where dev, size are the same as in the above call and cpu_addr and
+dma_handle are the values dma_alloc_coherent returned to you.
 This function may not be called in interrupt context.
 
 If your driver needs lots of smaller memory regions, you can write
-custom code to subdivide pages returned by pci_alloc_consistent,
-or you can use the pci_pool API to do that.  A pci_pool is like
-a kmem_cache, but it uses pci_alloc_consistent not __get_free_pages.
+custom code to subdivide pages returned by dma_alloc_coherent,
+or you can use the dma_pool API to do that.  A dma_pool is like
+a kmem_cache, but it uses dma_alloc_coherent not __get_free_pages.
 Also, it understands common hardware constraints for alignment,
 like queue heads needing to be aligned on N byte boundaries.
 
-Create a pci_pool like this:
+Create a dma_pool like this:
 
-       struct pci_pool *pool;
+       struct dma_pool *pool;
 
-       pool = pci_pool_create(name, pdev, size, align, alloc);
+       pool = dma_pool_create(name, dev, size, align, alloc);
 
-The "name" is for diagnostics (like a kmem_cache name); pdev and size
+The "name" is for diagnostics (like a kmem_cache name); dev and size
 are as above.  The device's hardware alignment requirement for this
 type of data is "align" (which is expressed in bytes, and must be a
 power of two).  If your device has no boundary crossing restrictions,
 pass 0 for alloc; passing 4096 says memory allocated from this pool
 must not cross 4KByte boundaries (but at that time it may be better to
-go for pci_alloc_consistent directly instead).
+go for dma_alloc_coherent directly instead).
 
-Allocate memory from a pci pool like this:
+Allocate memory from a dma pool like this:
 
-       cpu_addr = pci_pool_alloc(pool, flags, &dma_handle);
+       cpu_addr = dma_pool_alloc(pool, flags, &dma_handle);
 
 flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor
-holding SMP locks), SLAB_ATOMIC otherwise.  Like pci_alloc_consistent,
+holding SMP locks), SLAB_ATOMIC otherwise.  Like dma_alloc_coherent,
 this returns two values, cpu_addr and dma_handle.
 
-Free memory that was allocated from a pci_pool like this:
+Free memory that was allocated from a dma_pool like this:
 
-       pci_pool_free(pool, cpu_addr, dma_handle);
+       dma_pool_free(pool, cpu_addr, dma_handle);
 
-where pool is what you passed to pci_pool_alloc, and cpu_addr and
-dma_handle are the values pci_pool_alloc returned. This function
+where pool is what you passed to dma_pool_alloc, and cpu_addr and
+dma_handle are the values dma_pool_alloc returned. This function
 may be called in interrupt context.
 
-Destroy a pci_pool by calling:
+Destroy a dma_pool by calling:
 
-       pci_pool_destroy(pool);
+       dma_pool_destroy(pool);
 
-Make sure you've called pci_pool_free for all memory allocated
+Make sure you've called dma_pool_free for all memory allocated
 from a pool before you destroy the pool. This function may not
 be called in interrupt context.
 
@@ -411,15 +406,15 @@ The interfaces described in subsequent portions of this document
 take a DMA direction argument, which is an integer and takes on
 one of the following values:
 
PCI_DMA_BIDIRECTIONAL
PCI_DMA_TODEVICE
PCI_DMA_FROMDEVICE
PCI_DMA_NONE
+ DMA_BIDIRECTIONAL
DMA_TO_DEVICE
DMA_FROM_DEVICE
+ DMA_NONE
 
 One should provide the exact DMA direction if you know it.
 
-PCI_DMA_TODEVICE means "from main memory to the PCI device"
-PCI_DMA_FROMDEVICE means "from the PCI device to main memory"
+DMA_TO_DEVICE means "from main memory to the device"
+DMA_FROM_DEVICE means "from the device to main memory"
 It is the direction in which the data moves during the DMA
 transfer.
 
@@ -427,12 +422,12 @@ You are _strongly_ encouraged to specify this as precisely
 as you possibly can.
 
 If you absolutely cannot know the direction of the DMA transfer,
-specify PCI_DMA_BIDIRECTIONAL.  It means that the DMA can go in
+specify DMA_BIDIRECTIONAL.  It means that the DMA can go in
 either direction.  The platform guarantees that you may legally
 specify this, and that it will work, but this may be at the
 cost of performance for example.
 
-The value PCI_DMA_NONE is to be used for debugging.  One can
+The value DMA_NONE is to be used for debugging.  One can
 hold this in a data structure before you come to know the
 precise direction, and this will help catch cases where your
 direction tracking logic has failed to set things up properly.
@@ -442,21 +437,21 @@ potential platform-specific optimizations of such) is for debugging.
 Some platforms actually have a write permission boolean which DMA
 mappings can be marked with, much like page protections in the user
 program address space.  Such platforms can and do report errors in the
-kernel logs when the PCI controller hardware detects violation of the
+kernel logs when the DMA controller hardware detects violation of the
 permission setting.
 
 Only streaming mappings specify a direction, consistent mappings
 implicitly have a direction attribute setting of
-PCI_DMA_BIDIRECTIONAL.
+DMA_BIDIRECTIONAL.
 
 The SCSI subsystem tells you the direction to use in the
 'sc_data_direction' member of the SCSI command your driver is
 working on.
 
 For Networking drivers, it's a rather simple affair.  For transmit
-packets, map/unmap them with the PCI_DMA_TODEVICE direction
+packets, map/unmap them with the DMA_TO_DEVICE direction
 specifier.  For receive packets, just the opposite, map/unmap them
-with the PCI_DMA_FROMDEVICE direction specifier.
+with the DMA_FROM_DEVICE direction specifier.
 
                  Using Streaming DMA mappings
 
@@ -467,43 +462,43 @@ scatterlist.
 
 To map a single region, you do:
 
-       struct pci_dev *pdev = mydev->pdev;
+       struct device *dev = &my_dev->dev;
        dma_addr_t dma_handle;
        void *addr = buffer->ptr;
        size_t size = buffer->len;
 
-       dma_handle = pci_map_single(pdev, addr, size, direction);
+       dma_handle = dma_map_single(dev, addr, size, direction);
 
 and to unmap it:
 
-       pci_unmap_single(pdev, dma_handle, size, direction);
+       dma_unmap_single(dev, dma_handle, size, direction);
 
-You should call pci_unmap_single when the DMA activity is finished, e.g.
+You should call dma_unmap_single when the DMA activity is finished, e.g.
 from the interrupt which told you that the DMA transfer is done.
 
 Using cpu pointers like this for single mappings has a disadvantage,
 you cannot reference HIGHMEM memory in this way.  Thus, there is a
-map/unmap interface pair akin to pci_{map,unmap}_single.  These
+map/unmap interface pair akin to dma_{map,unmap}_single.  These
 interfaces deal with page/offset pairs instead of cpu pointers.
 Specifically:
 
-       struct pci_dev *pdev = mydev->pdev;
+       struct device *dev = &my_dev->dev;
        dma_addr_t dma_handle;
        struct page *page = buffer->page;
        unsigned long offset = buffer->offset;
        size_t size = buffer->len;
 
-       dma_handle = pci_map_page(pdev, page, offset, size, direction);
+       dma_handle = dma_map_page(dev, page, offset, size, direction);
 
        ...
 
-       pci_unmap_page(pdev, dma_handle, size, direction);
+       dma_unmap_page(dev, dma_handle, size, direction);
 
 Here, "offset" means byte offset within the given page.
 
 With scatterlists, you map a region gathered from several regions by:
 
-       int i, count = pci_map_sg(pdev, sglist, nents, direction);
+       int i, count = dma_map_sg(dev, sglist, nents, direction);
        struct scatterlist *sg;
 
        for_each_sg(sglist, sg, count, i) {
@@ -527,16 +522,16 @@ accessed sg->address and sg->length as shown above.
 
 To unmap a scatterlist, just call:
 
-       pci_unmap_sg(pdev, sglist, nents, direction);
+       dma_unmap_sg(dev, sglist, nents, direction);
 
 Again, make sure DMA activity has already finished.
 
-PLEASE NOTE:  The 'nents' argument to the pci_unmap_sg call must be
-              the _same_ one you passed into the pci_map_sg call,
+PLEASE NOTE:  The 'nents' argument to the dma_unmap_sg call must be
+              the _same_ one you passed into the dma_map_sg call,
              it should _NOT_ be the 'count' value _returned_ from the
-              pci_map_sg call.
+              dma_map_sg call.
 
-Every pci_map_{single,sg} call should have its pci_unmap_{single,sg}
+Every dma_map_{single,sg} call should have its dma_unmap_{single,sg}
 counterpart, because the bus address space is a shared resource (although
 in some ports the mapping is per each BUS so less devices contend for the
 same bus address space) and you could render the machine unusable by eating
@@ -547,14 +542,14 @@ the data in between the DMA transfers, the buffer needs to be synced
 properly in order for the cpu and device to see the most uptodate and
 correct copy of the DMA buffer.
 
-So, firstly, just map it with pci_map_{single,sg}, and after each DMA
+So, firstly, just map it with dma_map_{single,sg}, and after each DMA
 transfer call either:
 
-       pci_dma_sync_single_for_cpu(pdev, dma_handle, size, direction);
+       dma_sync_single_for_cpu(dev, dma_handle, size, direction);
 
 or:
 
-       pci_dma_sync_sg_for_cpu(pdev, sglist, nents, direction);
+       dma_sync_sg_for_cpu(dev, sglist, nents, direction);
 
 as appropriate.
 
@@ -562,27 +557,27 @@ Then, if you wish to let the device get at the DMA area again,
 finish accessing the data with the cpu, and then before actually
 giving the buffer to the hardware call either:
 
-       pci_dma_sync_single_for_device(pdev, dma_handle, size, direction);
+       dma_sync_single_for_device(dev, dma_handle, size, direction);
 
 or:
 
-       pci_dma_sync_sg_for_device(dev, sglist, nents, direction);
+       dma_sync_sg_for_device(dev, sglist, nents, direction);
 
 as appropriate.
 
 After the last DMA transfer call one of the DMA unmap routines
-pci_unmap_{single,sg}. If you don't touch the data from the first pci_map_*
-call till pci_unmap_*, then you don't have to call the pci_dma_sync_*
+dma_unmap_{single,sg}. If you don't touch the data from the first dma_map_*
+call till dma_unmap_*, then you don't have to call the dma_sync_*
 routines at all.
 
 Here is pseudo code which shows a situation in which you would need
-to use the pci_dma_sync_*() interfaces.
+to use the dma_sync_*() interfaces.
 
        my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len)
        {
                dma_addr_t mapping;
 
-               mapping = pci_map_single(cp->pdev, buffer, len, PCI_DMA_FROMDEVICE);
+               mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE);
 
                cp->rx_buf = buffer;
                cp->rx_len = len;
@@ -606,25 +601,25 @@ to use the pci_dma_sync_*() interfaces.
                         * the DMA transfer with the CPU first
                         * so that we see updated contents.
                         */
-                       pci_dma_sync_single_for_cpu(cp->pdev, cp->rx_dma,
-                                                   cp->rx_len,
-                                                   PCI_DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(&cp->dev, cp->rx_dma,
+                                               cp->rx_len,
+                                               DMA_FROM_DEVICE);
 
                        /* Now it is safe to examine the buffer. */
                        hp = (struct my_card_header *) cp->rx_buf;
                        if (header_is_ok(hp)) {
-                               pci_unmap_single(cp->pdev, cp->rx_dma, cp->rx_len,
-                                                PCI_DMA_FROMDEVICE);
+                               dma_unmap_single(&cp->dev, cp->rx_dma, cp->rx_len,
+                                                DMA_FROM_DEVICE);
                                pass_to_upper_layers(cp->rx_buf);
                                make_and_setup_new_rx_buf(cp);
                        } else {
                                /* Just sync the buffer and give it back
                                 * to the card.
                                 */
-                               pci_dma_sync_single_for_device(cp->pdev,
-                                                              cp->rx_dma,
-                                                              cp->rx_len,
-                                                              PCI_DMA_FROMDEVICE);
+                               dma_sync_single_for_device(&cp->dev,
+                                                          cp->rx_dma,
+                                                          cp->rx_len,
+                                                          DMA_FROM_DEVICE);
                                give_rx_buf_to_card(cp);
                        }
                }
@@ -634,19 +629,19 @@ Drivers converted fully to this interface should not use virt_to_bus any
 longer, nor should they use bus_to_virt. Some drivers have to be changed a
 little bit, because there is no longer an equivalent to bus_to_virt in the
 dynamic DMA mapping scheme - you have to always store the DMA addresses
-returned by the pci_alloc_consistent, pci_pool_alloc, and pci_map_single
-calls (pci_map_sg stores them in the scatterlist itself if the platform
+returned by the dma_alloc_coherent, dma_pool_alloc, and dma_map_single
+calls (dma_map_sg stores them in the scatterlist itself if the platform
 supports dynamic DMA mapping in hardware) in your driver structures and/or
 in the card registers.
 
-All PCI drivers should be using these interfaces with no exceptions.
-It is planned to completely remove virt_to_bus() and bus_to_virt() as
+All drivers should be using these interfaces with no exceptions.  It
+is planned to completely remove virt_to_bus() and bus_to_virt() as
 they are entirely deprecated.  Some ports already do not provide these
 as it is impossible to correctly support them.
 
                Optimizing Unmap State Space Consumption
 
-On many platforms, pci_unmap_{single,page}() is simply a nop.
+On many platforms, dma_unmap_{single,page}() is simply a nop.
 Therefore, keeping track of the mapping address and length is a waste
 of space.  Instead of filling your drivers up with ifdefs and the like
 to "work around" this (which would defeat the whole purpose of a
@@ -655,7 +650,7 @@ portable API) the following facilities are provided.
 Actually, instead of describing the macros one by one, we'll
 transform some example code.
 
-1) Use DECLARE_PCI_UNMAP_{ADDR,LEN} in state saving structures.
+1) Use DEFINE_DMA_UNMAP_{ADDR,LEN} in state saving structures.
    Example, before:
 
        struct ring_state {
@@ -668,14 +663,11 @@ transform some example code.
 
        struct ring_state {
                struct sk_buff *skb;
-               DECLARE_PCI_UNMAP_ADDR(mapping)
-               DECLARE_PCI_UNMAP_LEN(len)
+               DEFINE_DMA_UNMAP_ADDR(mapping);
+               DEFINE_DMA_UNMAP_LEN(len);
        };
 
-   NOTE: DO NOT put a semicolon at the end of the DECLARE_*()
-         macro.
-
-2) Use pci_unmap_{addr,len}_set to set these values.
+2) Use dma_unmap_{addr,len}_set to set these values.
    Example, before:
 
        ringp->mapping = FOO;
@@ -683,21 +675,21 @@ transform some example code.
 
    after:
 
-       pci_unmap_addr_set(ringp, mapping, FOO);
-       pci_unmap_len_set(ringp, len, BAR);
+       dma_unmap_addr_set(ringp, mapping, FOO);
+       dma_unmap_len_set(ringp, len, BAR);
 
-3) Use pci_unmap_{addr,len} to access these values.
+3) Use dma_unmap_{addr,len} to access these values.
    Example, before:
 
-       pci_unmap_single(pdev, ringp->mapping, ringp->len,
-                        PCI_DMA_FROMDEVICE);
+       dma_unmap_single(dev, ringp->mapping, ringp->len,
+                        DMA_FROM_DEVICE);
 
    after:
 
-       pci_unmap_single(pdev,
-                        pci_unmap_addr(ringp, mapping),
-                        pci_unmap_len(ringp, len),
-                        PCI_DMA_FROMDEVICE);
+       dma_unmap_single(dev,
+                        dma_unmap_addr(ringp, mapping),
+                        dma_unmap_len(ringp, len),
+                        DMA_FROM_DEVICE);
 
 It really should be self-explanatory.  We treat the ADDR and LEN
 separately, because it is possible for an implementation to only
@@ -732,15 +724,15 @@ to "Closing".
 DMA address space is limited on some architectures and an allocation
 failure can be determined by:
 
-- checking if pci_alloc_consistent returns NULL or pci_map_sg returns 0
+- checking if dma_alloc_coherent returns NULL or dma_map_sg returns 0
 
-- checking the returned dma_addr_t of pci_map_single and pci_map_page
-  by using pci_dma_mapping_error():
+- checking the returned dma_addr_t of dma_map_single and dma_map_page
+  by using dma_mapping_error():
 
        dma_addr_t dma_handle;
 
-       dma_handle = pci_map_single(pdev, addr, size, direction);
-       if (pci_dma_mapping_error(pdev, dma_handle)) {
+       dma_handle = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dev, dma_handle)) {
                /*
                 * reduce current DMA mapping usage,
                 * delay and try again later or
index 1053a56..8916ca4 100644 (file)
@@ -9,10 +9,14 @@ Documentation/SubmittingPatches and elsewhere regarding submitting Linux
 kernel patches.
 
 
-1: Builds cleanly with applicable or modified CONFIG options =y, =m, and
+1: If you use a facility then #include the file that defines/declares
+   that facility.  Don't depend on other header files pulling in ones
+   that you use.
+
+2: Builds cleanly with applicable or modified CONFIG options =y, =m, and
    =n.  No gcc warnings/errors, no linker warnings/errors.
 
-2: Passes allnoconfig, allmodconfig
+2b: Passes allnoconfig, allmodconfig
 
 3: Builds on multiple CPU architectures by using local cross-compile tools
    or some other build farm.
diff --git a/Documentation/cgroups/cgroup_event_listener.c b/Documentation/cgroups/cgroup_event_listener.c
new file mode 100644 (file)
index 0000000..8c2bfc4
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * cgroup_event_listener.c - Simple listener of cgroup events
+ *
+ * Copyright (C) Kirill A. Shutemov <kirill@shutemov.name>
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/eventfd.h>
+
+#define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>\n"
+
+int main(int argc, char **argv)
+{
+       int efd = -1;
+       int cfd = -1;
+       int event_control = -1;
+       char event_control_path[PATH_MAX];
+       char line[LINE_MAX];
+       int ret;
+
+       if (argc != 3) {
+               fputs(USAGE_STR, stderr);
+               return 1;
+       }
+
+       cfd = open(argv[1], O_RDONLY);
+       if (cfd == -1) {
+               fprintf(stderr, "Cannot open %s: %s\n", argv[1],
+                               strerror(errno));
+               goto out;
+       }
+
+       ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control",
+                       dirname(argv[1]));
+       if (ret >= PATH_MAX) {
+               fputs("Path to cgroup.event_control is too long\n", stderr);
+               goto out;
+       }
+
+       event_control = open(event_control_path, O_WRONLY);
+       if (event_control == -1) {
+               fprintf(stderr, "Cannot open %s: %s\n", event_control_path,
+                               strerror(errno));
+               goto out;
+       }
+
+       efd = eventfd(0, 0);
+       if (efd == -1) {
+               perror("eventfd() failed");
+               goto out;
+       }
+
+       ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]);
+       if (ret >= LINE_MAX) {
+               fputs("Arguments string is too long\n", stderr);
+               goto out;
+       }
+
+       ret = write(event_control, line, strlen(line) + 1);
+       if (ret == -1) {
+               perror("Cannot write to cgroup.event_control");
+               goto out;
+       }
+
+       while (1) {
+               uint64_t result;
+
+               ret = read(efd, &result, sizeof(result));
+               if (ret == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       perror("Cannot read from eventfd");
+                       break;
+               }
+               assert(ret == sizeof(result));
+
+               ret = access(event_control_path, W_OK);
+               if ((ret == -1) && (errno == ENOENT)) {
+                               puts("The cgroup seems to have removed.");
+                               ret = 0;
+                               break;
+               }
+
+               if (ret == -1) {
+                       perror("cgroup.event_control "
+                                       "is not accessable any more");
+                       break;
+               }
+
+               printf("%s %s: crossed\n", argv[1], argv[2]);
+       }
+
+out:
+       if (efd >= 0)
+               close(efd);
+       if (event_control >= 0)
+               close(event_control);
+       if (cfd >= 0)
+               close(cfd);
+
+       return (ret != 0);
+}
index 0b33bfe..fd588ff 100644 (file)
@@ -22,6 +22,8 @@ CONTENTS:
 2. Usage Examples and Syntax
   2.1 Basic Usage
   2.2 Attaching processes
+  2.3 Mounting hierarchies by name
+  2.4 Notification API
 3. Kernel API
   3.1 Overview
   3.2 Synchronization
@@ -434,6 +436,25 @@ you give a subsystem a name.
 The name of the subsystem appears as part of the hierarchy description
 in /proc/mounts and /proc/<pid>/cgroups.
 
+2.4 Notification API
+--------------------
+
+There is mechanism which allows to get notifications about changing
+status of a cgroup.
+
+To register new notification handler you need:
+ - create a file descriptor for event notification using eventfd(2);
+ - open a control file to be monitored (e.g. memory.usage_in_bytes);
+ - write "<event_fd> <control_fd> <args>" to cgroup.event_control.
+   Interpretation of args is defined by control file implementation;
+
+eventfd will be woken up by control file implementation or when the
+cgroup is removed.
+
+To unregister notification handler just close eventfd.
+
+NOTE: Support of notifications should be implemented for the control
+file. See documentation for the subsystem.
 
 3. Kernel API
 =============
@@ -488,6 +509,11 @@ Each subsystem should:
 - add an entry in linux/cgroup_subsys.h
 - define a cgroup_subsys object called <name>_subsys
 
+If a subsystem can be compiled as a module, it should also have in its
+module initcall a call to cgroup_load_subsys(), and in its exitcall a
+call to cgroup_unload_subsys(). It should also set its_subsys.module =
+THIS_MODULE in its .c file.
+
 Each subsystem may export the following methods. The only mandatory
 methods are create/destroy. Any others that are null are presumed to
 be successful no-ops.
@@ -536,10 +562,21 @@ returns an error, this will abort the attach operation.  If a NULL
 task is passed, then a successful result indicates that *any*
 unspecified task can be moved into the cgroup. Note that this isn't
 called on a fork. If this method returns 0 (success) then this should
-remain valid while the caller holds cgroup_mutex. If threadgroup is
+remain valid while the caller holds cgroup_mutex and it is ensured that either
+attach() or cancel_attach() will be called in future. If threadgroup is
 true, then a successful result indicates that all threads in the given
 thread's threadgroup can be moved together.
 
+void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
+              struct task_struct *task, bool threadgroup)
+(cgroup_mutex held by caller)
+
+Called when a task attach operation has failed after can_attach() has succeeded.
+A subsystem whose can_attach() has some side-effects should provide this
+function, so that the subsytem can implement a rollback. If not, not necessary.
+This will be called only about subsystems whose can_attach() operation have
+succeeded.
+
 void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
            struct cgroup *old_cgrp, struct task_struct *task,
            bool threadgroup)
index 72db89e..f7f68b2 100644 (file)
@@ -1,6 +1,6 @@
 Memory Resource Controller(Memcg)  Implementation Memo.
-Last Updated: 2009/1/20
-Base Kernel Version: based on 2.6.29-rc2.
+Last Updated: 2010/2
+Base Kernel Version: based on 2.6.33-rc7-mm(candidate for 34).
 
 Because VM is getting complex (one of reasons is memcg...), memcg's behavior
 is complex. This is a document for memcg's internal behavior.
@@ -337,7 +337,7 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
        race and lock dependency with other cgroup subsystems.
 
        example)
-       # mount -t cgroup none /cgroup -t cpuset,memory,cpu,devices
+       # mount -t cgroup none /cgroup -o cpuset,memory,cpu,devices
 
        and do task move, mkdir, rmdir etc...under this.
 
@@ -348,7 +348,7 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
 
        For example, test like following is good.
        (Shell-A)
-       # mount -t cgroup none /cgroup -t memory
+       # mount -t cgroup none /cgroup -o memory
        # mkdir /cgroup/test
        # echo 40M > /cgroup/test/memory.limit_in_bytes
        # echo 0 > /cgroup/test/tasks
@@ -378,3 +378,42 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
        #echo 50M > memory.limit_in_bytes
        #echo 50M > memory.memsw.limit_in_bytes
        run 51M of malloc
+
+ 9.9 Move charges at task migration
+       Charges associated with a task can be moved along with task migration.
+
+       (Shell-A)
+       #mkdir /cgroup/A
+       #echo $$ >/cgroup/A/tasks
+       run some programs which uses some amount of memory in /cgroup/A.
+
+       (Shell-B)
+       #mkdir /cgroup/B
+       #echo 1 >/cgroup/B/memory.move_charge_at_immigrate
+       #echo "pid of the program running in group A" >/cgroup/B/tasks
+
+       You can see charges have been moved by reading *.usage_in_bytes or
+       memory.stat of both A and B.
+       See 8.2 of Documentation/cgroups/memory.txt to see what value should be
+       written to move_charge_at_immigrate.
+
+ 9.10 Memory thresholds
+       Memory controler implements memory thresholds using cgroups notification
+       API. You can use Documentation/cgroups/cgroup_event_listener.c to test
+       it.
+
+       (Shell-A) Create cgroup and run event listener
+       # mkdir /cgroup/A
+       # ./cgroup_event_listener /cgroup/A/memory.usage_in_bytes 5M
+
+       (Shell-B) Add task to cgroup and try to allocate and free memory
+       # echo $$ >/cgroup/A/tasks
+       # a="$(dd if=/dev/zero bs=1M count=10)"
+       # a=
+
+       You will see message from cgroup_event_listener every time you cross
+       the thresholds.
+
+       Use /cgroup/A/memory.memsw.usage_in_bytes to test memsw thresholds.
+
+       It's good idea to test root cgroup as well.
index b871f25..f8bc802 100644 (file)
@@ -182,6 +182,8 @@ list.
 NOTE: Reclaim does not work for the root cgroup, since we cannot set any
 limits on the root cgroup.
 
+Note2: When panic_on_oom is set to "2", the whole system will panic.
+
 2. Locking
 
 The memory controller uses the following hierarchy
@@ -262,10 +264,12 @@ some of the pages cached in the cgroup (page cache pages).
 4.2 Task migration
 
 When a task migrates from one cgroup to another, it's charge is not
-carried forward. The pages allocated from the original cgroup still
+carried forward by default. The pages allocated from the original cgroup still
 remain charged to it, the charge is dropped when the page is freed or
 reclaimed.
 
+Note: You can move charges of a task along with task migration. See 8.
+
 4.3 Removing a cgroup
 
 A cgroup can be removed by rmdir, but as discussed in sections 4.1 and 4.2, a
@@ -377,7 +381,8 @@ The feature can be disabled by
 NOTE1: Enabling/disabling will fail if the cgroup already has other
 cgroups created below it.
 
-NOTE2: This feature can be enabled/disabled per subtree.
+NOTE2: When panic_on_oom is set to "2", the whole system will panic in
+case of an oom event in any cgroup.
 
 7. Soft limits
 
@@ -414,7 +419,76 @@ NOTE1: Soft limits take effect over a long period of time, since they involve
 NOTE2: It is recommended to set the soft limit always below the hard limit,
        otherwise the hard limit will take precedence.
 
-8. TODO
+8. Move charges at task migration
+
+Users can move charges associated with a task along with task migration, that
+is, uncharge task's pages from the old cgroup and charge them to the new cgroup.
+This feature is not supported in !CONFIG_MMU environments because of lack of
+page tables.
+
+8.1 Interface
+
+This feature is disabled by default. It can be enabled(and disabled again) by
+writing to memory.move_charge_at_immigrate of the destination cgroup.
+
+If you want to enable it:
+
+# echo (some positive value) > memory.move_charge_at_immigrate
+
+Note: Each bits of move_charge_at_immigrate has its own meaning about what type
+      of charges should be moved. See 8.2 for details.
+Note: Charges are moved only when you move mm->owner, IOW, a leader of a thread
+      group.
+Note: If we cannot find enough space for the task in the destination cgroup, we
+      try to make space by reclaiming memory. Task migration may fail if we
+      cannot make enough space.
+Note: It can take several seconds if you move charges in giga bytes order.
+
+And if you want disable it again:
+
+# echo 0 > memory.move_charge_at_immigrate
+
+8.2 Type of charges which can be move
+
+Each bits of move_charge_at_immigrate has its own meaning about what type of
+charges should be moved.
+
+  bit | what type of charges would be moved ?
+ -----+------------------------------------------------------------------------
+   0  | A charge of an anonymous page(or swap of it) used by the target task.
+      | Those pages and swaps must be used only by the target task. You must
+      | enable Swap Extension(see 2.4) to enable move of swap charges.
+
+Note: Those pages and swaps must be charged to the old cgroup.
+Note: More type of pages(e.g. file cache, shmem,) will be supported by other
+      bits in future.
+
+8.3 TODO
+
+- Add support for other types of pages(e.g. file cache, shmem, etc.).
+- Implement madvise(2) to let users decide the vma to be moved or not to be
+  moved.
+- All of moving charge operations are done under cgroup_mutex. It's not good
+  behavior to hold the mutex too long, so we may need some trick.
+
+9. Memory thresholds
+
+Memory controler implements memory thresholds using cgroups notification
+API (see cgroups.txt). It allows to register multiple memory and memsw
+thresholds and gets notifications when it crosses.
+
+To register a threshold application need:
+ - create an eventfd using eventfd(2);
+ - open memory.usage_in_bytes or memory.memsw.usage_in_bytes;
+ - write string like "<event_fd> <memory.usage_in_bytes> <threshold>" to
+   cgroup.event_control.
+
+Application will be notified through eventfd when memory usage crosses
+threshold in any direction.
+
+It's applicable for root and non-root cgroup.
+
+10. TODO
 
 1. Add support for accounting huge pages (as a separate controller)
 2. Make per-cgroup scanner reclaim not-shared pages first
index a618efa..945ff3f 100644 (file)
@@ -216,26 +216,14 @@ Works.  Use "Insert file..." or external editor.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Gmail (Web GUI)
 
-If you just have to use Gmail to send patches, it CAN be made to work.  It
-requires a bit of external help, though.
-
-The first problem is that Gmail converts tabs to spaces.  This will
-totally break your patches.  To prevent this, you have to use a different
-editor.  There is a firefox extension called "ViewSourceWith"
-(https://addons.mozilla.org/en-US/firefox/addon/394) which allows you to
-edit any text box in the editor of your choice.  Configure it to launch
-your favorite editor.  When you want to send a patch, use this technique.
-Once you have crafted your messsage + patch, save and exit the editor,
-which should reload the Gmail edit box.  GMAIL WILL PRESERVE THE TABS.
-Hoorah.  Apparently you can cut-n-paste literal tabs, but Gmail will
-convert those to spaces upon sending!
-
-The second problem is that Gmail converts tabs to spaces on replies.  If
-you reply to a patch, don't expect to be able to apply it as a patch.
-
-The last problem is that Gmail will base64-encode any message that has a
-non-ASCII character.  That includes things like European names.  Be aware.
-
-Gmail is not convenient for lkml patches, but CAN be made to work.
+Does not work for sending patches.
+
+Gmail web client converts tabs to spaces automatically.
+
+At the same time it wraps lines every 78 chars with CRLF style line breaks
+although tab2space problem can be solved with external editor.
+
+Another problem is that Gmail will base64-encode any message that has a
+non-ASCII character. That includes things like European names.
 
                                 ###
index 5139b8c..3bae418 100644 (file)
@@ -32,6 +32,8 @@ dlmfs.txt
        - info on the userspace interface to the OCFS2 DLM.
 dnotify.txt
        - info about directory notification in Linux.
+dnotify_test.c
+       - example program for dnotify
 ecryptfs.txt
        - docs on eCryptfs: stacked cryptographic filesystem for Linux.
 exofs.txt
diff --git a/Documentation/filesystems/Makefile b/Documentation/filesystems/Makefile
new file mode 100644 (file)
index 0000000..a5dd114
--- /dev/null
@@ -0,0 +1,8 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := dnotify_test
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
index 9f5d338..6baf88f 100644 (file)
@@ -62,38 +62,9 @@ disabled, fcntl(fd, F_NOTIFY, ...) will return -EINVAL.
 
 Example
 -------
+See Documentation/filesystems/dnotify_test.c for an example.
 
-       #define _GNU_SOURCE     /* needed to get the defines */
-       #include <fcntl.h>      /* in glibc 2.2 this has the needed
-                                          values defined */
-       #include <signal.h>
-       #include <stdio.h>
-       #include <unistd.h>
-
-       static volatile int event_fd;
-
-       static void handler(int sig, siginfo_t *si, void *data)
-       {
-               event_fd = si->si_fd;
-       }
-
-       int main(void)
-       {
-               struct sigaction act;
-               int fd;
-
-               act.sa_sigaction = handler;
-               sigemptyset(&act.sa_mask);
-               act.sa_flags = SA_SIGINFO;
-               sigaction(SIGRTMIN + 1, &act, NULL);
-
-               fd = open(".", O_RDONLY);
-               fcntl(fd, F_SETSIG, SIGRTMIN + 1);
-               fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
-               /* we will now be notified if any of the files
-                  in "." is modified or new files are created */
-               while (1) {
-                       pause();
-                       printf("Got event on fd=%d\n", event_fd);
-               }
-       }
+NOTE
+----
+Beginning with Linux 2.6.13, dnotify has been replaced by inotify.
+See Documentation/filesystems/inotify.txt for more information on it.
diff --git a/Documentation/filesystems/dnotify_test.c b/Documentation/filesystems/dnotify_test.c
new file mode 100644 (file)
index 0000000..8b37b4a
--- /dev/null
@@ -0,0 +1,34 @@
+#define _GNU_SOURCE    /* needed to get the defines */
+#include <fcntl.h>     /* in glibc 2.2 this has the needed
+                                  values defined */
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static volatile int event_fd;
+
+static void handler(int sig, siginfo_t *si, void *data)
+{
+       event_fd = si->si_fd;
+}
+
+int main(void)
+{
+       struct sigaction act;
+       int fd;
+
+       act.sa_sigaction = handler;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = SA_SIGINFO;
+       sigaction(SIGRTMIN + 1, &act, NULL);
+
+       fd = open(".", O_RDONLY);
+       fcntl(fd, F_SETSIG, SIGRTMIN + 1);
+       fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
+       /* we will now be notified if any of the files
+          in "." is modified or new files are created */
+       while (1) {
+               pause();
+               printf("Got event on fd=%d\n", event_fd);
+       }
+}
index c79ab99..bdb1381 100644 (file)
@@ -266,7 +266,7 @@ kobj_type:
 
     struct kobj_type {
            void (*release)(struct kobject *);
-           struct sysfs_ops    *sysfs_ops;
+           const struct sysfs_ops *sysfs_ops;
            struct attribute    **default_attrs;
     };
 
index ee5692b..f1fc13d 100644 (file)
@@ -2,6 +2,8 @@
        - This file
 acer-wmi.txt
        - information on the Acer Laptop WMI Extras driver.
+dslm.c
+       - Simple Disk Sleep Monitor program
 laptop-mode.txt
        - how to conserve battery power using laptop-mode.
 sony-laptop.txt
diff --git a/Documentation/laptops/Makefile b/Documentation/laptops/Makefile
new file mode 100644 (file)
index 0000000..5cb144a
--- /dev/null
@@ -0,0 +1,8 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := dslm
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
diff --git a/Documentation/laptops/dslm.c b/Documentation/laptops/dslm.c
new file mode 100644 (file)
index 0000000..72ff290
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * dslm.c
+ * Simple Disk Sleep Monitor
+ *  by Bartek Kania
+ * Licenced under the GPL
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+
+#ifdef DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+int endit = 0;
+
+/* Check if the disk is in powersave-mode
+ * Most of the code is stolen from hdparm.
+ * 1 = active, 0 = standby/sleep, -1 = unknown */
+static int check_powermode(int fd)
+{
+    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
+    int state;
+
+    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
+       && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
+       && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
+       if (errno != EIO || args[0] != 0 || args[1] != 0) {
+           state = -1; /* "unknown"; */
+       } else
+           state = 0; /* "sleeping"; */
+    } else {
+       state = (args[2] == 255) ? 1 : 0;
+    }
+    D(printf(" drive state is:  %d\n", state));
+
+    return state;
+}
+
+static char *state_name(int i)
+{
+    if (i == -1) return "unknown";
+    if (i == 0) return "sleeping";
+    if (i == 1) return "active";
+
+    return "internal error";
+}
+
+static char *myctime(time_t time)
+{
+    char *ts = ctime(&time);
+    ts[strlen(ts) - 1] = 0;
+
+    return ts;
+}
+
+static void measure(int fd)
+{
+    time_t start_time;
+    int last_state;
+    time_t last_time;
+    int curr_state;
+    time_t curr_time = 0;
+    time_t time_diff;
+    time_t active_time = 0;
+    time_t sleep_time = 0;
+    time_t unknown_time = 0;
+    time_t total_time = 0;
+    int changes = 0;
+    float tmp;
+
+    printf("Starting measurements\n");
+
+    last_state = check_powermode(fd);
+    start_time = last_time = time(0);
+    printf("  System is in state %s\n\n", state_name(last_state));
+
+    while(!endit) {
+       sleep(1);
+       curr_state = check_powermode(fd);
+
+       if (curr_state != last_state || endit) {
+           changes++;
+           curr_time = time(0);
+           time_diff = curr_time - last_time;
+
+           if (last_state == 1) active_time += time_diff;
+           else if (last_state == 0) sleep_time += time_diff;
+           else unknown_time += time_diff;
+
+           last_state = curr_state;
+           last_time = curr_time;
+
+           printf("%s: State-change to %s\n", myctime(curr_time),
+                  state_name(curr_state));
+       }
+    }
+    changes--; /* Compensate for SIGINT */
+
+    total_time = time(0) - start_time;
+    printf("\nTotal running time:  %lus\n", curr_time - start_time);
+    printf(" State changed %d times\n", changes);
+
+    tmp = (float)sleep_time / (float)total_time * 100;
+    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
+    tmp = (float)active_time / (float)total_time * 100;
+    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
+    tmp = (float)unknown_time / (float)total_time * 100;
+    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
+}
+
+static void ender(int s)
+{
+    endit = 1;
+}
+
+static void usage(void)
+{
+    puts("usage: dslm [-w <time>] <disk>");
+    exit(0);
+}
+
+int main(int argc, char **argv)
+{
+    int fd;
+    char *disk = 0;
+    int settle_time = 60;
+
+    /* Parse the simple command-line */
+    if (argc == 2)
+       disk = argv[1];
+    else if (argc == 4) {
+       settle_time = atoi(argv[2]);
+       disk = argv[3];
+    } else
+       usage();
+
+    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
+       printf("Can't open %s, because: %s\n", disk, strerror(errno));
+       exit(-1);
+    }
+
+    if (settle_time) {
+       printf("Waiting %d seconds for the system to settle down to "
+              "'normal'\n", settle_time);
+       sleep(settle_time);
+    } else
+       puts("Not waiting for system to settle down");
+
+    signal(SIGINT, ender);
+
+    measure(fd);
+
+    close(fd);
+
+    return 0;
+}
index eeedee1..2c3c350 100644 (file)
@@ -779,172 +779,4 @@ Monitoring tool
 ---------------
 
 Bartek Kania submitted this, it can be used to measure how much time your disk
-spends spun up/down.
-
----------------------------dslm.c BEGIN-----------------------------------------
-/*
- * Simple Disk Sleep Monitor
- *  by Bartek Kania
- * Licenced under the GPL
- */
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <time.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <linux/hdreg.h>
-
-#ifdef DEBUG
-#define D(x) x
-#else
-#define D(x)
-#endif
-
-int endit = 0;
-
-/* Check if the disk is in powersave-mode
- * Most of the code is stolen from hdparm.
- * 1 = active, 0 = standby/sleep, -1 = unknown */
-int check_powermode(int fd)
-{
-    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
-    int state;
-
-    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
-       && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
-       && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
-       if (errno != EIO || args[0] != 0 || args[1] != 0) {
-           state = -1; /* "unknown"; */
-       } else
-           state = 0; /* "sleeping"; */
-    } else {
-       state = (args[2] == 255) ? 1 : 0;
-    }
-    D(printf(" drive state is:  %d\n", state));
-
-    return state;
-}
-
-char *state_name(int i)
-{
-    if (i == -1) return "unknown";
-    if (i == 0) return "sleeping";
-    if (i == 1) return "active";
-
-    return "internal error";
-}
-
-char *myctime(time_t time)
-{
-    char *ts = ctime(&time);
-    ts[strlen(ts) - 1] = 0;
-
-    return ts;
-}
-
-void measure(int fd)
-{
-    time_t start_time;
-    int last_state;
-    time_t last_time;
-    int curr_state;
-    time_t curr_time = 0;
-    time_t time_diff;
-    time_t active_time = 0;
-    time_t sleep_time = 0;
-    time_t unknown_time = 0;
-    time_t total_time = 0;
-    int changes = 0;
-    float tmp;
-
-    printf("Starting measurements\n");
-
-    last_state = check_powermode(fd);
-    start_time = last_time = time(0);
-    printf("  System is in state %s\n\n", state_name(last_state));
-
-    while(!endit) {
-       sleep(1);
-       curr_state = check_powermode(fd);
-
-       if (curr_state != last_state || endit) {
-           changes++;
-           curr_time = time(0);
-           time_diff = curr_time - last_time;
-
-           if (last_state == 1) active_time += time_diff;
-           else if (last_state == 0) sleep_time += time_diff;
-           else unknown_time += time_diff;
-
-           last_state = curr_state;
-           last_time = curr_time;
-
-           printf("%s: State-change to %s\n", myctime(curr_time),
-                  state_name(curr_state));
-       }
-    }
-    changes--; /* Compensate for SIGINT */
-
-    total_time = time(0) - start_time;
-    printf("\nTotal running time:  %lus\n", curr_time - start_time);
-    printf(" State changed %d times\n", changes);
-
-    tmp = (float)sleep_time / (float)total_time * 100;
-    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
-    tmp = (float)active_time / (float)total_time * 100;
-    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
-    tmp = (float)unknown_time / (float)total_time * 100;
-    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
-}
-
-void ender(int s)
-{
-    endit = 1;
-}
-
-void usage()
-{
-    puts("usage: dslm [-w <time>] <disk>");
-    exit(0);
-}
-
-int main(int argc, char **argv)
-{
-    int fd;
-    char *disk = 0;
-    int settle_time = 60;
-
-    /* Parse the simple command-line */
-    if (argc == 2)
-       disk = argv[1];
-    else if (argc == 4) {
-       settle_time = atoi(argv[2]);
-       disk = argv[3];
-    } else
-       usage();
-
-    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
-       printf("Can't open %s, because: %s\n", disk, strerror(errno));
-       exit(-1);
-    }
-
-    if (settle_time) {
-       printf("Waiting %d seconds for the system to settle down to "
-              "'normal'\n", settle_time);
-       sleep(settle_time);
-    } else
-       puts("Not waiting for system to settle down");
-
-    signal(SIGINT, ender);
-
-    measure(fd);
-
-    close(fd);
-
-    return 0;
-}
----------------------------dslm.c END-------------------------------------------
+spends spun up/down.  See Documentation/laptops/dslm.c
index 5e5349a..7c90050 100644 (file)
@@ -105,6 +105,10 @@ write_wakeup()     -       May be called at any point between open and close.
                        is permitted to call the driver write method from
                        this function. In such a situation defer it.
 
+dcd_change()   -       Report to the tty line the current DCD pin status
+                       changes and the relative timestamp. The timestamp
+                       can be NULL.
+
 
 Driver Access
 
index 33df82e..bfcbbf8 100644 (file)
@@ -1812,7 +1812,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-ua101
   ----------------
 
-    Module for the Edirol UA-101 audio/MIDI interface.
+    Module for the Edirol UA-101/UA-1000 audio/MIDI interfaces.
 
     This module supports multiple devices, autoprobe and hotplugging.
 
index fc5790d..6c7d18c 100644 (file)
@@ -573,11 +573,14 @@ Because other nodes' memory may be free. This means system total status
 may be not fatal yet.
 
 If this is set to 2, the kernel panics compulsorily even on the
-above-mentioned.
+above-mentioned. Even oom happens under memory cgroup, the whole
+system panics.
 
 The default value is 0.
 1 and 2 are for failover of clustering. Please select either
 according to your policy of failover.
+panic_on_oom=2+kdump gives you very strong tool to investigate
+why oom happens. You can get snapshot.
 
 =============================================================
 
index 397dc35..a9248da 100644 (file)
@@ -4,6 +4,8 @@ highres.txt
        - High resolution timers and dynamic ticks design notes
 hpet.txt
        - High Precision Event Timer Driver for Linux
+hpet_example.c
+       - sample hpet timer test program
 hrtimers.txt
        - subsystem for high-resolution kernel timers
 timer_stats.txt
diff --git a/Documentation/timers/Makefile b/Documentation/timers/Makefile
new file mode 100644 (file)
index 0000000..c85625f
--- /dev/null
@@ -0,0 +1,8 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := hpet_example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
index 16d25e6..767392f 100644 (file)
@@ -26,274 +26,5 @@ initialization.  An example of this initialization can be found in
 arch/x86/kernel/hpet.c.
 
 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>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <memory.h>
-#include <malloc.h>
-#include <time.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <linux/hpet.h>
-
-
-extern void hpet_open_close(int, const char **);
-extern void hpet_info(int, const char **);
-extern void hpet_poll(int, const char **);
-extern void hpet_fasync(int, const char **);
-extern void hpet_read(int, const char **);
-
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <signal.h>
-
-struct hpet_command {
-       char            *command;
-       void            (*func)(int argc, const char ** argv);
-} hpet_command[] = {
-       {
-               "open-close",
-               hpet_open_close
-       },
-       {
-               "info",
-               hpet_info
-       },
-       {
-               "poll",
-               hpet_poll
-       },
-       {
-               "fasync",
-               hpet_fasync
-       },
-};
-
-int
-main(int argc, const char ** argv)
-{
-       int     i;
-
-       argc--;
-       argv++;
-
-       if (!argc) {
-               fprintf(stderr, "-hpet: requires command\n");
-               return -1;
-       }
-
-
-       for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
-               if (!strcmp(argv[0], hpet_command[i].command)) {
-                       argc--;
-                       argv++;
-                       fprintf(stderr, "-hpet: executing %s\n",
-                               hpet_command[i].command);
-                       hpet_command[i].func(argc, argv);
-                       return 0;
-               }
-
-       fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
-
-       return -1;
-}
-
-void
-hpet_open_close(int argc, const char **argv)
-{
-       int     fd;
-
-       if (argc != 1) {
-               fprintf(stderr, "hpet_open_close: device-name\n");
-               return;
-       }
-
-       fd = open(argv[0], O_RDONLY);
-       if (fd < 0)
-               fprintf(stderr, "hpet_open_close: open failed\n");
-       else
-               close(fd);
-
-       return;
-}
-
-void
-hpet_info(int argc, const char **argv)
-{
-}
-
-void
-hpet_poll(int argc, const char **argv)
-{
-       unsigned long           freq;
-       int                     iterations, i, fd;
-       struct pollfd           pfd;
-       struct hpet_info        info;
-       struct timeval          stv, etv;
-       struct timezone         tz;
-       long                    usec;
-
-       if (argc != 3) {
-               fprintf(stderr, "hpet_poll: device-name freq iterations\n");
-               return;
-       }
-
-       freq = atoi(argv[1]);
-       iterations = atoi(argv[2]);
-
-       fd = open(argv[0], O_RDONLY);
-
-       if (fd < 0) {
-               fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
-               return;
-       }
-
-       if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
-               fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
-               goto out;
-       }
-
-       if (ioctl(fd, HPET_INFO, &info) < 0) {
-               fprintf(stderr, "hpet_poll: failed to get info\n");
-               goto out;
-       }
-
-       fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
-
-       if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
-               fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
-               goto out;
-       }
-
-       if (ioctl(fd, HPET_IE_ON, 0) < 0) {
-               fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
-               goto out;
-       }
-
-       pfd.fd = fd;
-       pfd.events = POLLIN;
-
-       for (i = 0; i < iterations; i++) {
-               pfd.revents = 0;
-               gettimeofday(&stv, &tz);
-               if (poll(&pfd, 1, -1) < 0)
-                       fprintf(stderr, "hpet_poll: poll failed\n");
-               else {
-                       long    data;
-
-                       gettimeofday(&etv, &tz);
-                       usec = stv.tv_sec * 1000000 + stv.tv_usec;
-                       usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
-
-                       fprintf(stderr,
-                               "hpet_poll: expired time = 0x%lx\n", usec);
-
-                       fprintf(stderr, "hpet_poll: revents = 0x%x\n",
-                               pfd.revents);
-
-                       if (read(fd, &data, sizeof(data)) != sizeof(data)) {
-                               fprintf(stderr, "hpet_poll: read failed\n");
-                       }
-                       else
-                               fprintf(stderr, "hpet_poll: data 0x%lx\n",
-                                       data);
-               }
-       }
-
-out:
-       close(fd);
-       return;
-}
-
-static int hpet_sigio_count;
-
-static void
-hpet_sigio(int val)
-{
-       fprintf(stderr, "hpet_sigio: called\n");
-       hpet_sigio_count++;
-}
-
-void
-hpet_fasync(int argc, const char **argv)
-{
-       unsigned long           freq;
-       int                     iterations, i, fd, value;
-       sig_t                   oldsig;
-       struct hpet_info        info;
-
-       hpet_sigio_count = 0;
-       fd = -1;
-
-       if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
-               fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
-               return;
-       }
-
-       if (argc != 3) {
-               fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
-               goto out;
-       }
-
-       fd = open(argv[0], O_RDONLY);
-
-       if (fd < 0) {
-               fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
-               return;
-       }
-
-
-       if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
-               ((value = fcntl(fd, F_GETFL)) == 1) ||
-               (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
-               fprintf(stderr, "hpet_fasync: fcntl failed\n");
-               goto out;
-       }
-
-       freq = atoi(argv[1]);
-       iterations = atoi(argv[2]);
-
-       if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
-               fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
-               goto out;
-       }
-
-       if (ioctl(fd, HPET_INFO, &info) < 0) {
-               fprintf(stderr, "hpet_fasync: failed to get info\n");
-               goto out;
-       }
-
-       fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
-
-       if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
-               fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
-               goto out;
-       }
-
-       if (ioctl(fd, HPET_IE_ON, 0) < 0) {
-               fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
-               goto out;
-       }
-
-       for (i = 0; i < iterations; i++) {
-               (void) pause();
-               fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
-       }
-
-out:
-       signal(SIGIO, oldsig);
-
-       if (fd >= 0)
-               close(fd);
-
-       return;
-}
+RTC driver framework.  An example user space program is provided in
+file:Documentation/timers/hpet_example.c
diff --git a/Documentation/timers/hpet_example.c b/Documentation/timers/hpet_example.c
new file mode 100644 (file)
index 0000000..f9ce2d9
--- /dev/null
@@ -0,0 +1,269 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <malloc.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <linux/hpet.h>
+
+
+extern void hpet_open_close(int, const char **);
+extern void hpet_info(int, const char **);
+extern void hpet_poll(int, const char **);
+extern void hpet_fasync(int, const char **);
+extern void hpet_read(int, const char **);
+
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+struct hpet_command {
+       char            *command;
+       void            (*func)(int argc, const char ** argv);
+} hpet_command[] = {
+       {
+               "open-close",
+               hpet_open_close
+       },
+       {
+               "info",
+               hpet_info
+       },
+       {
+               "poll",
+               hpet_poll
+       },
+       {
+               "fasync",
+               hpet_fasync
+       },
+};
+
+int
+main(int argc, const char ** argv)
+{
+       int     i;
+
+       argc--;
+       argv++;
+
+       if (!argc) {
+               fprintf(stderr, "-hpet: requires command\n");
+               return -1;
+       }
+
+
+       for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
+               if (!strcmp(argv[0], hpet_command[i].command)) {
+                       argc--;
+                       argv++;
+                       fprintf(stderr, "-hpet: executing %s\n",
+                               hpet_command[i].command);
+                       hpet_command[i].func(argc, argv);
+                       return 0;
+               }
+
+       fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
+
+       return -1;
+}
+
+void
+hpet_open_close(int argc, const char **argv)
+{
+       int     fd;
+
+       if (argc != 1) {
+               fprintf(stderr, "hpet_open_close: device-name\n");
+               return;
+       }
+
+       fd = open(argv[0], O_RDONLY);
+       if (fd < 0)
+               fprintf(stderr, "hpet_open_close: open failed\n");
+       else
+               close(fd);
+
+       return;
+}
+
+void
+hpet_info(int argc, const char **argv)
+{
+}
+
+void
+hpet_poll(int argc, const char **argv)
+{
+       unsigned long           freq;
+       int                     iterations, i, fd;
+       struct pollfd           pfd;
+       struct hpet_info        info;
+       struct timeval          stv, etv;
+       struct timezone         tz;
+       long                    usec;
+
+       if (argc != 3) {
+               fprintf(stderr, "hpet_poll: device-name freq iterations\n");
+               return;
+       }
+
+       freq = atoi(argv[1]);
+       iterations = atoi(argv[2]);
+
+       fd = open(argv[0], O_RDONLY);
+
+       if (fd < 0) {
+               fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
+               return;
+       }
+
+       if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+               fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
+               goto out;
+       }
+
+       if (ioctl(fd, HPET_INFO, &info) < 0) {
+               fprintf(stderr, "hpet_poll: failed to get info\n");
+               goto out;
+       }
+
+       fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
+
+       if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+               fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
+               goto out;
+       }
+
+       if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+               fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
+               goto out;
+       }
+
+       pfd.fd = fd;
+       pfd.events = POLLIN;
+
+       for (i = 0; i < iterations; i++) {
+               pfd.revents = 0;
+               gettimeofday(&stv, &tz);
+               if (poll(&pfd, 1, -1) < 0)
+                       fprintf(stderr, "hpet_poll: poll failed\n");
+               else {
+                       long    data;
+
+                       gettimeofday(&etv, &tz);
+                       usec = stv.tv_sec * 1000000 + stv.tv_usec;
+                       usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
+
+                       fprintf(stderr,
+                               "hpet_poll: expired time = 0x%lx\n", usec);
+
+                       fprintf(stderr, "hpet_poll: revents = 0x%x\n",
+                               pfd.revents);
+
+                       if (read(fd, &data, sizeof(data)) != sizeof(data)) {
+                               fprintf(stderr, "hpet_poll: read failed\n");
+                       }
+                       else
+                               fprintf(stderr, "hpet_poll: data 0x%lx\n",
+                                       data);
+               }
+       }
+
+out:
+       close(fd);
+       return;
+}
+
+static int hpet_sigio_count;
+
+static void
+hpet_sigio(int val)
+{
+       fprintf(stderr, "hpet_sigio: called\n");
+       hpet_sigio_count++;
+}
+
+void
+hpet_fasync(int argc, const char **argv)
+{
+       unsigned long           freq;
+       int                     iterations, i, fd, value;
+       sig_t                   oldsig;
+       struct hpet_info        info;
+
+       hpet_sigio_count = 0;
+       fd = -1;
+
+       if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
+               fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
+               return;
+       }
+
+       if (argc != 3) {
+               fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
+               goto out;
+       }
+
+       fd = open(argv[0], O_RDONLY);
+
+       if (fd < 0) {
+               fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
+               return;
+       }
+
+
+       if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
+               ((value = fcntl(fd, F_GETFL)) == 1) ||
+               (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
+               fprintf(stderr, "hpet_fasync: fcntl failed\n");
+               goto out;
+       }
+
+       freq = atoi(argv[1]);
+       iterations = atoi(argv[2]);
+
+       if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+               fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
+               goto out;
+       }
+
+       if (ioctl(fd, HPET_INFO, &info) < 0) {
+               fprintf(stderr, "hpet_fasync: failed to get info\n");
+               goto out;
+       }
+
+       fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
+
+       if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+               fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
+               goto out;
+       }
+
+       if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+               fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
+               goto out;
+       }
+
+       for (i = 0; i < iterations; i++) {
+               (void) pause();
+               fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
+       }
+
+out:
+       signal(SIGIO, oldsig);
+
+       if (fd >= 0)
+               close(fd);
+
+       return;
+}
index e57d6a9..dca82d7 100644 (file)
@@ -4,23 +4,35 @@ active_mm.txt
        - An explanation from Linus about tsk->active_mm vs tsk->mm.
 balance
        - various information on memory balancing.
+hugepage-mmap.c
+       - Example app using huge page memory with the mmap system call.
+hugepage-shm.c
+       - Example app using huge page memory with Sys V shared memory system calls.
 hugetlbpage.txt
        - a brief summary of hugetlbpage support in the Linux kernel.
+hwpoison.txt
+       - explains what hwpoison is
 ksm.txt
        - how to use the Kernel Samepage Merging feature.
 locking
        - info on how locking and synchronization is done in the Linux vm code.
+map_hugetlb.c
+       - an example program that uses the MAP_HUGETLB mmap flag.
 numa
        - information about NUMA specific code in the Linux vm.
 numa_memory_policy.txt
        - documentation of concepts and APIs of the 2.6 memory policy support.
 overcommit-accounting
        - description of the Linux kernels overcommit handling modes.
+page-types.c
+       - Tool for querying page flags
 page_migration
        - description of page migration in NUMA systems.
+pagemap.txt
+       - pagemap, from the userspace perspective
 slabinfo.c
        - source code for a tool to get reports about slabs.
 slub.txt
        - a short users guide for SLUB.
-map_hugetlb.c
-       - an example program that uses the MAP_HUGETLB mmap flag.
+unevictable-lru.txt
+       - Unevictable LRU infrastructure
index 5bd269b..9dcff32 100644 (file)
@@ -2,7 +2,7 @@
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := slabinfo page-types
+hostprogs-y := slabinfo page-types hugepage-mmap hugepage-shm map_hugetlb
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
diff --git a/Documentation/vm/hugepage-mmap.c b/Documentation/vm/hugepage-mmap.c
new file mode 100644 (file)
index 0000000..db0dd9a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * hugepage-mmap:
+ *
+ * Example of using huge page memory in a user application using the mmap
+ * system call.  Before running this application, make sure that the
+ * administrator has mounted the hugetlbfs filesystem (on some directory
+ * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
+ * example, the app is requesting memory of size 256MB that is backed by
+ * huge pages.
+ *
+ * For the ia64 architecture, the Linux kernel reserves Region number 4 for
+ * huge pages.  That means that if one requires a fixed address, a huge page
+ * aligned address starting with 0x800000... will be required.  If a fixed
+ * address is not required, the kernel will select an address in the proper
+ * range.
+ * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define FILE_NAME "/mnt/hugepagefile"
+#define LENGTH (256UL*1024*1024)
+#define PROTECTION (PROT_READ | PROT_WRITE)
+
+/* Only ia64 requires this */
+#ifdef __ia64__
+#define ADDR (void *)(0x8000000000000000UL)
+#define FLAGS (MAP_SHARED | MAP_FIXED)
+#else
+#define ADDR (void *)(0x0UL)
+#define FLAGS (MAP_SHARED)
+#endif
+
+static void check_bytes(char *addr)
+{
+       printf("First hex is %x\n", *((unsigned int *)addr));
+}
+
+static void write_bytes(char *addr)
+{
+       unsigned long i;
+
+       for (i = 0; i < LENGTH; i++)
+               *(addr + i) = (char)i;
+}
+
+static void read_bytes(char *addr)
+{
+       unsigned long i;
+
+       check_bytes(addr);
+       for (i = 0; i < LENGTH; i++)
+               if (*(addr + i) != (char)i) {
+                       printf("Mismatch at %lu\n", i);
+                       break;
+               }
+}
+
+int main(void)
+{
+       void *addr;
+       int fd;
+
+       fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
+       if (fd < 0) {
+               perror("Open failed");
+               exit(1);
+       }
+
+       addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
+       if (addr == MAP_FAILED) {
+               perror("mmap");
+               unlink(FILE_NAME);
+               exit(1);
+       }
+
+       printf("Returned address is %p\n", addr);
+       check_bytes(addr);
+       write_bytes(addr);
+       read_bytes(addr);
+
+       munmap(addr, LENGTH);
+       close(fd);
+       unlink(FILE_NAME);
+
+       return 0;
+}
diff --git a/Documentation/vm/hugepage-shm.c b/Documentation/vm/hugepage-shm.c
new file mode 100644 (file)
index 0000000..07956d8
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * hugepage-shm:
+ *
+ * Example of using huge page memory in a user application using Sys V shared
+ * memory system calls.  In this example the app is requesting 256MB of
+ * memory that is backed by huge pages.  The application uses the flag
+ * SHM_HUGETLB in the shmget system call to inform the kernel that it is
+ * requesting huge pages.
+ *
+ * For the ia64 architecture, the Linux kernel reserves Region number 4 for
+ * huge pages.  That means that if one requires a fixed address, a huge page
+ * aligned address starting with 0x800000... will be required.  If a fixed
+ * address is not required, the kernel will select an address in the proper
+ * range.
+ * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
+ *
+ * Note: The default shared memory limit is quite low on many kernels,
+ * you may need to increase it via:
+ *
+ * echo 268435456 > /proc/sys/kernel/shmmax
+ *
+ * This will increase the maximum size per shared memory segment to 256MB.
+ * The other limit that you will hit eventually is shmall which is the
+ * total amount of shared memory in pages. To set it to 16GB on a system
+ * with a 4kB pagesize do:
+ *
+ * echo 4194304 > /proc/sys/kernel/shmall
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#ifndef SHM_HUGETLB
+#define SHM_HUGETLB 04000
+#endif
+
+#define LENGTH (256UL*1024*1024)
+
+#define dprintf(x)  printf(x)
+
+/* Only ia64 requires this */
+#ifdef __ia64__
+#define ADDR (void *)(0x8000000000000000UL)
+#define SHMAT_FLAGS (SHM_RND)
+#else
+#define ADDR (void *)(0x0UL)
+#define SHMAT_FLAGS (0)
+#endif
+
+int main(void)
+{
+       int shmid;
+       unsigned long i;
+       char *shmaddr;
+
+       if ((shmid = shmget(2, LENGTH,
+                           SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
+               perror("shmget");
+               exit(1);
+       }
+       printf("shmid: 0x%x\n", shmid);
+
+       shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
+       if (shmaddr == (char *)-1) {
+               perror("Shared memory attach failure");
+               shmctl(shmid, IPC_RMID, NULL);
+               exit(2);
+       }
+       printf("shmaddr: %p\n", shmaddr);
+
+       dprintf("Starting the writes:\n");
+       for (i = 0; i < LENGTH; i++) {
+               shmaddr[i] = (char)(i);
+               if (!(i % (1024 * 1024)))
+                       dprintf(".");
+       }
+       dprintf("\n");
+
+       dprintf("Starting the Check...");
+       for (i = 0; i < LENGTH; i++)
+               if (shmaddr[i] != (char)i)
+                       printf("\nIndex %lu mismatched\n", i);
+       dprintf("Done.\n");
+
+       if (shmdt((const void *)shmaddr) != 0) {
+               perror("Detach failure");
+               shmctl(shmid, IPC_RMID, NULL);
+               exit(3);
+       }
+
+       shmctl(shmid, IPC_RMID, NULL);
+
+       return 0;
+}
index bc31636..457634c 100644 (file)
@@ -299,176 +299,11 @@ map_hugetlb.c.
 *******************************************************************
 
 /*
- * Example of using huge page memory in a user application using Sys V shared
- * memory system calls.  In this example the app is requesting 256MB of
- * memory that is backed by huge pages.  The application uses the flag
- * SHM_HUGETLB in the shmget system call to inform the kernel that it is
- * requesting huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
- *
- * Note: The default shared memory limit is quite low on many kernels,
- * you may need to increase it via:
- *
- * echo 268435456 > /proc/sys/kernel/shmmax
- *
- * This will increase the maximum size per shared memory segment to 256MB.
- * The other limit that you will hit eventually is shmall which is the
- * total amount of shared memory in pages. To set it to 16GB on a system
- * with a 4kB pagesize do:
- *
- * echo 4194304 > /proc/sys/kernel/shmall
+ * hugepage-shm:  see Documentation/vm/hugepage-shm.c
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/mman.h>
-
-#ifndef SHM_HUGETLB
-#define SHM_HUGETLB 04000
-#endif
-
-#define LENGTH (256UL*1024*1024)
-
-#define dprintf(x)  printf(x)
-
-#define ADDR (void *)(0x0UL)   /* let kernel choose address */
-#define SHMAT_FLAGS (0)
-
-int main(void)
-{
-       int shmid;
-       unsigned long i;
-       char *shmaddr;
-
-       if ((shmid = shmget(2, LENGTH,
-                           SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
-               perror("shmget");
-               exit(1);
-       }
-       printf("shmid: 0x%x\n", shmid);
-
-       shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
-       if (shmaddr == (char *)-1) {
-               perror("Shared memory attach failure");
-               shmctl(shmid, IPC_RMID, NULL);
-               exit(2);
-       }
-       printf("shmaddr: %p\n", shmaddr);
-
-       dprintf("Starting the writes:\n");
-       for (i = 0; i < LENGTH; i++) {
-               shmaddr[i] = (char)(i);
-               if (!(i % (1024 * 1024)))
-                       dprintf(".");
-       }
-       dprintf("\n");
-
-       dprintf("Starting the Check...");
-       for (i = 0; i < LENGTH; i++)
-               if (shmaddr[i] != (char)i)
-                       printf("\nIndex %lu mismatched\n", i);
-       dprintf("Done.\n");
-
-       if (shmdt((const void *)shmaddr) != 0) {
-               perror("Detach failure");
-               shmctl(shmid, IPC_RMID, NULL);
-               exit(3);
-       }
-
-       shmctl(shmid, IPC_RMID, NULL);
-
-       return 0;
-}
 
 *******************************************************************
 
 /*
- * Example of using huge page memory in a user application using the mmap
- * system call.  Before running this application, make sure that the
- * administrator has mounted the hugetlbfs filesystem (on some directory
- * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
- * example, the app is requesting memory of size 256MB that is backed by
- * huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
+ * hugepage-mmap:  see Documentation/vm/hugepage-mmap.c
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#define FILE_NAME "/mnt/hugepagefile"
-#define LENGTH (256UL*1024*1024)
-#define PROTECTION (PROT_READ | PROT_WRITE)
-
-#define ADDR (void *)(0x0UL)   /* let kernel choose address */
-#define FLAGS (MAP_SHARED)
-
-void check_bytes(char *addr)
-{
-       printf("First hex is %x\n", *((unsigned int *)addr));
-}
-
-void write_bytes(char *addr)
-{
-       unsigned long i;
-
-       for (i = 0; i < LENGTH; i++)
-               *(addr + i) = (char)i;
-}
-
-void read_bytes(char *addr)
-{
-       unsigned long i;
-
-       check_bytes(addr);
-       for (i = 0; i < LENGTH; i++)
-               if (*(addr + i) != (char)i) {
-                       printf("Mismatch at %lu\n", i);
-                       break;
-               }
-}
-
-int main(void)
-{
-       void *addr;
-       int fd;
-
-       fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
-       if (fd < 0) {
-               perror("Open failed");
-               exit(1);
-       }
-
-       addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
-       if (addr == MAP_FAILED) {
-               perror("mmap");
-               unlink(FILE_NAME);
-               exit(1);
-       }
-
-       printf("Returned address is %p\n", addr);
-       check_bytes(addr);
-       write_bytes(addr);
-       read_bytes(addr);
-
-       munmap(addr, LENGTH);
-       close(fd);
-       unlink(FILE_NAME);
-
-       return 0;
-}
index e2bdae3..9969c7d 100644 (file)
 #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
 #endif
 
-void check_bytes(char *addr)
+static void check_bytes(char *addr)
 {
        printf("First hex is %x\n", *((unsigned int *)addr));
 }
 
-void write_bytes(char *addr)
+static void write_bytes(char *addr)
 {
        unsigned long i;
 
@@ -44,7 +44,7 @@ void write_bytes(char *addr)
                *(addr + i) = (char)i;
 }
 
-void read_bytes(char *addr)
+static void read_bytes(char *addr)
 {
        unsigned long i;
 
diff --git a/Documentation/voyager.txt b/Documentation/voyager.txt
deleted file mode 100644 (file)
index 2749af5..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-Running Linux on the Voyager Architecture
-=========================================
-
-For full details and current project status, see
-
-http://www.hansenpartnership.com/voyager
-
-The voyager architecture was designed by NCR in the mid 80s to be a
-fully SMP capable RAS computing architecture built around intel's 486
-chip set.  The voyager came in three levels of architectural
-sophistication: 3,4 and 5 --- 1 and 2 never made it out of prototype.
-The linux patches support only the Level 5 voyager architecture (any
-machine class 3435 and above).
-
-The Voyager Architecture
-------------------------
-
-Voyager machines consist of a Baseboard with a 386 diagnostic
-processor, a Power Supply Interface (PSI) a Primary and possibly
-Secondary Microchannel bus and between 2 and 20 voyager slots.  The
-voyager slots can be populated with memory and cpu cards (up to 4GB
-memory and from 1 486 to 32 Pentium Pro processors).  Internally, the
-voyager has a dual arbitrated system bus and a configuration and test
-bus (CAT).  The voyager bus speed is 40MHz.  Therefore (since all
-voyager cards are dual ported for each system bus) the maximum
-transfer rate is 320Mb/s but only if you have your slot configuration
-tuned (only memory cards can communicate with both busses at once, CPU
-cards utilise them one at a time).
-
-Voyager SMP
------------
-
-Since voyager was the first intel based SMP system, it is slightly
-more primitive than the Intel IO-APIC approach to SMP.  Voyager allows
-arbitrary interrupt routing (including processor affinity routing) of
-all 16 PC type interrupts.  However it does this by using a modified
-5259 master/slave chip set instead of an APIC bus.  Additionally,
-voyager supports Cross Processor Interrupts (CPI) equivalent to the
-APIC IPIs.  There are two routed voyager interrupt lines provided to
-each slot.
-
-Processor Cards
----------------
-
-These come in single, dyadic and quad configurations (the quads are
-problematic--see later).  The maximum configuration is 8 quad cards
-for 32 way SMP.
-
-Quad Processors
----------------
-
-Because voyager only supplies two interrupt lines to each Processor
-card, the Quad processors have to be configured (and Bootstrapped) in
-as a pair of Master/Slave processors.
-
-In fact, most Quad cards only accept one VIC interrupt line, so they
-have one interrupt handling processor (called the VIC extended
-processor) and three non-interrupt handling processors.
-
-Current Status
---------------
-
-The System will boot on Mono, Dyad and Quad cards.  There was
-originally a Quad boot problem which has been fixed by proper gdt
-alignment in the initial boot loader.  If you still cannot get your
-voyager system to boot, email me at:
-
-<J.E.J.Bottomley@HansenPartnership.com>
-
-
-The Quad cards now support using the separate Quad CPI vectors instead
-of going through the VIC mailbox system.
-
-The Level 4 architecture (3430 and 3360 Machines) should also work
-fine.
-
-Dump Switch
------------
-
-The voyager dump switch sends out a broadcast NMI which the voyager
-code intercepts and does a task dump.
-
-Power Switch
-------------
-
-The front panel power switch is intercepted by the kernel and should
-cause a system shutdown and power off.
-
-A Note About Mixed CPU Systems
-------------------------------
-
-Linux isn't designed to handle mixed CPU systems very well.  In order
-to get everything going you *must* make sure that your lowest
-capability CPU is used for booting.  Also, mixing CPU classes
-(e.g. 486 and 586) is really not going to work very well at all.
index bd8ac1e..fe88b5f 100644 (file)
@@ -1251,6 +1251,13 @@ W:       http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/rtc/rtc-bfin.c
 
+BLACKFIN SDH DRIVER
+M:     Cliff Cai <cliff.cai@analog.com>
+L:     uclinux-dist-devel@blackfin.uclinux.org
+W:     http://blackfin.uclinux.org
+S:     Supported
+F:     drivers/mmc/host/bfin_sdh.c
+
 BLACKFIN SERIAL DRIVER
 M:     Sonic Zhang <sonic.zhang@analog.com>
 L:     uclinux-dist-devel@blackfin.uclinux.org
@@ -2820,7 +2827,7 @@ S:        Maintained
 F:     drivers/input/
 
 INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
-M:     Sylvain Meyer <sylvain.meyer@worldonline.fr>
+M:     Maik Broemme <mbroemme@plusserver.de>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/fb/intelfb.txt
@@ -3637,7 +3644,7 @@ F:        mm/
 
 MEMORY RESOURCE CONTROLLER
 M:     Balbir Singh <balbir@linux.vnet.ibm.com>
-M:     Pavel Emelyanov <xemul@openvz.org>
+M:     Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
 M:     KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
 L:     linux-mm@kvack.org
 S:     Maintained
index 1b24895..08ff02d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 33
-EXTRAVERSION =
+SUBLEVEL = 34
+EXTRAVERSION = -rc1
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
index bd7261e..75291fd 100644 (file)
@@ -10,6 +10,7 @@ config ALPHA
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS
        select HAVE_PERF_EVENTS
+       select HAVE_DMA_ATTRS
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -58,6 +59,9 @@ config ZONE_DMA
        bool
        default y
 
+config NEED_DMA_MAP_STATE
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y
index 04eb568..1bce816 100644 (file)
@@ -1,71 +1,49 @@
 #ifndef _ALPHA_DMA_MAPPING_H
 #define _ALPHA_DMA_MAPPING_H
 
+#include <linux/dma-attrs.h>
 
-#ifdef CONFIG_PCI
+extern struct dma_map_ops *dma_ops;
 
-#include <linux/pci.h>
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+       return dma_ops;
+}
 
-#define dma_map_single(dev, va, size, dir)             \
-               pci_map_single(alpha_gendev_to_pci(dev), va, size, dir)
-#define dma_unmap_single(dev, addr, size, dir)         \
-               pci_unmap_single(alpha_gendev_to_pci(dev), addr, size, dir)
-#define dma_alloc_coherent(dev, size, addr, gfp)       \
-             __pci_alloc_consistent(alpha_gendev_to_pci(dev), size, addr, gfp)
-#define dma_free_coherent(dev, size, va, addr)         \
-               pci_free_consistent(alpha_gendev_to_pci(dev), size, va, addr)
-#define dma_map_page(dev, page, off, size, dir)                \
-               pci_map_page(alpha_gendev_to_pci(dev), page, off, size, dir)
-#define dma_unmap_page(dev, addr, size, dir)           \
-               pci_unmap_page(alpha_gendev_to_pci(dev), addr, size, dir)
-#define dma_map_sg(dev, sg, nents, dir)                        \
-               pci_map_sg(alpha_gendev_to_pci(dev), sg, nents, dir)
-#define dma_unmap_sg(dev, sg, nents, dir)              \
-               pci_unmap_sg(alpha_gendev_to_pci(dev), sg, nents, dir)
-#define dma_supported(dev, mask)                       \
-               pci_dma_supported(alpha_gendev_to_pci(dev), mask)
-#define dma_mapping_error(dev, addr)                           \
-               pci_dma_mapping_error(alpha_gendev_to_pci(dev), addr)
+#include <asm-generic/dma-mapping-common.h>
 
-#else  /* no PCI - no IOMMU. */
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t gfp)
+{
+       return get_dma_ops(dev)->alloc_coherent(dev, size, dma_handle, gfp);
+}
 
-#include <asm/io.h>    /* for virt_to_phys() */
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *vaddr, dma_addr_t dma_handle)
+{
+       get_dma_ops(dev)->free_coherent(dev, size, vaddr, dma_handle);
+}
 
-struct scatterlist;
-void *dma_alloc_coherent(struct device *dev, size_t size,
-                        dma_addr_t *dma_handle, gfp_t gfp);
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-              enum dma_data_direction direction);
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return get_dma_ops(dev)->mapping_error(dev, dma_addr);
+}
 
-#define dma_free_coherent(dev, size, va, addr)         \
-               free_pages((unsigned long)va, get_order(size))
-#define dma_supported(dev, mask)               (mask < 0x00ffffffUL ? 0 : 1)
-#define dma_map_single(dev, va, size, dir)     virt_to_phys(va)
-#define dma_map_page(dev, page, off, size, dir)        (page_to_pa(page) + off)
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       return get_dma_ops(dev)->dma_supported(dev, mask);
+}
 
-#define dma_unmap_single(dev, addr, size, dir) ((void)0)
-#define dma_unmap_page(dev, addr, size, dir)   ((void)0)
-#define dma_unmap_sg(dev, sg, nents, dir)      ((void)0)
-
-#define dma_mapping_error(dev, addr)  (0)
-
-#endif /* !CONFIG_PCI */
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+       return get_dma_ops(dev)->set_dma_mask(dev, mask);
+}
 
 #define dma_alloc_noncoherent(d, s, h, f)      dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h)       dma_free_coherent(d, s, v, h)
 #define dma_is_consistent(d, h)                        (1)
 
-int dma_set_mask(struct device *dev, u64 mask);
-
-#define dma_sync_single_for_cpu(dev, addr, size, dir)    ((void)0)
-#define dma_sync_single_for_device(dev, addr, size, dir)  ((void)0)
-#define dma_sync_single_range(dev, addr, off, size, dir)  ((void)0)
-#define dma_sync_sg_for_cpu(dev, sg, nents, dir)         ((void)0)
-#define dma_sync_sg_for_device(dev, sg, nents, dir)      ((void)0)
 #define dma_cache_sync(dev, va, size, dir)               ((void)0)
-#define dma_sync_single_range_for_cpu(dev, addr, offset, size, dir)    ((void)0)
-#define dma_sync_single_range_for_device(dev, addr, offset, size, dir) ((void)0)
-
 #define dma_get_cache_alignment()                        L1_CACHE_BYTES
 
 #endif /* _ALPHA_DMA_MAPPING_H */
index dd8dcab..28d0497 100644 (file)
@@ -70,142 +70,11 @@ extern inline void pcibios_penalize_isa_irq(int irq, int active)
    decisions.  */
 #define PCI_DMA_BUS_IS_PHYS  0
 
-/* Allocate and map kernel buffer using consistent mode DMA for PCI
-   device.  Returns non-NULL cpu-view pointer to the buffer if
-   successful and sets *DMA_ADDRP to the pci side dma address as well,
-   else DMA_ADDRP is undefined.  */
-
-extern void *__pci_alloc_consistent(struct pci_dev *, size_t,
-                                   dma_addr_t *, gfp_t);
-static inline void *
-pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma)
-{
-       return __pci_alloc_consistent(dev, size, dma, GFP_ATOMIC);
-}
-
-/* Free and unmap a consistent DMA buffer.  CPU_ADDR and DMA_ADDR must
-   be values that were returned from pci_alloc_consistent.  SIZE must
-   be the same as what as passed into pci_alloc_consistent.
-   References to the memory and mappings associated with CPU_ADDR or
-   DMA_ADDR past this call are illegal.  */
-
-extern void pci_free_consistent(struct pci_dev *, size_t, void *, dma_addr_t);
-
-/* Map a single buffer of the indicate size for PCI DMA in streaming mode.
-   The 32-bit PCI bus mastering address to use is returned.  Once the device
-   is given the dma address, the device owns this memory until either
-   pci_unmap_single or pci_dma_sync_single_for_cpu is performed.  */
-
-extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int);
-
-/* Likewise, but for a page instead of an address.  */
-extern dma_addr_t pci_map_page(struct pci_dev *, struct page *,
-                              unsigned long, size_t, int);
-
-/* Test for pci_map_single or pci_map_page having generated an error.  */
-
-static inline int
-pci_dma_mapping_error(struct pci_dev *pdev, dma_addr_t dma_addr)
-{
-       return dma_addr == 0;
-}
-
-/* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
-   SIZE must match what was provided for in a previous pci_map_single
-   call.  All other usages are undefined.  After this call, reads by
-   the cpu to the buffer are guaranteed to see whatever the device
-   wrote there.  */
-
-extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
-extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int);
-
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
-/* Map a set of buffers described by scatterlist in streaming mode for
-   PCI DMA.  This is the scatter-gather version of the above
-   pci_map_single interface.  Here the scatter gather list elements
-   are each tagged with the appropriate PCI dma address and length.
-   They are obtained via sg_dma_{address,length}(SG).
-
-   NOTE: An implementation may be able to use a smaller number of DMA
-   address/length pairs than there are SG table elements.  (for
-   example via virtual mapping capabilities) The routine returns the
-   number of addr/length pairs actually used, at most nents.
-
-   Device ownership issues as mentioned above for pci_map_single are
-   the same here.  */
-
-extern int pci_map_sg(struct pci_dev *, struct scatterlist *, int, int);
-
-/* Unmap a set of streaming mode DMA translations.  Again, cpu read
-   rules concerning calls here are the same as for pci_unmap_single()
-   above.  */
-
-extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int);
-
-/* Make physical memory consistent for a single streaming mode DMA
-   translation after a transfer and device currently has ownership
-   of the buffer.
-
-   If you perform a pci_map_single() but wish to interrogate the
-   buffer using the cpu, yet do not wish to teardown the PCI dma
-   mapping, you must call this function before doing so.  At the next
-   point you give the PCI dma address back to the card, you must first
-   perform a pci_dma_sync_for_device, and then the device again owns
-   the buffer.  */
-
-static inline void
-pci_dma_sync_single_for_cpu(struct pci_dev *dev, dma_addr_t dma_addr,
-                           long size, int direction)
-{
-       /* Nothing to do.  */
-}
-
-static inline void
-pci_dma_sync_single_for_device(struct pci_dev *dev, dma_addr_t dma_addr,
-                              size_t size, int direction)
-{
-       /* Nothing to do.  */
-}
-
-/* Make physical memory consistent for a set of streaming mode DMA
-   translations after a transfer.  The same as pci_dma_sync_single_*
-   but for a scatter-gather list, same rules and usage.  */
-
-static inline void
-pci_dma_sync_sg_for_cpu(struct pci_dev *dev, struct scatterlist *sg,
-                       int nents, int direction)
-{
-       /* Nothing to do.  */
-}
-
-static inline void
-pci_dma_sync_sg_for_device(struct pci_dev *dev, struct scatterlist *sg,
-                          int nents, int direction)
-{
-       /* Nothing to do.  */
-}
-
-/* Return whether the given PCI device DMA address mask can
-   be supported properly.  For example, if your device can
-   only drive the low 24-bits during PCI bus mastering, then
-   you would pass 0x00ffffff as the mask to this function.  */
+#ifdef CONFIG_PCI
 
-extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
+/* implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
 
-#ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
                                        unsigned long *strategy_parameter)
@@ -244,8 +113,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
        return hose->need_domain_info;
 }
 
-struct pci_dev *alpha_gendev_to_pci(struct device *dev);
-
 #endif /* __KERNEL__ */
 
 /* Values for the `which' argument to sys_pciconfig_iobase.  */
index 32c7a5c..65cf3e2 100644 (file)
@@ -68,6 +68,7 @@ struct switch_stack {
 
 #ifdef __KERNEL__
 
+#define arch_has_single_step()         (1)
 #define user_mode(regs) (((regs)->ps & 8) != 0)
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
index c19a376..823a540 100644 (file)
@@ -106,58 +106,8 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
                return -ENODEV;
 }
 
-/* Stubs for the routines in pci_iommu.c: */
-
-void *
-__pci_alloc_consistent(struct pci_dev *pdev, size_t size,
-                      dma_addr_t *dma_addrp, gfp_t gfp)
-{
-       return NULL;
-}
-
-void
-pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_addr)
-{
-}
-
-dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size,
-              int direction)
-{
-       return (dma_addr_t) 0;
-}
-
-void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
-                int direction)
-{
-}
-
-int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
-          int direction)
-{
-       return 0;
-}
-
-void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
-            int direction)
-{
-}
-
-int
-pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
-{
-       return 0;
-}
-
-/* Generic DMA mapping functions: */
-
-void *
-dma_alloc_coherent(struct device *dev, size_t size,
-                  dma_addr_t *dma_handle, gfp_t gfp)
+static void *alpha_noop_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t gfp)
 {
        void *ret;
 
@@ -171,11 +121,22 @@ dma_alloc_coherent(struct device *dev, size_t size,
        return ret;
 }
 
-EXPORT_SYMBOL(dma_alloc_coherent);
+static void alpha_noop_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_addr)
+{
+       free_pages((unsigned long)cpu_addr, get_order(size));
+}
+
+static dma_addr_t alpha_noop_map_page(struct device *dev, struct page *page,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction dir,
+                                     struct dma_attrs *attrs)
+{
+       return page_to_pa(page) + offset;
+}
 
-int
-dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
-          enum dma_data_direction direction)
+static int alpha_noop_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
+                            enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        int i;
        struct scatterlist *sg;
@@ -192,19 +153,37 @@ dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
        return nents;
 }
 
-EXPORT_SYMBOL(dma_map_sg);
+static int alpha_noop_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+static int alpha_noop_supported(struct device *dev, u64 mask)
+{
+       return mask < 0x00ffffffUL ? 0 : 1;
+}
 
-int
-dma_set_mask(struct device *dev, u64 mask)
+static int alpha_noop_set_mask(struct device *dev, u64 mask)
 {
        if (!dev->dma_mask || !dma_supported(dev, mask))
                return -EIO;
 
        *dev->dma_mask = mask;
-
        return 0;
 }
-EXPORT_SYMBOL(dma_set_mask);
+
+struct dma_map_ops alpha_noop_ops = {
+       .alloc_coherent         = alpha_noop_alloc_coherent,
+       .free_coherent          = alpha_noop_free_coherent,
+       .map_page               = alpha_noop_map_page,
+       .map_sg                 = alpha_noop_map_sg,
+       .mapping_error          = alpha_noop_mapping_error,
+       .dma_supported          = alpha_noop_supported,
+       .set_dma_mask           = alpha_noop_set_mask,
+};
+
+struct dma_map_ops *dma_ops = &alpha_noop_ops;
+EXPORT_SYMBOL(dma_ops);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
 {
index 8449504..ce9e54c 100644 (file)
@@ -216,10 +216,30 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n)
        for (i = 0; i < n; ++i)
                p[i] = 0;
 }
-\f
-/* True if the machine supports DAC addressing, and DEV can
-   make use of it given MASK.  */
-static int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
+
+/*
+ * True if the machine supports DAC addressing, and DEV can
+ * make use of it given MASK.
+ */
+static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
+{
+       dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
+       int ok = 1;
+
+       /* If this is not set, the machine doesn't support DAC at all.  */
+       if (dac_offset == 0)
+               ok = 0;
+
+       /* The device has to be able to address our DAC bit.  */
+       if ((dac_offset & dev->dma_mask) != dac_offset)
+               ok = 0;
+
+       /* If both conditions above are met, we are fine. */
+       DBGA("pci_dac_dma_supported %s from %p\n",
+            ok ? "yes" : "no", __builtin_return_address(0));
+
+       return ok;
+}
 
 /* Map a single buffer of the indicated size for PCI DMA in streaming
    mode.  The 32-bit PCI bus mastering address to use is returned.
@@ -301,23 +321,36 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        return ret;
 }
 
-dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir)
+/* Helper for generic DMA-mapping functions. */
+static struct pci_dev *alpha_gendev_to_pci(struct device *dev)
 {
-       int dac_allowed; 
+       if (dev && dev->bus == &pci_bus_type)
+               return to_pci_dev(dev);
 
-       if (dir == PCI_DMA_NONE)
-               BUG();
+       /* Assume that non-PCI devices asking for DMA are either ISA or EISA,
+          BUG() otherwise. */
+       BUG_ON(!isa_bridge);
 
-       dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; 
-       return pci_map_single_1(pdev, cpu_addr, size, dac_allowed);
+       /* Assume non-busmaster ISA DMA when dma_mask is not set (the ISA
+          bridge is bus master then). */
+       if (!dev || !dev->dma_mask || !*dev->dma_mask)
+               return isa_bridge;
+
+       /* For EISA bus masters, return isa_bridge (it might have smaller
+          dma_mask due to wiring limitations). */
+       if (*dev->dma_mask >= isa_bridge->dma_mask)
+               return isa_bridge;
+
+       /* This assumes ISA bus master with dma_mask 0xffffff. */
+       return NULL;
 }
-EXPORT_SYMBOL(pci_map_single);
 
-dma_addr_t
-pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
-            size_t size, int dir)
+static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
+                                    unsigned long offset, size_t size,
+                                    enum dma_data_direction dir,
+                                    struct dma_attrs *attrs)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        int dac_allowed;
 
        if (dir == PCI_DMA_NONE)
@@ -327,7 +360,6 @@ pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
        return pci_map_single_1(pdev, (char *)page_address(page) + offset, 
                                size, dac_allowed);
 }
-EXPORT_SYMBOL(pci_map_page);
 
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
    SIZE must match what was provided for in a previous pci_map_single
@@ -335,16 +367,17 @@ EXPORT_SYMBOL(pci_map_page);
    the cpu to the buffer are guaranteed to see whatever the device
    wrote there.  */
 
-void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
-                int direction)
+static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
+                                size_t size, enum dma_data_direction dir,
+                                struct dma_attrs *attrs)
 {
        unsigned long flags;
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
        struct pci_iommu_arena *arena;
        long dma_ofs, npages;
 
-       if (direction == PCI_DMA_NONE)
+       if (dir == PCI_DMA_NONE)
                BUG();
 
        if (dma_addr >= __direct_map_base
@@ -393,25 +426,16 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
        DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n",
              dma_addr, size, npages, __builtin_return_address(0));
 }
-EXPORT_SYMBOL(pci_unmap_single);
-
-void
-pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr,
-              size_t size, int direction)
-{
-       pci_unmap_single(pdev, dma_addr, size, direction);
-}
-EXPORT_SYMBOL(pci_unmap_page);
 
 /* Allocate and map kernel buffer using consistent mode DMA for PCI
    device.  Returns non-NULL cpu-view pointer to the buffer if
    successful and sets *DMA_ADDRP to the pci side dma address as well,
    else DMA_ADDRP is undefined.  */
 
-void *
-__pci_alloc_consistent(struct pci_dev *pdev, size_t size,
-                      dma_addr_t *dma_addrp, gfp_t gfp)
+static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
+                                     dma_addr_t *dma_addrp, gfp_t gfp)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        void *cpu_addr;
        long order = get_order(size);
 
@@ -439,13 +463,12 @@ try_again:
                gfp |= GFP_DMA;
                goto try_again;
        }
-               
+
        DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n",
              size, cpu_addr, *dma_addrp, __builtin_return_address(0));
 
        return cpu_addr;
 }
-EXPORT_SYMBOL(__pci_alloc_consistent);
 
 /* Free and unmap a consistent DMA buffer.  CPU_ADDR and DMA_ADDR must
    be values that were returned from pci_alloc_consistent.  SIZE must
@@ -453,17 +476,16 @@ EXPORT_SYMBOL(__pci_alloc_consistent);
    References to the memory and mappings associated with CPU_ADDR or
    DMA_ADDR past this call are illegal.  */
 
-void
-pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
-                   dma_addr_t dma_addr)
+static void alpha_pci_free_coherent(struct device *dev, size_t size,
+                                   void *cpu_addr, dma_addr_t dma_addr)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
        free_pages((unsigned long)cpu_addr, get_order(size));
 
        DBGA2("pci_free_consistent: [%llx,%zx] from %p\n",
              dma_addr, size, __builtin_return_address(0));
 }
-EXPORT_SYMBOL(pci_free_consistent);
 
 /* Classify the elements of the scatterlist.  Write dma_address
    of each element with:
@@ -626,23 +648,21 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
        return 1;
 }
 
-int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
-          int direction)
+static int alpha_pci_map_sg(struct device *dev, struct scatterlist *sg,
+                           int nents, enum dma_data_direction dir,
+                           struct dma_attrs *attrs)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        struct scatterlist *start, *end, *out;
        struct pci_controller *hose;
        struct pci_iommu_arena *arena;
        dma_addr_t max_dma;
        int dac_allowed;
-       struct device *dev;
 
-       if (direction == PCI_DMA_NONE)
+       if (dir == PCI_DMA_NONE)
                BUG();
 
-       dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
-
-       dev = pdev ? &pdev->dev : NULL;
+       dac_allowed = dev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
 
        /* Fast path single entry scatterlists.  */
        if (nents == 1) {
@@ -699,19 +719,19 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
        /* Some allocation failed while mapping the scatterlist
           entries.  Unmap them now.  */
        if (out > start)
-               pci_unmap_sg(pdev, start, out - start, direction);
+               pci_unmap_sg(pdev, start, out - start, dir);
        return 0;
 }
-EXPORT_SYMBOL(pci_map_sg);
 
 /* Unmap a set of streaming mode DMA translations.  Again, cpu read
    rules concerning calls here are the same as for pci_unmap_single()
    above.  */
 
-void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
-            int direction)
+static void alpha_pci_unmap_sg(struct device *dev, struct scatterlist *sg,
+                              int nents, enum dma_data_direction dir,
+                              struct dma_attrs *attrs)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        unsigned long flags;
        struct pci_controller *hose;
        struct pci_iommu_arena *arena;
@@ -719,7 +739,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
        dma_addr_t max_dma;
        dma_addr_t fbeg, fend;
 
-       if (direction == PCI_DMA_NONE)
+       if (dir == PCI_DMA_NONE)
                BUG();
 
        if (! alpha_mv.mv_pci_tbi)
@@ -783,15 +803,13 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
 
        DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg));
 }
-EXPORT_SYMBOL(pci_unmap_sg);
-
 
 /* Return whether the given PCI device DMA address mask can be
    supported properly.  */
 
-int
-pci_dma_supported(struct pci_dev *pdev, u64 mask)
+static int alpha_pci_supported(struct device *dev, u64 mask)
 {
+       struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        struct pci_controller *hose;
        struct pci_iommu_arena *arena;
 
@@ -818,7 +836,6 @@ pci_dma_supported(struct pci_dev *pdev, u64 mask)
 
        return 0;
 }
-EXPORT_SYMBOL(pci_dma_supported);
 
 \f
 /*
@@ -918,66 +935,32 @@ iommu_unbind(struct pci_iommu_arena *arena, long pg_start, long pg_count)
        return 0;
 }
 
-/* True if the machine supports DAC addressing, and DEV can
-   make use of it given MASK.  */
-
-static int
-pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
-{
-       dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
-       int ok = 1;
-
-       /* If this is not set, the machine doesn't support DAC at all.  */
-       if (dac_offset == 0)
-               ok = 0;
-
-       /* The device has to be able to address our DAC bit.  */
-       if ((dac_offset & dev->dma_mask) != dac_offset)
-               ok = 0;
-
-       /* If both conditions above are met, we are fine. */
-       DBGA("pci_dac_dma_supported %s from %p\n",
-            ok ? "yes" : "no", __builtin_return_address(0));
-
-       return ok;
-}
-
-/* Helper for generic DMA-mapping functions. */
-
-struct pci_dev *
-alpha_gendev_to_pci(struct device *dev)
+static int alpha_pci_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-       if (dev && dev->bus == &pci_bus_type)
-               return to_pci_dev(dev);
-
-       /* Assume that non-PCI devices asking for DMA are either ISA or EISA,
-          BUG() otherwise. */
-       BUG_ON(!isa_bridge);
-
-       /* Assume non-busmaster ISA DMA when dma_mask is not set (the ISA
-          bridge is bus master then). */
-       if (!dev || !dev->dma_mask || !*dev->dma_mask)
-               return isa_bridge;
-
-       /* For EISA bus masters, return isa_bridge (it might have smaller
-          dma_mask due to wiring limitations). */
-       if (*dev->dma_mask >= isa_bridge->dma_mask)
-               return isa_bridge;
-
-       /* This assumes ISA bus master with dma_mask 0xffffff. */
-       return NULL;
+       return dma_addr == 0;
 }
-EXPORT_SYMBOL(alpha_gendev_to_pci);
 
-int
-dma_set_mask(struct device *dev, u64 mask)
+static int alpha_pci_set_mask(struct device *dev, u64 mask)
 {
        if (!dev->dma_mask ||
            !pci_dma_supported(alpha_gendev_to_pci(dev), mask))
                return -EIO;
 
        *dev->dma_mask = mask;
-
        return 0;
 }
-EXPORT_SYMBOL(dma_set_mask);
+
+struct dma_map_ops alpha_pci_ops = {
+       .alloc_coherent         = alpha_pci_alloc_coherent,
+       .free_coherent          = alpha_pci_free_coherent,
+       .map_page               = alpha_pci_map_page,
+       .unmap_page             = alpha_pci_unmap_page,
+       .map_sg                 = alpha_pci_map_sg,
+       .unmap_sg               = alpha_pci_unmap_sg,
+       .mapping_error          = alpha_pci_mapping_error,
+       .dma_supported          = alpha_pci_supported,
+       .set_dma_mask           = alpha_pci_set_mask,
+};
+
+struct dma_map_ops *dma_ops = &alpha_pci_ops;
+EXPORT_SYMBOL(dma_ops);
index e072041..9acadc6 100644 (file)
@@ -249,6 +249,17 @@ ptrace_cancel_bpt(struct task_struct * child)
        return (nsaved != 0);
 }
 
+void user_enable_single_step(struct task_struct *child)
+{
+       /* Mark single stepping.  */
+       task_thread_info(child)->bpt_nsaved = -1;
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       ptrace_cancel_bpt(child);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -256,7 +267,7 @@ ptrace_cancel_bpt(struct task_struct * child)
  */
 void ptrace_disable(struct task_struct *child)
 { 
-       ptrace_cancel_bpt(child);
+       user_disable_single_step(child);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -295,52 +306,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
                ret = put_reg(child, addr, data);
                break;
-
-       case PTRACE_SYSCALL:
-               /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:    /* restart after signal. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               /* make sure single-step breakpoint is gone. */
-               ptrace_cancel_bpt(child);
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-       /*
-        * Make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)
-                       break;
-               child->exit_code = SIGKILL;
-               /* make sure single-step breakpoint is gone. */
-               ptrace_cancel_bpt(child);
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP:  /* execute single instruction. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               /* Mark single stepping.  */
-               task_thread_info(child)->bpt_nsaved = -1;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               wake_up_process(child);
-               /* give it a chance to run. */
-               ret = 0;
-               break;
-
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index e12d700..cadfe2e 100644 (file)
@@ -155,6 +155,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config ZONE_DMA
        bool
 
+config NEED_DMA_MAP_STATE
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
 
index 2793447..ee1d3b8 100644 (file)
@@ -272,33 +272,6 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
                ((dma_addr + size - PHYS_OFFSET) >= SZ_64M);
 }
 
-/*
- * We override these so we properly do dmabounce otherwise drivers
- * are able to set the dma_mask to 0xffffffff and we can no longer
- * trap bounces. :(
- *
- * We just return true on everyhing except for < 64MB in which case
- * we will fail miseralby and die since we can't handle that case.
- */
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       dev_dbg(&dev->dev, "%s: %llx\n", __func__, mask);
-       if (mask >= PHYS_OFFSET + SZ_64M - 1)
-               return 0;
-
-       return -EIO;
-}
-
-int
-pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       dev_dbg(&dev->dev, "%s: %llx\n", __func__, mask);
-       if (mask >= PHYS_OFFSET + SZ_64M - 1)
-               return 0;
-
-       return -EIO;
-}
-
 int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
 {
        it8152_io.start = IT8152_IO_BASE + 0x12000;
index 97300ec..51cc2a2 100644 (file)
@@ -590,8 +590,40 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NUC900=y
+CONFIG_GPM1040A0_320X240=y
+CONFIG_FB_NUC900_DEBUG=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+
 
 #
 # Display device support
@@ -603,6 +635,25 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB_SUPPORT=y
index 256ee1c..69ce072 100644 (file)
@@ -128,6 +128,14 @@ static inline int dma_supported(struct device *dev, u64 mask)
 
 static inline int dma_set_mask(struct device *dev, u64 dma_mask)
 {
+#ifdef CONFIG_DMABOUNCE
+       if (dev->archdata.dmabounce) {
+               if (dma_mask >= ISA_DMA_THRESHOLD)
+                       return 0;
+               else
+                       return -EIO;
+       }
+#endif
        if (!dev->dma_mask || !dma_supported(dev, dma_mask))
                return -EIO;
 
index 226cddd..4798011 100644 (file)
@@ -30,17 +30,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
-/*
- * Whether pci_unmap_{single,page} is a nop depends upon the
- * configuration.
- */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)         ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index eec6e89..9dcb11e 100644 (file)
@@ -128,6 +128,8 @@ struct pt_regs {
 
 #ifdef __KERNEL__
 
+#define arch_has_single_step() (1)
+
 #define user_mode(regs)        \
        (((regs)->ARM_cpsr & 0xf) == 0)
 
index cf9cdaa..dd2bf53 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_OLD_MMAP
+#define __ARCH_WANT_SYS_OLD_SELECT
 
 #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
 #define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_UTIME
index 9314a2d..37ae301 100644 (file)
@@ -91,7 +91,7 @@
                CALL(sys_settimeofday)
 /* 80 */       CALL(sys_getgroups16)
                CALL(sys_setgroups16)
-               CALL(OBSOLETE(old_select))      /* used by libc4 */
+               CALL(OBSOLETE(sys_old_select))  /* used by libc4 */
                CALL(sys_symlink)
                CALL(sys_ni_syscall)            /* was sys_lstat */
 /* 85 */       CALL(sys_readlink)
@@ -99,7 +99,7 @@
                CALL(sys_swapon)
                CALL(sys_reboot)
                CALL(OBSOLETE(sys_old_readdir)) /* used by libc4 */
-/* 90 */       CALL(OBSOLETE(old_mmap))        /* used by libc4 */
+/* 90 */       CALL(OBSOLETE(sys_old_mmap))    /* used by libc4 */
                CALL(sys_munmap)
                CALL(sys_truncate)
                CALL(sys_ftruncate)
index 08f899f..3f562a7 100644 (file)
@@ -452,12 +452,23 @@ void ptrace_cancel_bpt(struct task_struct *child)
                clear_breakpoint(child, &child->thread.debug.bp[i]);
 }
 
+void user_disable_single_step(struct task_struct *task)
+{
+       task->ptrace &= ~PT_SINGLESTEP;
+       ptrace_cancel_bpt(task);
+}
+
+void user_enable_single_step(struct task_struct *task)
+{
+       task->ptrace |= PT_SINGLESTEP;
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  */
 void ptrace_disable(struct task_struct *child)
 {
-       single_step_disable(child);
+       user_disable_single_step(child);
 }
 
 /*
@@ -753,53 +764,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        ret = ptrace_write_user(child, addr, data);
                        break;
 
-               /*
-                * continue/restart and stop at next (return from) syscall
-                */
-               case PTRACE_SYSCALL:
-               case PTRACE_CONT:
-                       ret = -EIO;
-                       if (!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;
-                       single_step_disable(child);
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-
-               /*
-                * make the child exit.  Best I can do is send it a sigkill.
-                * perhaps it should be put in the status that it wants to
-                * exit.
-                */
-               case PTRACE_KILL:
-                       single_step_disable(child);
-                       if (child->exit_state != EXIT_ZOMBIE) {
-                               child->exit_code = SIGKILL;
-                               wake_up_process(child);
-                       }
-                       ret = 0;
-                       break;
-
-               /*
-                * execute single instruction.
-                */
-               case PTRACE_SINGLESTEP:
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       single_step_enable(child);
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       child->exit_code = data;
-                       /* give it a chance to run. */
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-
                case PTRACE_GETREGS:
                        ret = ptrace_getregs(child, (void __user *)data);
                        break;
index def3b61..3926605 100644 (file)
@@ -13,20 +13,6 @@ extern void ptrace_cancel_bpt(struct task_struct *);
 extern void ptrace_set_bpt(struct task_struct *);
 extern void ptrace_break(struct task_struct *, struct pt_regs *);
 
-/*
- * make sure single-step breakpoint is gone.
- */
-static inline void single_step_disable(struct task_struct *task)
-{
-       task->ptrace &= ~PT_SINGLESTEP;
-       ptrace_cancel_bpt(task);
-}
-
-static inline void single_step_enable(struct task_struct *task)
-{
-       task->ptrace |= PT_SINGLESTEP;
-}
-
 /*
  * Send SIGTRAP if we're single-stepping
  */
index ae4027b..4350f75 100644 (file)
 #include <linux/ipc.h>
 #include <linux/uaccess.h>
 
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
-{
-       int error = -EFAULT;
-       struct mmap_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       error = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls.
- */
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set __user *inp, *outp, *exp;
-       struct timeval __user *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc(uint call, int first, int second, int third,
-                      void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
-                                       (const struct timespec __user *)fifth);
-
-       case SEMGET:
-               return sys_semget (first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd(first, (struct msgbuf __user *) ptr, 
-                                 second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-                       if (copy_from_user(&tmp,(struct ipc_kludge __user *)ptr,
-                                          sizeof (tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv (first,
-                                          (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget ((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = do_shmat(first, (char __user *)ptr, second, &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user(raddr, (ulong __user *)third);
-               }
-               case 1: /* Of course, we don't support iBCS2! */
-                       return -EINVAL;
-               }
-       case SHMDT: 
-               return sys_shmdt ((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget (first, second, third);
-       case SHMCTL:
-               return sys_shmctl (first, second,
-                                  (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
-#endif
-
 /* Fork a new task - this creates a new program thread.
  * This is called indirectly via a small wrapper
  */
index d59a0cd..33ff678 100644 (file)
@@ -346,9 +346,6 @@ asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops,
        return sys_oabi_semtimedop(semid, tsops, nsops, NULL);
 }
 
-extern asmlinkage int sys_ipc(uint call, int first, int second, int third,
-                             void __user *ptr, long fifth);
-
 asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
                            void __user *ptr, long fifth)
 {
index 3bd934e..93107d8 100644 (file)
@@ -65,6 +65,8 @@
 #define TS72XX_RTC_DATA_PHYS_BASE      0x11700000
 #define TS72XX_RTC_DATA_SIZE           0x00001000
 
+#define TS72XX_WDT_CONTROL_PHYS_BASE   0x23800000
+#define TS72XX_WDT_FEED_PHYS_BASE      0x23c00000
 
 #ifndef __ASSEMBLY__
 
index 259f782..fac1ec7 100644 (file)
@@ -166,6 +166,26 @@ static struct platform_device ts72xx_rtc_device = {
        .num_resources  = 0,
 };
 
+static struct resource ts72xx_wdt_resources[] = {
+       {
+               .start  = TS72XX_WDT_CONTROL_PHYS_BASE,
+               .end    = TS72XX_WDT_CONTROL_PHYS_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = TS72XX_WDT_FEED_PHYS_BASE,
+               .end    = TS72XX_WDT_FEED_PHYS_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ts72xx_wdt_device = {
+       .name           = "ts72xx-wdt",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ts72xx_wdt_resources),
+       .resource       = ts72xx_wdt_resources,
+};
+
 static struct ep93xx_eth_data ts72xx_eth_data = {
        .phy_id         = 1,
 };
@@ -175,6 +195,7 @@ static void __init ts72xx_init_machine(void)
        ep93xx_init_devices();
        ts72xx_register_flash();
        platform_device_register(&ts72xx_rtc_device);
+       platform_device_register(&ts72xx_wdt_device);
 
        ep93xx_register_eth(&ts72xx_eth_data, 1);
 }
index c4a0159..e318153 100644 (file)
@@ -502,32 +502,6 @@ struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys)
        return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
 }
 
-/*
- * We override these so we properly do dmabounce otherwise drivers
- * are able to set the dma_mask to 0xffffffff and we can no longer
- * trap bounces. :(
- *
- * We just return true on everyhing except for < 64MB in which case 
- * we will fail miseralby and die since we can't handle that case.
- */
-int
-pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       if (mask >= SZ_64M - 1 )
-               return 0;
-
-       return -EIO;
-}
-    
-int
-pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       if (mask >= SZ_64M - 1 )
-               return 0;
-
-       return -EIO;
-}
-
 EXPORT_SYMBOL(ixp4xx_pci_read);
 EXPORT_SYMBOL(ixp4xx_pci_write);
 
index f9d1c43..f91ca6d 100644 (file)
 #define PCIBIOS_MAX_MEM                0x4BFFFFFF
 #endif
 
-/*
- * We override the standard dma-mask routines for bouncing.
- */
-#define        HAVE_ARCH_PCI_SET_DMA_MASK
-
 #define pcibios_assign_all_busses()    1
 
 /* Register locations and bits */
index 4bd10a1..993d75e 100644 (file)
@@ -288,7 +288,7 @@ int __init am300_init(void)
 }
 
 module_param(panel_type, uint, 0);
-MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
+MODULE_PARM_DESC(panel_type, "Select the panel type: 37, 6, 97");
 
 MODULE_DESCRIPTION("board driver for am300 epd kit");
 MODULE_AUTHOR("Jaya Kumar");
index a5ee707..1d9bc11 100644 (file)
@@ -204,7 +204,7 @@ void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
        ssp_machinfo = machinfo;
 }
 
-static int __init corgi_ssp_probe(struct platform_device *dev)
+static int __devinit corgi_ssp_probe(struct platform_device *dev)
 {
        int ret;
 
index e741bf1..7515757 100644 (file)
@@ -314,7 +314,6 @@ extern unsigned long get_clock_tick_rate(void);
 #define PCIBIOS_MIN_IO         0
 #define PCIBIOS_MIN_MEM                0
 #define pcibios_assign_all_busses()    1
-#define HAVE_ARCH_PCI_SET_DMA_MASK     1
 #endif
 
 
index 67229a1..463d874 100644 (file)
@@ -900,7 +900,7 @@ static struct platform_suspend_ops sharpsl_pm_ops = {
 };
 #endif
 
-static int __init sharpsl_pm_probe(struct platform_device *pdev)
+static int __devinit sharpsl_pm_probe(struct platform_device *pdev)
 {
        int ret;
 
index b7d1f8d..a3f3c7b 100644 (file)
@@ -56,7 +56,7 @@ static const struct rfkill_ops h1940bt_rfkill_ops = {
        .set_block = h1940bt_set_block,
 };
 
-static int __init h1940bt_probe(struct platform_device *pdev)
+static int __devinit h1940bt_probe(struct platform_device *pdev)
 {
        struct rfkill *rfk;
        int ret = 0;
index 506a5e5..9b6dee5 100644 (file)
@@ -130,7 +130,7 @@ void jornada_ssp_end(void)
 };
 EXPORT_SYMBOL(jornada_ssp_end);
 
-static int __init jornada_ssp_probe(struct platform_device *dev)
+static int __devinit jornada_ssp_probe(struct platform_device *dev)
 {
        int ret;
 
index 4d58ba1..f8730b6 100644 (file)
@@ -57,3 +57,4 @@ extern struct platform_device nuc900_device_fmi;
 extern struct platform_device nuc900_device_kpi;
 extern struct platform_device nuc900_device_rtc;
 extern struct platform_device nuc900_device_ts;
+extern struct platform_device nuc900_device_lcd;
index ec711f4..4887612 100644 (file)
@@ -34,6 +34,7 @@
 #include <mach/regs-serial.h>
 #include <mach/nuc900_spi.h>
 #include <mach/map.h>
+#include <mach/fb.h>
 
 #include "cpu.h"
 
@@ -380,6 +381,47 @@ struct platform_device nuc900_device_kpi = {
        .resource       = nuc900_kpi_resource,
 };
 
+#ifdef CONFIG_FB_NUC900
+
+static struct resource nuc900_lcd_resource[] = {
+       [0] = {
+               .start = W90X900_PA_LCD,
+               .end   = W90X900_PA_LCD + W90X900_SZ_LCD - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_LCD,
+               .end   = IRQ_LCD,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 nuc900_device_lcd_dmamask = -1;
+struct platform_device nuc900_device_lcd = {
+       .name             = "nuc900-lcd",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(nuc900_lcd_resource),
+       .resource         = nuc900_lcd_resource,
+       .dev              = {
+               .dma_mask               = &nuc900_device_lcd_dmamask,
+               .coherent_dma_mask      = -1,
+       }
+};
+
+void  nuc900_fb_set_platdata(struct nuc900fb_mach_info *pd)
+{
+       struct nuc900fb_mach_info *npd;
+
+       npd = kmalloc(sizeof(*npd), GFP_KERNEL);
+       if (npd) {
+               memcpy(npd, pd, sizeof(*npd));
+               nuc900_device_lcd.dev.platform_data = npd;
+       } else {
+               printk(KERN_ERR "no memory for LCD platform data\n");
+       }
+}
+#endif
+
 /*Here should be your evb resourse,such as LCD*/
 
 static struct platform_device *nuc900_public_dev[] __initdata = {
diff --git a/arch/arm/mach-w90x900/include/mach/fb.h b/arch/arm/mach-w90x900/include/mach/fb.h
new file mode 100644 (file)
index 0000000..cec5ece
--- /dev/null
@@ -0,0 +1,83 @@
+/* linux/include/asm/arch-nuc900/fb.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Changelog:
+ *
+ *   2008/08/26     vincen.zswan modify this file for LCD.
+ */
+
+#ifndef __ASM_ARM_FB_H
+#define __ASM_ARM_FB_H
+
+
+
+/* LCD Controller Hardware Desc */
+struct nuc900fb_hw {
+       unsigned int lcd_dccs;
+       unsigned int lcd_device_ctrl;
+       unsigned int lcd_mpulcd_cmd;
+       unsigned int lcd_int_cs;
+       unsigned int lcd_crtc_size;
+       unsigned int lcd_crtc_dend;
+       unsigned int lcd_crtc_hr;
+       unsigned int lcd_crtc_hsync;
+       unsigned int lcd_crtc_vr;
+       unsigned int lcd_va_baddr0;
+       unsigned int lcd_va_baddr1;
+       unsigned int lcd_va_fbctrl;
+       unsigned int lcd_va_scale;
+       unsigned int lcd_va_test;
+       unsigned int lcd_va_win;
+       unsigned int lcd_va_stuff;
+};
+
+/* LCD Display Description */
+struct nuc900fb_display {
+       /* LCD Image type */
+       unsigned type;
+
+       /* LCD Screen Size */
+       unsigned short width;
+       unsigned short height;
+
+       /* LCD Screen Info */
+       unsigned short xres;
+       unsigned short yres;
+       unsigned short bpp;
+
+       unsigned long pixclock;
+       unsigned short left_margin;
+       unsigned short right_margin;
+       unsigned short hsync_len;
+       unsigned short upper_margin;
+       unsigned short lower_margin;
+       unsigned short vsync_len;
+
+       /* hardware special register value */
+       unsigned int dccs;
+       unsigned int devctl;
+       unsigned int fbctrl;
+       unsigned int scale;
+};
+
+struct nuc900fb_mach_info {
+       struct nuc900fb_display *displays;
+       unsigned num_displays;
+       unsigned default_display;
+       /* GPIO Setting  Info */
+       unsigned gpio_dir;
+       unsigned gpio_dir_mask;
+       unsigned gpio_data;
+       unsigned gpio_data_mask;
+};
+
+extern void __init nuc900_fb_set_platdata(struct nuc900fb_mach_info *);
+
+#endif /* __ASM_ARM_FB_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-ldm.h b/arch/arm/mach-w90x900/include/mach/regs-ldm.h
new file mode 100644 (file)
index 0000000..e9d480a
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-serial.h
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  Description:
+ *     Nuvoton Display, LCM Register list
+ *  Author:  Wang Qiang (rurality.linux@gmail.com) 2009/12/11
+ *
+ */
+
+
+#ifndef __ASM_ARM_W90X900_REGS_LDM_H
+#define __ASM_ARM_W90X900_REGS_LDM_H
+
+#include <mach/map.h>
+
+/* Display Controller Control/Status Register */
+#define REG_LCM_DCCS                   (0x00)
+
+#define LCM_DCCS_ENG_RST               (1 << 0)
+#define LCM_DCCS_VA_EN                 (1 << 1)
+#define LCM_DCCS_OSD_EN                        (1 << 2)
+#define LCM_DCCS_DISP_OUT_EN           (1 << 3)
+#define LCM_DCCS_DISP_INT_EN           (1 << 4)
+#define LCM_DCCS_CMD_ON                        (1 << 5)
+#define LCM_DCCS_FIELD_INTR            (1 << 6)
+#define LCM_DCCS_SINGLE                        (1 << 7)
+
+enum LCM_DCCS_VA_SRC {
+       LCM_DCCS_VA_SRC_YUV422          = (0 << 8),
+       LCM_DCCS_VA_SRC_YCBCR422        = (1 << 8),
+       LCM_DCCS_VA_SRC_RGB888          = (2 << 8),
+       LCM_DCCS_VA_SRC_RGB666          = (3 << 8),
+       LCM_DCCS_VA_SRC_RGB565          = (4 << 8),
+       LCM_DCCS_VA_SRC_RGB444LOW       = (5 << 8),
+       LCM_DCCS_VA_SRC_RGB444HIGH      = (7 << 8)
+};
+
+
+/* Display Device Control Register */
+#define REG_LCM_DEV_CTRL               (0x04)
+
+enum LCM_DEV_CTRL_SWAP_YCbCr {
+       LCM_DEV_CTRL_SWAP_UYVY          = (0 << 1),
+       LCM_DEV_CTRL_SWAP_YUYV          = (1 << 1),
+       LCM_DEV_CTRL_SWAP_VYUY          = (2 << 1),
+       LCM_DEV_CTRL_SWAP_YVYU          = (3 << 1)
+};
+
+enum LCM_DEV_CTRL_RGB_SHIFT {
+       LCM_DEV_CTRL_RGB_SHIFT_NOT      = (0 << 3),
+       LCM_DEV_CTRL_RGB_SHIFT_ONECYCLE = (1 << 3),
+       LCM_DEV_CTRL_RGB_SHIFT_TWOCYCLE = (2 << 3),
+       LCM_DEV_CTRL_RGB_SHIFT_NOT_DEF  = (3 << 3)
+};
+
+enum LCM_DEV_CTRL_DEVICE {
+       LCM_DEV_CTRL_DEVICE_YUV422      = (0 << 5),
+       LCM_DEV_CTRL_DEVICE_YUV444      = (1 << 5),
+       LCM_DEV_CTRL_DEVICE_UNIPAC      = (4 << 5),
+       LCM_DEV_CTRL_DEVICE_SEIKO_EPSON = (5 << 5),
+       LCM_DEV_CTRL_DEVICE_HIGH_COLOR  = (6 << 5),
+       LCM_DEV_CTRL_DEVICE_MPU         = (7 << 5)
+};
+
+#define LCM_DEV_CTRL_LCD_DDA           (8)
+#define LCM_DEV_CTRL_YUV2CCIR          (16)
+
+enum LCM_DEV_CTRL_LCD_SEL {
+       LCM_DEV_CTRL_LCD_SEL_RGB_GBR    = (0 << 17),
+       LCM_DEV_CTRL_LCD_SEL_BGR_RBG    = (1 << 17),
+       LCM_DEV_CTRL_LCD_SEL_GBR_RGB    = (2 << 17),
+       LCM_DEV_CTRL_LCD_SEL_RBG_BGR    = (3 << 17)
+};
+
+enum LCM_DEV_CTRL_FAL_D {
+       LCM_DEV_CTRL_FAL_D_FALLING      = (0 << 19),
+       LCM_DEV_CTRL_FAL_D_RISING       = (1 << 19),
+};
+
+enum LCM_DEV_CTRL_H_POL {
+       LCM_DEV_CTRL_H_POL_LOW          = (0 << 20),
+       LCM_DEV_CTRL_H_POL_HIGH         = (1 << 20),
+};
+
+enum LCM_DEV_CTRL_V_POL {
+       LCM_DEV_CTRL_V_POL_LOW          = (0 << 21),
+       LCM_DEV_CTRL_V_POL_HIGH         = (1 << 21),
+};
+
+enum LCM_DEV_CTRL_VR_LACE {
+       LCM_DEV_CTRL_VR_LACE_NINTERLACE = (0 << 22),
+       LCM_DEV_CTRL_VR_LACE_INTERLACE  = (1 << 22),
+};
+
+enum LCM_DEV_CTRL_LACE {
+       LCM_DEV_CTRL_LACE_NINTERLACE    = (0 << 23),
+       LCM_DEV_CTRL_LACE_INTERLACE     = (1 << 23),
+};
+
+enum LCM_DEV_CTRL_RGB_SCALE {
+       LCM_DEV_CTRL_RGB_SCALE_4096     = (0 << 24),
+       LCM_DEV_CTRL_RGB_SCALE_65536    = (1 << 24),
+       LCM_DEV_CTRL_RGB_SCALE_262144   = (2 << 24),
+       LCM_DEV_CTRL_RGB_SCALE_16777216 = (3 << 24),
+};
+
+enum LCM_DEV_CTRL_DBWORD {
+       LCM_DEV_CTRL_DBWORD_HALFWORD    = (0 << 26),
+       LCM_DEV_CTRL_DBWORD_FULLWORD    = (1 << 26),
+};
+
+enum LCM_DEV_CTRL_MPU68 {
+       LCM_DEV_CTRL_MPU68_80_SERIES    = (0 << 27),
+       LCM_DEV_CTRL_MPU68_68_SERIES    = (1 << 27),
+};
+
+enum LCM_DEV_CTRL_DE_POL {
+       LCM_DEV_CTRL_DE_POL_HIGH        = (0 << 28),
+       LCM_DEV_CTRL_DE_POL_LOW         = (1 << 28),
+};
+
+#define LCM_DEV_CTRL_CMD16             (29)
+#define LCM_DEV_CTRL_CM16t18           (30)
+#define LCM_DEV_CTRL_CMD_LOW           (31)
+
+/* MPU-Interface LCD Write Command */
+#define REG_LCM_MPU_CMD                        (0x08)
+
+/* Interrupt Control/Status Register */
+#define REG_LCM_INT_CS                 (0x0c)
+#define LCM_INT_CS_DISP_F_EN           (1 << 0)
+#define LCM_INT_CS_UNDERRUN_EN         (1 << 1)
+#define LCM_INT_CS_BUS_ERROR_INT       (1 << 28)
+#define LCM_INT_CS_UNDERRUN_INT        (1 << 29)
+#define LCM_INT_CS_DISP_F_STATUS       (1 << 30)
+#define LCM_INT_CS_DISP_F_INT          (1 << 31)
+
+/* CRTC Display Size Control Register */
+#define REG_LCM_CRTC_SIZE              (0x10)
+#define LCM_CRTC_SIZE_VTTVAL(x)                ((x) << 16)
+#define LCM_CRTC_SIZE_HTTVAL(x)                ((x) << 0)
+
+/* CRTC Display Enable End */
+#define REG_LCM_CRTC_DEND              (0x14)
+#define LCM_CRTC_DEND_VDENDVAL(x)      ((x) << 16)
+#define LCM_CRTC_DEND_HDENDVAL(x)      ((x) << 0)
+
+/* CRTC Internal Horizontal Retrace Control Register */
+#define REG_LCM_CRTC_HR                        (0x18)
+#define LCM_CRTC_HR_EVAL(x)            ((x) << 16)
+#define LCM_CRTC_HR_SVAL(x)            ((x) << 0)
+
+/* CRTC Horizontal Sync Control Register */
+#define REG_LCM_CRTC_HSYNC             (0x1C)
+#define LCM_CRTC_HSYNC_SHIFTVAL(x)     ((x) << 30)
+#define LCM_CRTC_HSYNC_EVAL(x)         ((x) << 16)
+#define LCM_CRTC_HSYNC_SVAL(x)         ((x) << 0)
+
+/* CRTC Internal Vertical Retrace Control Register */
+#define REG_LCM_CRTC_VR                        (0x20)
+#define LCM_CRTC_VR_EVAL(x)            ((x) << 16)
+#define LCM_CRTC_VR_SVAL(x)            ((x) << 0)
+
+/* Video Stream Frame Buffer-0 Starting Address */
+#define REG_LCM_VA_BADDR0              (0x24)
+
+/* Video Stream Frame Buffer-1 Starting Address */
+#define REG_LCM_VA_BADDR1              (0x28)
+
+/* Video Stream Frame Buffer Control Register */
+#define REG_LCM_VA_FBCTRL              (0x2C)
+#define LCM_VA_FBCTRL_IO_REGION_HALF   (1 << 28)
+#define LCM_VA_FBCTRL_FIELD_DUAL       (1 << 29)
+#define LCM_VA_FBCTRL_START_BUF        (1 << 30)
+#define LCM_VA_FBCTRL_DB_EN            (1 << 31)
+
+/* Video Stream Scaling Control Register */
+#define REG_LCM_VA_SCALE               (0x30)
+#define LCM_VA_SCALE_XCOPY_INTERPOLATION (0 << 15)
+#define LCM_VA_SCALE_XCOPY_DUPLICATION  (1 << 15)
+
+/* Image Stream Active Window Coordinates */
+#define REG_LCM_VA_WIN                 (0x38)
+
+/* Image Stream Stuff Pixel */
+#define REG_LCM_VA_STUFF               (0x3C)
+
+/* OSD Window Starting Coordinates */
+#define REG_LCM_OSD_WINS               (0x40)
+
+/* OSD Window Ending Coordinates */
+#define REG_LCM_OSD_WINE               (0x44)
+
+/* OSD Stream Frame Buffer Starting Address */
+#define REG_LCM_OSD_BADDR              (0x48)
+
+/* OSD Stream Frame Buffer Control Register */
+#define REG_LCM_OSD_FBCTRL             (0x4c)
+
+/* OSD Overlay Control Register */
+#define REG_LCM_OSD_OVERLAY            (0x50)
+
+/* OSD Overlay Color-Key Pattern Register */
+#define REG_LCM_OSD_CKEY               (0x54)
+
+/* OSD Overlay Color-Key Mask Register */
+#define REG_LCM_OSD_CMASK              (0x58)
+
+/* OSD Window Skip1 Register */
+#define REG_LCM_OSD_SKIP1              (0x5C)
+
+/* OSD Window Skip2 Register */
+#define REG_LCM_OSD_SKIP2              (0x60)
+
+/* OSD horizontal up scaling control register */
+#define REG_LCM_OSD_SCALE              (0x64)
+
+/* MPU Vsync control register */
+#define REG_LCM_MPU_VSYNC              (0x68)
+
+/* Hardware cursor control Register */
+#define REG_LCM_HC_CTRL                        (0x6C)
+
+/* Hardware cursot tip point potison on va picture */
+#define REG_LCM_HC_POS                 (0x70)
+
+/* Hardware Cursor Window Buffer Control Register */
+#define REG_LCM_HC_WBCTRL              (0x74)
+
+/* Hardware cursor memory base address register */
+#define REG_LCM_HC_BADDR               (0x78)
+
+/* Hardware cursor color ram register mapped to bpp = 0 */
+#define REG_LCM_HC_COLOR0              (0x7C)
+
+/* Hardware cursor color ram register mapped to bpp = 1 */
+#define REG_LCM_HC_COLOR1              (0x80)
+
+/* Hardware cursor color ram register mapped to bpp = 2 */
+#define REG_LCM_HC_COLOR2              (0x84)
+
+/* Hardware cursor color ram register mapped to bpp = 3 */
+#define REG_LCM_HC_COLOR3              (0x88)
+
+#endif /* __ASM_ARM_W90X900_REGS_LDM_H */
index cef903b..b3edc3c 100644 (file)
@@ -10,6 +10,8 @@
  * This program is free software; 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.
+ *   history:
+ *     Wang Qiang (rurality.linux@gmail.com) add LCD support
  *
  */
 
 #include <asm/mach/map.h>
 #include <asm/mach-types.h>
 #include <mach/map.h>
+#include <mach/regs-ldm.h>
+#include <mach/fb.h>
 
 #include "nuc950.h"
 
+#ifdef CONFIG_FB_NUC900
+/* LCD Controller */
+static struct nuc900fb_display __initdata nuc950_lcd_info[] = {
+       /* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
+       [0] = {
+               .type           = LCM_DCCS_VA_SRC_RGB565,
+               .width          = 320,
+               .height         = 240,
+               .xres           = 320,
+               .yres           = 240,
+               .bpp            = 16,
+               .pixclock       = 200000,
+               .left_margin    = 34,
+               .right_margin   = 54,
+               .hsync_len      = 10,
+               .upper_margin   = 18,
+               .lower_margin   = 4,
+               .vsync_len      = 1,
+               .dccs           = 0x8e00041a,
+               .devctl         = 0x060800c0,
+               .fbctrl         = 0x00a000a0,
+               .scale          = 0x04000400,
+       },
+};
+
+static struct nuc900fb_mach_info nuc950_fb_info __initdata = {
+#if defined(CONFIG_GPM1040A0_320X240)
+       .displays               = &nuc950_lcd_info[0],
+#else
+       .displays               = nuc950_lcd_info,
+#endif
+       .num_displays           = ARRAY_SIZE(nuc950_lcd_info),
+       .default_display        = 0,
+       .gpio_dir               = 0x00000004,
+       .gpio_dir_mask          = 0xFFFFFFFD,
+       .gpio_data              = 0x00000004,
+       .gpio_data_mask         = 0xFFFFFFFD,
+};
+#endif
+
 static void __init nuc950evb_map_io(void)
 {
        nuc950_map_io();
@@ -30,6 +74,9 @@ static void __init nuc950evb_map_io(void)
 static void __init nuc950evb_init(void)
 {
        nuc950_board_init();
+#ifdef CONFIG_FB_NUC900
+       nuc900_fb_set_platdata(&nuc950_fb_info);
+#endif
 }
 
 MACHINE_START(W90P950EVB, "W90P950EVB")
index 1495081..4d1f1ab 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
+
 #include "cpu.h"
 
 /* define specific CPU platform device */
@@ -25,6 +26,9 @@
 static struct platform_device *nuc950_dev[] __initdata = {
        &nuc900_device_kpi,
        &nuc900_device_fmi,
+#ifdef CONFIG_FB_NUC900
+       &nuc900_device_lcd,
+#endif
 };
 
 /* define specific CPU platform io map */
index 9e2d44f..e53dd0d 100644 (file)
@@ -124,6 +124,8 @@ struct pt_regs {
 
 #include <asm/ocd.h>
 
+#define arch_has_single_step()         (1)
+
 #define arch_ptrace_attach(child)       ocd_enable(child)
 
 #define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
index 1fed38f..dd5b882 100644 (file)
@@ -28,9 +28,9 @@ static struct pt_regs *get_user_regs(struct task_struct *tsk)
                                  THREAD_SIZE - sizeof(struct pt_regs));
 }
 
-static void ptrace_single_step(struct task_struct *tsk)
+static void user_enable_single_step(struct task_struct *tsk)
 {
-       pr_debug("ptrace_single_step: pid=%u, PC=0x%08lx, SR=0x%08lx\n",
+       pr_debug("user_enable_single_step: pid=%u, PC=0x%08lx, SR=0x%08lx\n",
                 tsk->pid, task_pt_regs(tsk)->pc, task_pt_regs(tsk)->sr);
 
        /*
@@ -49,6 +49,11 @@ static void ptrace_single_step(struct task_struct *tsk)
        set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
 }
 
+void user_disable_single_step(struct task_struct *child)
+{
+       /* XXX(hch): a no-op here seems wrong.. */
+}
+
 /*
  * Called by kernel/ptrace.c when detaching
  *
@@ -167,50 +172,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_write_user(child, addr, data);
                break;
 
-       /* continue and stop at next (return from) syscall */
-       case PTRACE_SYSCALL:
-       /* restart after signal */
-       case PTRACE_CONT:
-               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;
-               /* XXX: Are we sure no breakpoints are active here? */
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-       /*
-        * Make the child exit. Best I can do is send it a
-        * SIGKILL. Perhaps it should be put in the status that it
-        * wants to exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)
-                       break;
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
-               break;
-
-       /*
-        * execute single instruction.
-        */
-       case PTRACE_SINGLESTEP:
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               ptrace_single_step(child);
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-               break;
-
        case PTRACE_GETREGS:
                ret = ptrace_getregs(child, (void __user *)data);
                break;
index f9172ff..413a303 100644 (file)
@@ -65,13 +65,6 @@ _dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir)
        }
 }
 
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
- */
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
               enum dma_data_direction dir)
@@ -88,14 +81,6 @@ dma_map_page(struct device *dev, struct page *page,
        return dma_map_single(dev, page_address(page) + offset, size, dir);
 }
 
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
 static inline void
 dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
                 enum dma_data_direction dir)
@@ -110,30 +95,9 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
        dma_unmap_single(dev, dma_addr, size, dir);
 }
 
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
 extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                      enum dma_data_direction dir);
 
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
 static inline void
 dma_unmap_sg(struct device *dev, struct scatterlist *sg,
             int nhwentries, enum dma_data_direction dir)
index c52bef3..0d6420d 100644 (file)
@@ -692,7 +692,7 @@ sys_call_table:
        .long sys_swapon
        .long sys_reboot
        .long sys_old_readdir
-       .long old_mmap          /* 90 */
+       .long sys_old_mmap      /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
index ee505b2..e70c804 100644 (file)
@@ -127,57 +127,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        ret = 0;
                        break;
 
-               case PTRACE_SYSCALL:
-               case PTRACE_CONT:
-                       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;
-                       
-                       /* TODO: make sure any pending breakpoint is killed */
-                       wake_up_process(child);
-                       ret = 0;
-                       
-                       break;
-               
-               /* Make the child exit by sending it a sigkill. */
-               case PTRACE_KILL:
-                       ret = 0;
-                       
-                       if (child->exit_state == EXIT_ZOMBIE)
-                               break;
-                       
-                       child->exit_code = SIGKILL;
-                       
-                       /* TODO: make sure any pending breakpoint is killed */
-                       wake_up_process(child);
-                       break;
-
-               /* Set the trap flag. */
-               case PTRACE_SINGLESTEP:
-                       ret = -EIO;
-                       
-                       if (!valid_signal(data))
-                               break;
-                       
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-                       /* TODO: set some clever breakpoint mechanism... */
-
-                       child->exit_code = data;
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-
                /* Get all GP registers from the child. */
                case PTRACE_GETREGS: {
                        int i;
index 435b967..1f39861 100644 (file)
@@ -615,7 +615,7 @@ sys_call_table:
        .long sys_swapon
        .long sys_reboot
        .long sys_old_readdir
-       .long old_mmap          /* 90 */
+       .long sys_old_mmap      /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
index dd40147..f4ebd1e 100644 (file)
@@ -78,6 +78,35 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
        return 0;
 }
 
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long tmp;
+
+       /*
+        * Set up SPC if not set already (in which case we have no other
+        * choice but to trust it).
+        */
+       if (!get_reg(child, PT_SPC)) {
+               /* In case we're stopped in a delay slot. */
+               tmp = get_reg(child, PT_ERP) & ~1;
+               put_reg(child, PT_SPC, tmp);
+       }
+       tmp = get_reg(child, PT_CCS) | SBIT_USER;
+       put_reg(child, PT_CCS, tmp);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       put_reg(child, PT_SPC, 0);
+
+       if (!get_debugreg(child->pid, PT_BP_CTRL)) {
+               unsigned long tmp;
+               /* If no h/w bp configured, disable S bit. */
+               tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
+               put_reg(child, PT_CCS, tmp);
+       }
+}
+
 /*
  * Called by kernel/ptrace.c when detaching.
  *
@@ -89,8 +118,7 @@ ptrace_disable(struct task_struct *child)
        unsigned long tmp;
 
        /* Deconfigure SPC and S-bit. */
-       tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
-       put_reg(child, PT_CCS, tmp);
+       user_disable_single_step(child);
        put_reg(child, PT_SPC, 0);
 
        /* Deconfigure any watchpoints associated with the child. */
@@ -169,83 +197,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        ret = 0;
                        break;
 
-               case PTRACE_SYSCALL:
-               case PTRACE_CONT:
-                       ret = -EIO;
-
-                       if (!valid_signal(data))
-                               break;
-
-                       /* Continue means no single-step. */
-                       put_reg(child, PT_SPC, 0);
-
-                       if (!get_debugreg(child->pid, PT_BP_CTRL)) {
-                               unsigned long tmp;
-                               /* If no h/w bp configured, disable S bit. */
-                               tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
-                               put_reg(child, PT_CCS, tmp);
-                       }
-
-                       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;
-
-                       /* TODO: make sure any pending breakpoint is killed */
-                       wake_up_process(child);
-                       ret = 0;
-
-                       break;
-
-               /* Make the child exit by sending it a sigkill. */
-               case PTRACE_KILL:
-                       ret = 0;
-
-                       if (child->exit_state == EXIT_ZOMBIE)
-                               break;
-
-                       child->exit_code = SIGKILL;
-
-                       /* Deconfigure single-step and h/w bp. */
-                       ptrace_disable(child);
-
-                       /* TODO: make sure any pending breakpoint is killed */
-                       wake_up_process(child);
-                       break;
-
-               /* Set the trap flag. */
-               case PTRACE_SINGLESTEP: {
-                       unsigned long tmp;
-                       ret = -EIO;
-
-                       /* Set up SPC if not set already (in which case we have
-                          no other choice but to trust it). */
-                       if (!get_reg(child, PT_SPC)) {
-                               /* In case we're stopped in a delay slot. */
-                               tmp = get_reg(child, PT_ERP) & ~1;
-                               put_reg(child, PT_SPC, tmp);
-                       }
-                       tmp = get_reg(child, PT_CCS) | SBIT_USER;
-                       put_reg(child, PT_CCS, tmp);
-
-                       if (!valid_signal(data))
-                               break;
-
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-                       /* TODO: set some clever breakpoint mechanism... */
-
-                       child->exit_code = data;
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-
-               }
-
                /* Get all GP registers from the child. */
                case PTRACE_GETREGS: {
                        int i;
index 41f4e86..ffca8d0 100644 (file)
@@ -108,6 +108,7 @@ struct switch_stack {
 
 #ifdef __KERNEL__
 
+#define arch_has_single_step() (1)
 #define user_mode(regs) (((regs)->ccs & (1 << (U_CCS_BITNR + CCS_SHIFT))) != 0)
 #define instruction_pointer(regs) ((regs)->erp)
 extern void show_regs(struct pt_regs *);
index 730ce40..9f1cd56 100644 (file)
@@ -44,14 +44,6 @@ struct pci_dev;
  */
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                               enum pci_mmap_state mmap_state, int write_combine);
index c170793..f6fad83 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_MMAP
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index c2bbb1a..7aa036e 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/segment.h>
 
-asmlinkage unsigned long old_mmap(unsigned long __user *args)
-{        
-       unsigned long buffer[6];
-       int err = -EFAULT;
-
-       if (copy_from_user(&buffer, args, sizeof(buffer)))
-               goto out;
-
-       err = -EINVAL;
-       if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */
-               goto out;
-
-       err = sys_mmap_pgoff(buffer[0], buffer[1], buffer[2], buffer[3],
-                       buffer[4], buffer[5] >> PAGE_SHIFT);
-out:
-       return err;
-}
-
 asmlinkage long
 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
           unsigned long flags, unsigned long fd, unsigned long pgoff)
@@ -51,81 +33,3 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
        /* bug(?): 8Kb pages here */
         return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly. (same as arch/i386)
- */
-
-asmlinkage int sys_ipc (uint call, int first, int second,
-                       int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
-                                       (const struct timespec __user *)fifth);
-
-       case SEMGET:
-               return sys_semget (first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
-                                  second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-                       
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr, 
-                                          sizeof (tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv (first,
-                                          (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget ((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
-
-       case SHMAT: {
-                ulong raddr;
-                ret = do_shmat (first, (char __user *) ptr, second, &raddr);
-                if (ret)
-                        return ret;
-                return put_user (raddr, (ulong __user *) third);
-        }
-       case SHMDT: 
-               return sys_shmdt ((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget (first, second, third);
-       case SHMCTL:
-               return sys_shmctl (first, second,
-                                  (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
index b289887..6af5d83 100644 (file)
@@ -7,6 +7,11 @@
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 
+/*
+ * See Documentation/DMA-API.txt for the description of how the
+ * following DMA API should work.
+ */
+
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
@@ -16,24 +21,9 @@ extern unsigned long __nongprelbss dma_coherent_mem_end;
 void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp);
 void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
 
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
- */
 extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                                 enum dma_data_direction direction);
 
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
 static inline
 void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
                      enum dma_data_direction direction)
@@ -41,30 +31,9 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
        BUG_ON(direction == DMA_NONE);
 }
 
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
 extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                      enum dma_data_direction direction);
 
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
 static inline
 void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
             enum dma_data_direction direction)
index 8c7260a..0d59979 100644 (file)
@@ -43,14 +43,6 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)       (0)
 
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index a54b535..6bfad4c 100644 (file)
@@ -84,8 +84,6 @@ extern void show_regs(struct pt_regs *);
 #define task_pt_regs(task) ((task)->thread.frame0)
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
index be6ef0f..b28da49 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 /* #define __ARCH_WANT_SYS_GETHOSTNAME */
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 /* #define __ARCH_WANT_SYS_SGETMASK */
 /* #define __ARCH_WANT_SYS_SIGNAL */
index 1d3d4c9..9c49808 100644 (file)
@@ -42,92 +42,3 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        return sys_mmap_pgoff(addr, len, prot, flags, fd,
                              pgoff >> (PAGE_SHIFT - 12));
 }
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage long sys_ipc(unsigned long call,
-                       unsigned long first,
-                       unsigned long second,
-                       unsigned long third,
-                       void __user *ptr,
-                       unsigned long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
-                                     (const struct timespec __user *)fifth);
-
-       case SEMGET:
-               return sys_semget (first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd (first, (struct msgbuf __user *) ptr,
-                                  second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr,
-                                          sizeof (tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv (first,
-                                          (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget ((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = do_shmat (first, (char __user *) ptr, second, &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user (raddr, (ulong __user *) third);
-               }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               return -EINVAL;
-                       /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
-                       return do_shmat (first, (char __user *) ptr, second, (ulong *) third);
-               }
-       case SHMDT:
-               return sys_shmdt ((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget (first, second, third);
-       case SHMCTL:
-               return sys_shmctl (first, second,
-                                  (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
index 4e1ba0b..e47857f 100644 (file)
@@ -106,13 +106,6 @@ void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_
 
 EXPORT_SYMBOL(dma_free_coherent);
 
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either dma_unmap_single or pci_dma_sync_single is performed.
- */
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                          enum dma_data_direction direction)
 {
@@ -125,22 +118,6 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 
 EXPORT_SYMBOL(dma_map_single);
 
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above dma_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for dma_map_single are
- * the same here.
- */
 int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
               enum dma_data_direction direction)
 {
@@ -157,13 +134,6 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
 EXPORT_SYMBOL(dma_map_sg);
 
-/*
- * Map a single page of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Device ownership issues as mentioned above for dma_map_single are
- * the same here.
- */
 dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset,
                        size_t size, enum dma_data_direction direction)
 {
index 45954f0..2c912e8 100644 (file)
@@ -38,13 +38,6 @@ void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_
 
 EXPORT_SYMBOL(dma_free_coherent);
 
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
- */
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                          enum dma_data_direction direction)
 {
@@ -57,22 +50,6 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 
 EXPORT_SYMBOL(dma_map_single);
 
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above dma_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for dma_map_single are
- * the same here.
- */
 int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
               enum dma_data_direction direction)
 {
@@ -103,13 +80,6 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
 EXPORT_SYMBOL(dma_map_sg);
 
-/*
- * Map a single page of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Device ownership issues as mentioned above for dma_map_single are
- * the same here.
- */
 dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset,
                        size_t size, enum dma_data_direction direction)
 {
index c2e05e4..d866c0e 100644 (file)
@@ -55,6 +55,8 @@ struct pt_regs {
 /* Find the stack offset for a register, relative to thread.esp0. */
 #define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
 
+#define arch_has_single_step() (1)
+
 #define user_mode(regs) (!((regs)->ccr & PS_S))
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
index 99f3c35..50f2c5a 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_MMAP
+#define __ARCH_WANT_SYS_OLD_SELECT
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index d32bbf0..df11412 100644 (file)
 /* cpu depend functions */
 extern long h8300_get_reg(struct task_struct *task, int regno);
 extern int  h8300_put_reg(struct task_struct *task, int regno, unsigned long data);
-extern void h8300_disable_trace(struct task_struct *child);
-extern void h8300_enable_trace(struct task_struct *child);
+
+
+void user_disable_single_step(struct task_struct *child)
+{
+}
 
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
  */
 
-inline
-static int read_long(struct task_struct * tsk, unsigned long addr,
-       unsigned long * result)
-{
-       *result = *(unsigned long *)addr;
-       return 0;
-}
-
 void ptrace_disable(struct task_struct *child)
 {
-       h8300_disable_trace(child);
+       user_disable_single_step(child);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -60,17 +55,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        int ret;
 
        switch (request) {
-               case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-               case PTRACE_PEEKDATA: {
-                       unsigned long tmp;
-
-                       ret = read_long(child, addr, &tmp);
-                       if (ret < 0)
-                               break ;
-                       ret = put_user(tmp, (unsigned long *) data);
-                       break ;
-               }
-
        /* read the word at location addr in the USER area. */
                case PTRACE_PEEKUSR: {
                        unsigned long tmp = 0;
@@ -109,11 +93,6 @@ 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_POKETEXT: /* write the word at location addr. */
-               case PTRACE_POKEDATA:
-                       ret = generic_ptrace_pokedata(child, addr, data);
-                       break;
-
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
                                ret = -EIO;
@@ -131,53 +110,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        }
                        ret = -EIO;
                        break ;
-               case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-               case PTRACE_CONT: { /* restart after signal. */
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break ;
-                       if (request == PTRACE_SYSCALL)
-                               set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       else
-                               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       child->exit_code = data;
-                       wake_up_process(child);
-                       /* make sure the single step bit is not set. */
-                       h8300_disable_trace(child);
-                       ret = 0;
-               }
-
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
-               case PTRACE_KILL: {
-
-                       ret = 0;
-                       if (child->exit_state == EXIT_ZOMBIE) /* already dead */
-                               break;
-                       child->exit_code = SIGKILL;
-                       h8300_disable_trace(child);
-                       wake_up_process(child);
-                       break;
-               }
-
-               case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       child->exit_code = data;
-                       h8300_enable_trace(child);
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-               }
-
-               case PTRACE_DETACH:     /* detach a process that was attached. */
-                       ret = ptrace_detach(child, data);
-                       break;
 
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                        int i;
@@ -210,7 +142,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                }
 
                default:
-                       ret = -EIO;
+                       ret = ptrace_request(child, request, addr, data);
                        break;
        }
        return ret;
index b5969db..f9b3f44 100644 (file)
 #include <asm/traps.h>
 #include <asm/unistd.h>
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
- * handle more than 4 system call parameters, so these system calls
- * used a memory block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct *arg)
-{
-       struct mmap_arg_struct a;
-       int error = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       error = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
-                              a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set *inp, *outp, *exp;
-       struct timeval *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc (uint call, int first, int second,
-                       int third, void *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       return sys_semop (first, (struct sembuf *)ptr, second);
-               case SEMGET:
-                       return sys_semget (first, second, third);
-               case SEMCTL: {
-                       union semun fourth;
-                       if (!ptr)
-                               return -EINVAL;
-                       if (get_user(fourth.__pad, (void **) ptr))
-                               return -EFAULT;
-                       return sys_semctl (first, second, third, fourth);
-                       }
-               default:
-                       return -EINVAL;
-               }
-       if (call <= MSGCTL) 
-               switch (call) {
-               case MSGSND:
-                       return sys_msgsnd (first, (struct msgbuf *) ptr, 
-                                         second, third);
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               if (!ptr)
-                                       return -EINVAL;
-                               if (copy_from_user (&tmp,
-                                                   (struct ipc_kludge *)ptr,
-                                                   sizeof (tmp)))
-                                       return -EFAULT;
-                               return sys_msgrcv (first, tmp.msgp, second,
-                                                  tmp.msgtyp, third);
-                               }
-                       default:
-                               return sys_msgrcv (first,
-                                                  (struct msgbuf *) ptr,
-                                                  second, fifth, third);
-                       }
-               case MSGGET:
-                       return sys_msgget ((key_t) first, second);
-               case MSGCTL:
-                       return sys_msgctl (first, second,
-                                          (struct msqid_ds *) ptr);
-               default:
-                       return -EINVAL;
-               }
-       if (call <= SHMCTL) 
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       default: {
-                               ulong raddr;
-                               ret = do_shmat (first, (char *) ptr,
-                                                second, &raddr);
-                               if (ret)
-                                       return ret;
-                               return put_user (raddr, (ulong *) third);
-                       }
-                       }
-               case SHMDT: 
-                       return sys_shmdt ((char *)ptr);
-               case SHMGET:
-                       return sys_shmget (first, second, third);
-               case SHMCTL:
-                       return sys_shmctl (first, second,
-                                          (struct shmid_ds *) ptr);
-               default:
-                       return -EINVAL;
-               }
-
-       return -EINVAL;
-}
-
 /* sys_cacheflush -- no support.  */
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
index 2d69881..faefaff 100644 (file)
@@ -96,7 +96,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_settimeofday)
        .long SYMBOL_NAME(sys_getgroups16)      /* 80 */
        .long SYMBOL_NAME(sys_setgroups16)
-       .long SYMBOL_NAME(old_select)
+       .long SYMBOL_NAME(sys_old_select)
        .long SYMBOL_NAME(sys_symlink)
        .long SYMBOL_NAME(sys_lstat)
        .long SYMBOL_NAME(sys_readlink)         /* 85 */
@@ -104,7 +104,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_swapon)
        .long SYMBOL_NAME(sys_reboot)
        .long SYMBOL_NAME(sys_old_readdir)
-       .long SYMBOL_NAME(old_mmap)             /* 90 */
+       .long SYMBOL_NAME(sys_old_mmap)         /* 90 */
        .long SYMBOL_NAME(sys_munmap)
        .long SYMBOL_NAME(sys_truncate)
        .long SYMBOL_NAME(sys_ftruncate)
index 746b1ae..4f1ed02 100644 (file)
@@ -60,7 +60,7 @@ int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
 }
 
 /* disable singlestep */
-void h8300_disable_trace(struct task_struct *child)
+void user_disable_single_step(struct task_struct *child)
 {
        if((long)child->thread.breakinfo.addr != -1L) {
                *child->thread.breakinfo.addr = child->thread.breakinfo.inst;
@@ -264,7 +264,7 @@ static unsigned short *getnextpc(struct task_struct *child, unsigned short *pc)
 
 /* Set breakpoint(s) to simulate a single step from the current PC.  */
 
-void h8300_enable_trace(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
 {
        unsigned short *nextpc;
        nextpc = getnextpc(child,(unsigned short *)h8300_get_reg(child, PT_PC));
@@ -276,7 +276,7 @@ void h8300_enable_trace(struct task_struct *child)
 asmlinkage void trace_trap(unsigned long bp)
 {
        if ((unsigned long)current->thread.breakinfo.addr == bp) {
-               h8300_disable_trace(current);
+               user_disable_single_step(current);
                force_sig(SIGTRAP,current);
        } else
                force_sig(SIGILL,current);
index e8cd46f..c058ab1 100644 (file)
@@ -65,13 +65,13 @@ int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
 }
 
 /* disable singlestep */
-void h8300_disable_trace(struct task_struct *child)
+void user_disable_single_step(struct task_struct *child)
 {
        *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) &= ~EXR_TRACE;
 }
 
 /* enable singlestep */
-void h8300_enable_trace(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
 {
        *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) |= EXR_TRACE;
 }
index 9a50d7d..4d4f418 100644 (file)
@@ -53,6 +53,9 @@ config MMU
        bool
        default y
 
+config NEED_DMA_MAP_STATE
+       def_bool y
+
 config SWIOTLB
        bool
 
index dfcf75b..f90edc8 100644 (file)
@@ -5,7 +5,8 @@
  */
 #include <linux/types.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "i686\0\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 55281aa..73b5f78 100644 (file)
@@ -56,20 +56,6 @@ pcibios_penalize_isa_irq (int irq, int active)
 
 #include <asm-generic/pci-dma-compat.h>
 
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index 14055c6..7ae9c3f 100644 (file)
@@ -319,11 +319,7 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
        ptrace_attach_sync_user_rbs(child)
 
   #define arch_has_single_step()  (1)
-  extern void user_enable_single_step(struct task_struct *);
-  extern void user_disable_single_step(struct task_struct *);
-
   #define arch_has_block_step()   (1)
-  extern void user_enable_block_step(struct task_struct *);
 
 #endif /* !__KERNEL__ */
 
index 8f06035..b3a5818 100644 (file)
@@ -282,7 +282,7 @@ static ssize_t cache_show(struct kobject * kobj, struct attribute * attr, char *
        return ret;
 }
 
-static struct sysfs_ops cache_sysfs_ops = {
+static const struct sysfs_ops cache_sysfs_ops = {
        .show   = cache_show
 };
 
index a0755b9..840a123 100644 (file)
@@ -120,6 +120,8 @@ struct pt_regs {
 
 #include <asm/m32r.h>          /* M32R_PSW_BSM, M32R_PSW_BPM */
 
+#define arch_has_single_step() (1)
+
 struct task_struct;
 extern void init_debug_traps(struct task_struct *);
 #define arch_ptrace_attach(child) \
index cf701c9..7612577 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_TIME
 #define __ARCH_WANT_SYS_UTIME
index 98682bb..e555091 100644 (file)
@@ -580,6 +580,35 @@ init_debug_traps(struct task_struct *child)
        }
 }
 
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long next_pc;
+       unsigned long pc, insn;
+
+       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+       /* Compute next pc.  */
+       pc = get_stack_long(child, PT_BPC);
+
+       if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
+           != sizeof(insn))
+               break;
+
+       compute_next_pc(insn, pc, &next_pc, child);
+       if (next_pc & 0x80000000)
+               break;
+
+       if (embed_debug_trap(child, next_pc))
+               break;
+
+       invalidate_cache();
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       unregister_all_debug_traps(child);
+       invalidate_cache();
+}
 
 /*
  * Called by kernel/ptrace.c when detaching..
@@ -630,74 +659,6 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_write_user(child, addr, data);
                break;
 
-       /*
-        * continue/restart and stop at next (return from) syscall
-        */
-       case PTRACE_SYSCALL:
-       case PTRACE_CONT:
-               ret = -EIO;
-               if (!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;
-               wake_up_process(child);
-               ret = 0;
-               break;
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL: {
-               ret = 0;
-               unregister_all_debug_traps(child);
-               invalidate_cache();
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
-               break;
-       }
-
-       /*
-        * execute single instruction.
-        */
-       case PTRACE_SINGLESTEP: {
-               unsigned long next_pc;
-               unsigned long pc, insn;
-
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-               /* Compute next pc.  */
-               pc = get_stack_long(child, PT_BPC);
-
-               if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
-                   != sizeof(insn))
-                       break;
-
-               compute_next_pc(insn, pc, &next_pc, child);
-               if (next_pc & 0x80000000)
-                       break;
-
-               if (embed_debug_trap(child, next_pc))
-                       break;
-
-               invalidate_cache();
-               child->exit_code = data;
-
-               /* give it a chance to run. */
-               wake_up_process(child);
-               ret = 0;
-               break;
-       }
-
        case PTRACE_GETREGS:
                ret = ptrace_getregs(child, (void __user *)data);
                break;
index d3c865c..0a00f46 100644 (file)
@@ -76,98 +76,6 @@ asmlinkage int sys_tas(int __user *addr)
        return oldval;
 }
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc(uint call, int first, int second,
-                      int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second, (const struct timespec __user *)fifth);
-       case SEMGET:
-               return sys_semget (first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
-               }
-
-       case MSGSND:
-               return sys_msgsnd (first, (struct msgbuf __user *) ptr,
-                                  second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr,
-                                          sizeof (tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-                       }
-               default:
-                       return sys_msgrcv (first,
-                                          (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget ((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl (first, second,
-                                  (struct msqid_ds __user *) ptr);
-       case SHMAT: {
-               ulong raddr;
-
-               if (!access_ok(VERIFY_WRITE, (ulong __user *) third,
-                                     sizeof(ulong)))
-                       return -EFAULT;
-               ret = do_shmat (first, (char __user *) ptr, second, &raddr);
-               if (ret)
-                       return ret;
-               return put_user (raddr, (ulong __user *) third);
-               }
-       case SHMDT:
-               return sys_shmdt ((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget (first, second, third);
-       case SHMCTL:
-               return sys_shmctl (first, second,
-                                  (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
-
-asmlinkage int sys_uname(struct old_utsname __user * name)
-{
-       int err;
-       if (!name)
-               return -EFAULT;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof (*name));
-       up_read(&uts_sem);
-       return err?-EFAULT:0;
-}
-
 asmlinkage int sys_cacheflush(void *addr, int bytes, int cache)
 {
        /* This should flush more selectively ...  */
index 21605c7..6e6e3ac 100644 (file)
@@ -87,18 +87,10 @@ struct switch_stack {
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
 
-/*
- * These are defined as per linux/ptrace.h.
- */
-struct task_struct;
-
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
 
 #ifdef CONFIG_MMU
 #define arch_has_block_step()  (1)
-extern void user_enable_block_step(struct task_struct *);
 #endif
 
 #endif /* __KERNEL__ */
index d72a71d..60b15d0 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_MMAP
+#define __ARCH_WANT_SYS_OLD_SELECT
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index e136b8c..2391bdf 100644 (file)
@@ -510,7 +510,7 @@ sys_call_table:
        .long sys_settimeofday
        .long sys_getgroups16   /* 80 */
        .long sys_setgroups16
-       .long old_select
+       .long sys_old_select
        .long sys_symlink
        .long sys_lstat
        .long sys_readlink      /* 85 */
@@ -518,7 +518,7 @@ sys_call_table:
        .long sys_swapon
        .long sys_reboot
        .long sys_old_readdir
-       .long old_mmap          /* 90 */
+       .long sys_old_mmap      /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
index e3ad2d6..7789669 100644 (file)
@@ -46,137 +46,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
- * handle more than 4 system call parameters, so these system calls
- * used a memory block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
-{
-       struct mmap_arg_struct a;
-       int error = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       error = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
-                              a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set __user *inp, *outp, *exp;
-       struct timeval __user *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc (uint call, int first, int second,
-                       int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       return sys_semop (first, ptr, second);
-               case SEMGET:
-                       return sys_semget (first, second, third);
-               case SEMCTL: {
-                       union semun fourth;
-                       if (!ptr)
-                               return -EINVAL;
-                       if (get_user(fourth.__pad, (void __user *__user *) ptr))
-                               return -EFAULT;
-                       return sys_semctl (first, second, third, fourth);
-                       }
-               default:
-                       return -ENOSYS;
-               }
-       if (call <= MSGCTL)
-               switch (call) {
-               case MSGSND:
-                       return sys_msgsnd (first, ptr, second, third);
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               if (!ptr)
-                                       return -EINVAL;
-                               if (copy_from_user (&tmp, ptr, sizeof (tmp)))
-                                       return -EFAULT;
-                               return sys_msgrcv (first, tmp.msgp, second,
-                                                  tmp.msgtyp, third);
-                               }
-                       default:
-                               return sys_msgrcv (first, ptr,
-                                                  second, fifth, third);
-                       }
-               case MSGGET:
-                       return sys_msgget ((key_t) first, second);
-               case MSGCTL:
-                       return sys_msgctl (first, second, ptr);
-               default:
-                       return -ENOSYS;
-               }
-       if (call <= SHMCTL)
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       default: {
-                               ulong raddr;
-                               ret = do_shmat (first, ptr, second, &raddr);
-                               if (ret)
-                                       return ret;
-                               return put_user (raddr, (ulong __user *) third);
-                       }
-                       }
-               case SHMDT:
-                       return sys_shmdt (ptr);
-               case SHMGET:
-                       return sys_shmget (first, second, third);
-               case SHMCTL:
-                       return sys_shmctl (first, second, ptr);
-               default:
-                       return -ENOSYS;
-               }
-
-       return -EINVAL;
-}
-
 /* Convert virtual (user) address VADDR to physical address PADDR */
 #define virt_to_phys_040(vaddr)                                                \
 ({                                                                     \
index 85ed2f9..f6be124 100644 (file)
@@ -116,12 +116,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        int ret;
 
        switch (request) {
-               /* when I and D space are separate, these will need to be fixed. */
-               case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-               case PTRACE_PEEKDATA:
-                       ret = generic_ptrace_peekdata(child, addr, data);
-                       break;
-
                /* read the word at location addr in the USER area. */
                case PTRACE_PEEKUSR: {
                        unsigned long tmp;
@@ -160,12 +154,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
                }
 
-               /* when I and D space are separate, this will have to be fixed. */
-               case PTRACE_POKETEXT: /* write the word at location addr. */
-               case PTRACE_POKEDATA:
-                       ret = generic_ptrace_pokedata(child, addr, data);
-                       break;
-
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
                        ret = -EIO;
                        if ((addr & 3) || addr < 0 ||
@@ -202,66 +190,6 @@ 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;
-
-                       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_SR) & ~(TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-               }
-
-               /*
-                * make the child exit.  Best I can do is send it a sigkill. 
-                * perhaps it should be put in the status that it wants to 
-                * exit.
-                */
-               case PTRACE_KILL: {
-                       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_SR) & ~(TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       wake_up_process(child);
-                       break;
-               }
-
-               case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-                       long tmp;
-
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-
-                       child->exit_code = data;
-                       /* give it a chance to run. */
-                       wake_up_process(child);
-                       ret = 0;
-                       break;
-               }
-
-               case PTRACE_DETACH:     /* detach a process that was attached. */
-                       ret = ptrace_detach(child, data);
-                       break;
-
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                        int i;
                        unsigned long tmp;
@@ -325,7 +253,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
 
                default:
-                       ret = -EIO;
+                       ret = ptrace_request(child, request, addr, data);
                        break;
        }
        return ret;
index 923dd4a..d65e9c4 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/unistd.h>
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
- * handle more than 4 system call parameters, so these system calls
- * used a memory block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct *arg)
-{
-       struct mmap_arg_struct a;
-       int error = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       error = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
-                               a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set *inp, *outp, *exp;
-       struct timeval *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc (uint call, int first, int second,
-                       int third, void *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       return sys_semop (first, (struct sembuf *)ptr, second);
-               case SEMGET:
-                       return sys_semget (first, second, third);
-               case SEMCTL: {
-                       union semun fourth;
-                       if (!ptr)
-                               return -EINVAL;
-                       if (get_user(fourth.__pad, (void **) ptr))
-                               return -EFAULT;
-                       return sys_semctl (first, second, third, fourth);
-                       }
-               default:
-                       return -EINVAL;
-               }
-       if (call <= MSGCTL) 
-               switch (call) {
-               case MSGSND:
-                       return sys_msgsnd (first, (struct msgbuf *) ptr, 
-                                         second, third);
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               if (!ptr)
-                                       return -EINVAL;
-                               if (copy_from_user (&tmp,
-                                                   (struct ipc_kludge *)ptr,
-                                                   sizeof (tmp)))
-                                       return -EFAULT;
-                               return sys_msgrcv (first, tmp.msgp, second,
-                                                  tmp.msgtyp, third);
-                               }
-                       default:
-                               return sys_msgrcv (first,
-                                                  (struct msgbuf *) ptr,
-                                                  second, fifth, third);
-                       }
-               case MSGGET:
-                       return sys_msgget ((key_t) first, second);
-               case MSGCTL:
-                       return sys_msgctl (first, second,
-                                          (struct msqid_ds *) ptr);
-               default:
-                       return -EINVAL;
-               }
-       if (call <= SHMCTL)
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       default: {
-                               ulong raddr;
-                               ret = do_shmat (first, ptr, second, &raddr);
-                               if (ret)
-                                       return ret;
-                               return put_user (raddr, (ulong __user *) third);
-                       }
-                       }
-               case SHMDT:
-                       return sys_shmdt (ptr);
-               case SHMGET:
-                       return sys_shmget (first, second, third);
-               case SHMCTL:
-                       return sys_shmctl (first, second, ptr);
-               default:
-                       return -ENOSYS;
-               }
-
-       return -EINVAL;
-}
-
 /* sys_cacheflush -- flush (part of) the processor cache.  */
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
index 56dd01d..b30b3eb 100644 (file)
@@ -100,7 +100,7 @@ ENTRY(sys_call_table)
        .long sys_settimeofday
        .long sys_getgroups16   /* 80 */
        .long sys_setgroups16
-       .long old_select
+       .long sys_old_select
        .long sys_symlink
        .long sys_lstat
        .long sys_readlink      /* 85 */
@@ -108,7 +108,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall    /* sys_swapon */
        .long sys_reboot
        .long sys_old_readdir
-       .long old_mmap          /* 90 */
+       .long sys_old_mmap      /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
index 4b3ac32..6d6349a 100644 (file)
@@ -78,26 +78,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        unsigned long copied;
 
        switch (request) {
-       case PTRACE_PEEKTEXT: /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-               pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
-               copied = access_process_vm(child, addr, &val, sizeof(val), 0);
-               rval = -EIO;
-               if (copied != sizeof(val))
-                       break;
-               rval = put_user(val, (unsigned long *)data);
-               break;
-
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA:
-               pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
-               rval = 0;
-               if (access_process_vm(child, addr, &data, sizeof(data), 1)
-                   == sizeof(data))
-                       break;
-               rval = -EIO;
-               break;
-
        /* Read/write the word at location ADDR in the registers. */
        case PTRACE_PEEKUSR:
        case PTRACE_POKEUSR:
@@ -130,50 +110,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                if (rval == 0 && request == PTRACE_PEEKUSR)
                        rval = put_user(val, (unsigned long *)data);
                break;
-       /* Continue and stop at next (return from) syscall */
-       case PTRACE_SYSCALL:
-               pr_debug("PTRACE_SYSCALL\n");
-       case PTRACE_SINGLESTEP:
-               pr_debug("PTRACE_SINGLESTEP\n");
-       /* Restart after a signal.  */
-       case PTRACE_CONT:
-               pr_debug("PTRACE_CONT\n");
-               rval = -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;
-               pr_debug("wakeup_process\n");
-               wake_up_process(child);
-               rval = 0;
-               break;
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               pr_debug("PTRACE_KILL\n");
-               rval = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
-               break;
-
-       case PTRACE_DETACH: /* detach a process that was attached. */
-               pr_debug("PTRACE_DETACH\n");
-               rval = ptrace_detach(child, data);
-               break;
        default:
-               /* rval = ptrace_request(child, request, addr, data); noMMU */
-               rval = -EIO;
+               rval = ptrace_request(child, request, addr, data);
        }
        return rval;
 }
index 591ca0c..29e8692 100644 (file)
@@ -812,9 +812,9 @@ config DMA_COHERENT
 
 config DMA_NONCOHERENT
        bool
-       select DMA_NEED_PCI_MAP_STATE
+       select NEED_DMA_MAP_STATE
 
-config DMA_NEED_PCI_MAP_STATE
+config NEED_DMA_MAP_STATE
        bool
 
 config SYS_HAS_EARLY_PRINTK
index f58aed3..613f691 100644 (file)
@@ -8,7 +8,8 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "mips\0\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 5ebf825..3beea14 100644 (file)
@@ -102,28 +102,6 @@ struct pci_dev;
  */
 extern unsigned int PCI_DMA_BUS_IS_PHYS;
 
-#ifdef CONFIG_DMA_NEED_PCI_MAP_STATE
-
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)         ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
-
-#else /* CONFIG_DMA_NEED_PCI_MAP_STATE  */
-
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
-#endif /* CONFIG_DMA_NEED_PCI_MAP_STATE  */
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index 65c679e..1b5a664 100644 (file)
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_UTIME
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index bde79ef..a39d059 100644 (file)
@@ -249,22 +249,6 @@ SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
 }
 #endif
 
-SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name)
-{
-       int ret = 0;
-
-       down_read(&uts_sem);
-       if (copy_to_user(name, utsname(), sizeof *name))
-               ret = -EFAULT;
-       up_read(&uts_sem);
-
-       if (current->personality == PER_LINUX32 && !ret)
-               if (copy_to_user(name->machine, "mips\0\0\0", 8))
-                       ret = -EFAULT;
-
-       return ret;
-}
-
 SYSCALL_DEFINE1(32_personality, unsigned long, personality)
 {
        int ret;
index 054861c..c51b95f 100644 (file)
@@ -493,36 +493,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_setfpregs(child, (__u32 __user *) data);
                break;
 
-       case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT: { /* restart after signal. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL) {
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               }
-               else {
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               }
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-               break;
-       }
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
-               break;
-
        case PTRACE_GET_THREAD_AREA:
                ret = put_user(task_thread_info(child)->tp_value,
                                (unsigned long __user *) data);
index 66b5a48..44337ba 100644 (file)
@@ -181,7 +181,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_exit
        PTR     compat_sys_wait4
        PTR     sys_kill                        /* 6060 */
-       PTR     sys_32_newuname
+       PTR     sys_newuname
        PTR     sys_semget
        PTR     sys_semop
        PTR     sys_n32_semctl
index 515f9ea..813689e 100644 (file)
@@ -325,7 +325,7 @@ sys_call_table:
        PTR     sys32_sigreturn
        PTR     sys32_clone                     /* 4120 */
        PTR     sys_setdomainname
-       PTR     sys_32_newuname
+       PTR     sys_newuname
        PTR     sys_ni_syscall                  /* sys_modify_ldt */
        PTR     compat_sys_adjtimex
        PTR     sys_mprotect                    /* 4125 */
index 3f7f466..e96b1c3 100644 (file)
@@ -215,48 +215,6 @@ out:
        return error;
 }
 
-/*
- * Compacrapability ...
- */
-SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
-{
-       if (name && !copy_to_user(name, utsname(), sizeof (*name)))
-               return 0;
-       return -EFAULT;
-}
-
-/*
- * Compacrapability ...
- */
-SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
-{
-       int error;
-
-       if (!name)
-               return -EFAULT;
-       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
-               return -EFAULT;
-
-       error = __copy_to_user(&name->sysname, &utsname()->sysname,
-                              __OLD_UTS_LEN);
-       error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
-       error -= __copy_to_user(&name->nodename, &utsname()->nodename,
-                               __OLD_UTS_LEN);
-       error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
-       error -= __copy_to_user(&name->release, &utsname()->release,
-                               __OLD_UTS_LEN);
-       error -= __put_user(0, name->release + __OLD_UTS_LEN);
-       error -= __copy_to_user(&name->version, &utsname()->version,
-                               __OLD_UTS_LEN);
-       error -= __put_user(0, name->version + __OLD_UTS_LEN);
-       error -= __copy_to_user(&name->machine, &utsname()->machine,
-                               __OLD_UTS_LEN);
-       error = __put_user(0, name->machine + __OLD_UTS_LEN);
-       error = error ? -EFAULT : 0;
-
-       return error;
-}
-
 SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
 {
        struct thread_info *ti = task_thread_info(current);
@@ -406,94 +364,6 @@ _sys_sysmips(nabi_no_regargs struct pt_regs regs)
        return -EINVAL;
 }
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second,
-       unsigned long, third, void __user *, ptr, long, fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second,
-                                     (const struct timespec __user *)fifth);
-       case SEMGET:
-               return sys_semget(first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user *__user *) ptr))
-                       return -EFAULT;
-               return sys_semctl(first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd(first, (struct msgbuf __user *) ptr,
-                                 second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr,
-                                          sizeof(tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv(first, tmp.msgp, second,
-                                         tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv(first,
-                                         (struct msgbuf __user *) ptr,
-                                         second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl(first, second,
-                                 (struct msqid_ds __user *) ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       unsigned long raddr;
-                       ret = do_shmat(first, (char __user *) ptr, second,
-                                      &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user(raddr, (unsigned long __user *) third);
-               }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               return -EINVAL;
-                       return do_shmat(first, (char __user *) ptr, second,
-                                       (unsigned long *) third);
-               }
-       case SHMDT:
-               return sys_shmdt((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget(first, second, third);
-       case SHMCTL:
-               return sys_shmctl(first, second,
-                                 (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
-
 /*
  * No implemented yet ...
  */
index 727ab21..7f8416f 100644 (file)
@@ -58,13 +58,16 @@ static ssize_t raw_store(struct sys_device *dev,
 static SYSDEV_ATTR(ascii, 0200, NULL, ascii_store);
 static SYSDEV_ATTR(raw, 0200, NULL, raw_store);
 
-static ssize_t map_seg7_show(struct sysdev_class *class, char *buf)
+static ssize_t map_seg7_show(struct sysdev_class *class,
+                            struct sysdev_class_attribute *attr,
+                            char *buf)
 {
        memcpy(buf, &txx9_seg7map, sizeof(txx9_seg7map));
        return sizeof(txx9_seg7map);
 }
 
 static ssize_t map_seg7_store(struct sysdev_class *class,
+                             struct sysdev_class_attribute *attr,
                              const char *buf, size_t size)
 {
        if (size != sizeof(txx9_seg7map))
index ccae8f6..4ed1522 100644 (file)
 #include <asm/cache.h>
 #include <asm/io.h>
 
+/*
+ * See Documentation/DMA-API.txt for the description of how the
+ * following DMA API should work.
+ */
+
 extern void *dma_alloc_coherent(struct device *dev, size_t size,
                                dma_addr_t *dma_handle, int flag);
 
@@ -26,13 +31,6 @@ extern void dma_free_coherent(struct device *dev, size_t size,
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
 #define dma_free_noncoherent(d, s, v, h)  dma_free_coherent((d), (s), (v), (h))
 
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.  The
- * 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory until
- * either pci_unmap_single or pci_dma_sync_single is performed.
- */
 static inline
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
                          enum dma_data_direction direction)
@@ -42,14 +40,6 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
        return virt_to_bus(ptr);
 }
 
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size must
- * match what was provided for in a previous pci_map_single call.  All other
- * usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
 static inline
 void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
                      enum dma_data_direction direction)
@@ -57,20 +47,6 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
        BUG_ON(direction == DMA_NONE);
 }
 
-/*
- * Map a set of buffers described by scatterlist in streaming mode for DMA.
- * This is the scather-gather version of the above pci_map_single interface.
- * Here the scatter gather list elements are each tagged with the appropriate
- * dma address and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of DMA
- *       address/length pairs than there are SG table elements.  (for example
- *       via virtual mapping capabilities) The routine returns the number of
- *       addr/length pairs actually used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are the same
- * here.
- */
 static inline
 int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
               enum dma_data_direction direction)
@@ -91,11 +67,6 @@ int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
        return nents;
 }
 
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
 static inline
 void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
                  enum dma_data_direction direction)
@@ -103,10 +74,6 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
        BUG_ON(!valid_dma_direction(direction));
 }
 
-/*
- * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
- * to pci_map_single, but takes a struct page instead of a virtual address
- */
 static inline
 dma_addr_t dma_map_page(struct device *dev, struct page *page,
                        unsigned long offset, size_t size,
@@ -123,15 +90,6 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
        BUG_ON(direction == DMA_NONE);
 }
 
-/*
- * Make physical memory consistent for a single streaming mode DMA translation
- * after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the buffer using
- * the cpu, yet do not wish to teardown the PCI dma mapping, you must call this
- * function before doing so.  At the next point you give the PCI dma address
- * back to the card, the device again owns the buffer.
- */
 static inline
 void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
                             size_t size, enum dma_data_direction direction)
@@ -161,13 +119,6 @@ dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 }
 
 
-/*
- * Make physical memory consistent for a set of streaming mode DMA translations
- * after a transfer.
- *
- * The same as pci_dma_sync_single but for a scatter-gather list, same rules
- * and usage.
- */
 static inline
 void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
                         int nelems, enum dma_data_direction direction)
@@ -187,12 +138,6 @@ int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
        return 0;
 }
 
-/*
- * Return whether the given PCI device DMA address mask can be supported
- * properly.  For example, if your device can only drive the low 24-bits during
- * PCI bus mastering, then you would pass 0x00ffffff as the mask to this
- * function.
- */
 static inline
 int dma_supported(struct device *dev, u64 mask)
 {
index 1b0ba5e..7c2e911 100644 (file)
@@ -99,8 +99,6 @@ struct task_struct;
 extern void show_regs(struct pt_regs *);
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
 
 #endif  /*  !__ASSEMBLY  */
 
index c05acb9..9d056f5 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_SELECT
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index 88e3e1c..d9ed5a1 100644 (file)
@@ -468,7 +468,7 @@ ENTRY(sys_call_table)
        .long sys_settimeofday
        .long sys_getgroups16   /* 80 */
        .long sys_setgroups16
-       .long old_select
+       .long sys_old_select
        .long sys_symlink
        .long sys_lstat
        .long sys_readlink      /* 85 */
index 17cc6ce..815f135 100644 (file)
@@ -31,109 +31,3 @@ asmlinkage long old_mmap(unsigned long addr, unsigned long len,
                return -EINVAL;
        return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 }
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set *inp;
-       fd_set *outp;
-       fd_set *exp;
-       struct timeval *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage long sys_ipc(uint call, int first, int second,
-                       int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     second,
-                                     (const struct timespec __user *)fifth);
-       case SEMGET:
-               return sys_semget(first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl(first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd(first, (struct msgbuf __user *) ptr,
-                                 second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr,
-                                          sizeof(tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv(first, tmp.msgp, second,
-                                         tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv(first,
-                                         (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl(first, second,
-                                  (struct msqid_ds __user *) ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = do_shmat(first, (char __user *) ptr, second,
-                                      &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user(raddr, (ulong *) third);
-               }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               return -EINVAL;
-                       return do_shmat(first, (char __user *) ptr, second,
-                                       (ulong *) third);
-               }
-       case SHMDT:
-               return sys_shmdt((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget(first, second, third);
-       case SHMCTL:
-               return sys_shmctl(first, second,
-                                 (struct shmid_ds __user *) ptr);
-       default:
-               return -EINVAL;
-       }
-}
index f388dc6..9c4da3d 100644 (file)
@@ -95,6 +95,9 @@ config PM
 config STACKTRACE_SUPPORT
        def_bool y
 
+config NEED_DMA_MAP_STATE
+       def_bool y
+
 config ISA_DMA_API
        bool
 
index 7f32611..02b77ba 100644 (file)
@@ -7,7 +7,8 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ                 100
+#define COMPAT_UTS_MACHINE     "parisc\0\0"
 
 typedef u32    compat_size_t;
 typedef s32    compat_ssize_t;
index 64c7aa5..2242a5c 100644 (file)
@@ -183,20 +183,6 @@ struct pci_bios_ops {
        void (*fixup_bus)(struct pci_bus *bus);
 };
 
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
 /*
 ** Stuff declared in arch/parisc/kernel/pci.c
 */
index aead40b..7f09533 100644 (file)
@@ -47,13 +47,8 @@ struct pt_regs {
 
 #define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
 
-struct task_struct;
 #define arch_has_single_step() 1
-void user_disable_single_step(struct task_struct *task);
-void user_enable_single_step(struct task_struct *task);
-
 #define arch_has_block_step()  1
-void user_enable_block_step(struct task_struct *task);
 
 /* XXX should we use iaoq[1] or iaoq[0] ? */
 #define user_mode(regs)                        (((regs)->iaoq[0] & 3) ? 1 : 0)
index 9147391..c9b9322 100644 (file)
@@ -234,18 +234,3 @@ long parisc_personality(unsigned long personality)
 
        return err;
 }
-
-long parisc_newuname(struct new_utsname __user *name)
-{
-       int err = sys_newuname(name);
-
-#ifdef CONFIG_COMPAT
-       if (!err && personality(current->personality) == PER_LINUX32) {
-               if (__put_user(0, name->machine + 6) ||
-                   __put_user(0, name->machine + 7))
-                       err = -EFAULT;
-       }
-#endif
-
-       return err;
-}
index de5f6da..3d52c97 100644 (file)
        ENTRY_SAME(socketpair)
        ENTRY_SAME(setpgid)
        ENTRY_SAME(send)
-       ENTRY_OURS(newuname)
+       ENTRY_SAME(newuname)
        ENTRY_SAME(umask)               /* 60 */
        ENTRY_SAME(chroot)
        ENTRY_COMP(ustat)
index 155d571..8a54eb8 100644 (file)
@@ -672,6 +672,9 @@ config ZONE_DMA
        bool
        default y
 
+config NEED_DMA_MAP_STATE
+       def_bool (PPC64 || NOT_COHERENT_CACHE)
+
 config GENERIC_ISA_DMA
        bool
        depends on PPC64 || POWER4 || 6xx && !CPM2
index 4774c2f..396d21a 100644 (file)
@@ -7,7 +7,8 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "ppc\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 80a973b..c85ef23 100644 (file)
@@ -127,9 +127,6 @@ static inline int dma_supported(struct device *dev, u64 mask)
        return dma_ops->dma_supported(dev, mask);
 }
 
-/* We have our own implementation of pci_set_dma_mask() */
-#define HAVE_ARCH_PCI_SET_DMA_MASK
-
 static inline int dma_set_mask(struct device *dev, u64 dma_mask)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
index b5ea626..a20a9ad 100644 (file)
@@ -141,38 +141,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
 
 #define HAVE_PCI_LEGACY        1
 
-#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
-/*
- * For 64-bit kernels, pci_unmap_{single,page} is not a nop.
- * For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and
- * so on are not nops.
- * and thus...
- */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
-#else /* 32-bit && coherent */
-
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
-#endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */
-
 #ifdef CONFIG_PPC64
 
 /* The PCI address space does not equal the physical memory address
index b451081..9e2d84c 100644 (file)
@@ -137,15 +137,8 @@ do {                                                                             \
 } while (0)
 #endif /* __powerpc64__ */
 
-/*
- * These are defined as per linux/ptrace.h, which see.
- */
 #define arch_has_single_step() (1)
 #define arch_has_block_step()  (!cpu_has_feature(CPU_FTR_601))
-extern void user_enable_single_step(struct task_struct *);
-extern void user_enable_block_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
-
 #define ARCH_HAS_USER_SINGLE_STEP_INFO
 
 #endif /* __ASSEMBLY__ */
index eb8eb40..4084e56 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include <asm/signal.h>
 
-struct new_utsname;
 struct pt_regs;
 struct rtas_args;
 struct sigaction;
@@ -35,12 +34,9 @@ asmlinkage long sys_pipe2(int __user *fildes, int flags);
 asmlinkage long sys_rt_sigaction(int sig,
                const struct sigaction __user *act,
                struct sigaction __user *oact, size_t sigsetsize);
-asmlinkage int sys_ipc(uint call, int first, unsigned long second,
-               long third, void __user *ptr, long fifth);
 asmlinkage long ppc64_personality(unsigned long personality);
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs);
 asmlinkage time_t sys64_time(time_t __user * tloc);
-asmlinkage long ppc_newuname(struct new_utsname __user * name);
 
 asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
                size_t sigsetsize);
index 07d2d19..a5ee345 100644 (file)
@@ -125,7 +125,7 @@ SYSCALL_SPU(fsync)
 SYS32ONLY(sigreturn)
 PPC_SYS(clone)
 COMPAT_SYS_SPU(setdomainname)
-PPC_SYS_SPU(newuname)
+SYSCALL_SPU(newuname)
 SYSCALL(ni_syscall)
 COMPAT_SYS_SPU(adjtimex)
 SYSCALL_SPU(mprotect)
index f6ca761..f0a1026 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index bb37b1d..01fe9ce 100644 (file)
@@ -642,7 +642,7 @@ static struct kobj_attribute *cache_index_opt_attrs[] = {
        &cache_assoc_attr,
 };
 
-static struct sysfs_ops cache_index_ops = {
+static const struct sysfs_ops cache_index_ops = {
        .show = cache_index_show,
 };
 
index 2597f95..f3c42ce 100644 (file)
@@ -63,21 +63,6 @@ struct dma_map_ops *get_pci_dma_ops(void)
 }
 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;
index 3370e62..f2496f2 100644 (file)
 #include <asm/time.h>
 #include <asm/unistd.h>
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-int sys_ipc(uint call, int first, unsigned long second, long third,
-           void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       ret = -ENOSYS;
-       switch (call) {
-       case SEMOP:
-               ret = sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     (unsigned)second, NULL);
-               break;
-       case SEMTIMEDOP:
-               ret = sys_semtimedop(first, (struct sembuf __user *)ptr,
-                                     (unsigned)second,
-                                     (const struct timespec __user *) fifth);
-               break;
-       case SEMGET:
-               ret = sys_semget (first, (int)second, third);
-               break;
-       case SEMCTL: {
-               union semun fourth;
-
-               ret = -EINVAL;
-               if (!ptr)
-                       break;
-               if ((ret = get_user(fourth.__pad, (void __user * __user *)ptr)))
-                       break;
-               ret = sys_semctl(first, (int)second, third, fourth);
-               break;
-       }
-       case MSGSND:
-               ret = sys_msgsnd(first, (struct msgbuf __user *)ptr,
-                                (size_t)second, third);
-               break;
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-
-                       ret = -EINVAL;
-                       if (!ptr)
-                               break;
-                       if ((ret = copy_from_user(&tmp,
-                                               (struct ipc_kludge __user *) ptr,
-                                               sizeof (tmp)) ? -EFAULT : 0))
-                               break;
-                       ret = sys_msgrcv(first, tmp.msgp, (size_t) second,
-                                         tmp.msgtyp, third);
-                       break;
-               }
-               default:
-                       ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
-                                         (size_t)second, fifth, third);
-                       break;
-               }
-               break;
-       case MSGGET:
-               ret = sys_msgget((key_t)first, (int)second);
-               break;
-       case MSGCTL:
-               ret = sys_msgctl(first, (int)second,
-                                 (struct msqid_ds __user *)ptr);
-               break;
-       case SHMAT: {
-               ulong raddr;
-               ret = do_shmat(first, (char __user *)ptr, (int)second, &raddr);
-               if (ret)
-                       break;
-               ret = put_user(raddr, (ulong __user *) third);
-               break;
-       }
-       case SHMDT:
-               ret = sys_shmdt((char __user *)ptr);
-               break;
-       case SHMGET:
-               ret = sys_shmget(first, (size_t)second, third);
-               break;
-       case SHMCTL:
-               ret = sys_shmctl(first, (int)second,
-                                (struct shmid_ds __user *)ptr);
-               break;
-       }
-
-       return ret;
-}
-
 static inline unsigned long do_mmap2(unsigned long addr, size_t len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, unsigned long off, int shift)
@@ -210,76 +116,6 @@ long ppc64_personality(unsigned long personality)
 }
 #endif
 
-#ifdef CONFIG_PPC64
-#define OVERRIDE_MACHINE    (personality(current->personality) == PER_LINUX32)
-#else
-#define OVERRIDE_MACHINE    0
-#endif
-
-static inline int override_machine(char __user *mach)
-{
-       if (OVERRIDE_MACHINE) {
-               /* change ppc64 to ppc */
-               if (__put_user(0, mach+3) || __put_user(0, mach+4))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-long ppc_newuname(struct new_utsname __user * name)
-{
-       int err = 0;
-
-       down_read(&uts_sem);
-       if (copy_to_user(name, utsname(), sizeof(*name)))
-               err = -EFAULT;
-       up_read(&uts_sem);
-       if (!err)
-               err = override_machine(name->machine);
-       return err;
-}
-
-int sys_uname(struct old_utsname __user *name)
-{
-       int err = 0;
-       
-       down_read(&uts_sem);
-       if (copy_to_user(name, utsname(), sizeof(*name)))
-               err = -EFAULT;
-       up_read(&uts_sem);
-       if (!err)
-               err = override_machine(name->machine);
-       return err;
-}
-
-int sys_olduname(struct oldold_utsname __user *name)
-{
-       int error;
-
-       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
-               return -EFAULT;
-  
-       down_read(&uts_sem);
-       error = __copy_to_user(&name->sysname, &utsname()->sysname,
-                              __OLD_UTS_LEN);
-       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->release, &utsname()->release,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->release + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->version, &utsname()->version,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->version + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->machine, &utsname()->machine,
-                               __OLD_UTS_LEN);
-       error |= override_machine(name->machine);
-       up_read(&uts_sem);
-
-       return error? -EFAULT: 0;
-}
-
 long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
                      u32 len_high, u32 len_low)
 {
index 6f8ebe1..072b948 100644 (file)
@@ -553,7 +553,7 @@ static ssize_t mpc52xx_wdt_write(struct file *file, const char __user *data,
        return 0;
 }
 
-static struct watchdog_info mpc5200_wdt_info = {
+static const struct watchdog_info mpc5200_wdt_info = {
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity       = WDT_IDENTITY,
 };
index 01a0802..104f200 100644 (file)
@@ -35,7 +35,8 @@
 
 extern long psw32_user_bits;
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "s390\0\0\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index dd2d913..fef9b33 100644 (file)
@@ -489,9 +489,6 @@ struct user_regs_struct
  * These are defined as per linux/ptrace.h, which see.
  */
 #define arch_has_single_step() (1)
-struct task_struct;
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
 extern void show_regs(struct pt_regs * regs);
 
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
index c666bfe..9b04b11 100644 (file)
@@ -321,11 +321,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
 #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION    0x40
 #define QDIO_ERROR_SLSB_STATE                  0x80
 
-/* for qdio_initialize */
-#define QDIO_INBOUND_0COPY_SBALS               0x01
-#define QDIO_OUTBOUND_0COPY_SBALS              0x02
-#define QDIO_USE_OUTBOUND_PCIS                 0x04
-
 /* for qdio_cleanup */
 #define QDIO_FLAG_CLEANUP_USING_CLEAR          0x01
 #define QDIO_FLAG_CLEANUP_USING_HALT           0x02
@@ -344,7 +339,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
  * @input_handler: handler to be called for input queues
  * @output_handler: handler to be called for output queues
  * @int_parm: interruption parameter
- * @flags: initialization flags
  * @input_sbal_addr_array:  address of no_input_qs * 128 pointers
  * @output_sbal_addr_array: address of no_output_qs * 128 pointers
  */
@@ -361,7 +355,6 @@ struct qdio_initialize {
        qdio_handler_t *input_handler;
        qdio_handler_t *output_handler;
        unsigned long int_parm;
-       unsigned long flags;
        void **input_sbal_addr_array;
        void **output_sbal_addr_array;
 };
index 6e9f049..5f00751 100644 (file)
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_MMAP
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index 30de2d0..672ce52 100644 (file)
@@ -547,7 +547,7 @@ sys32_setdomainname_wrapper:
        .globl  sys32_newuname_wrapper
 sys32_newuname_wrapper:
        llgtr   %r2,%r2                 # struct new_utsname *
-       jg      sys_s390_newuname       # branch to system call
+       jg      sys_newuname            # branch to system call
 
        .globl  compat_sys_adjtimex_wrapper
 compat_sys_adjtimex_wrapper:
index e1e5e76..eb15c12 100644 (file)
@@ -24,17 +24,13 @@ int __cpuinit start_secondary(void *cpuvoid);
 void __init startup_init(void);
 void die(const char * str, struct pt_regs * regs, long err);
 
-struct new_utsname;
-struct mmap_arg_struct;
+struct s390_mmap_arg_struct;
 struct fadvise64_64_args;
 struct old_sigaction;
-struct sel_arg_struct;
 
-long sys_mmap2(struct mmap_arg_struct __user  *arg);
-long sys_s390_old_mmap(struct mmap_arg_struct __user *arg);
-long sys_ipc(uint call, int first, unsigned long second,
+long sys_mmap2(struct s390_mmap_arg_struct __user  *arg);
+long sys_s390_ipc(uint call, int first, unsigned long second,
             unsigned long third, void __user *ptr);
-long sys_s390_newuname(struct new_utsname __user *name);
 long sys_s390_personality(unsigned long personality);
 long sys_s390_fadvise64(int fd, u32 offset_high, u32 offset_low,
                    size_t len, int advice);
index 8b10127..29f65bc 100644 (file)
@@ -1020,7 +1020,9 @@ out:
        return rc;
 }
 
-static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf,
+static ssize_t __ref rescan_store(struct sysdev_class *class,
+                                 struct sysdev_class_attribute *attr,
+                                 const char *buf,
                                  size_t count)
 {
        int rc;
@@ -1031,7 +1033,9 @@ static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf,
 static SYSDEV_CLASS_ATTR(rescan, 0200, NULL, rescan_store);
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static ssize_t dispatching_show(struct sysdev_class *class, char *buf)
+static ssize_t dispatching_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        ssize_t count;
 
@@ -1041,7 +1045,9 @@ static ssize_t dispatching_show(struct sysdev_class *class, char *buf)
        return count;
 }
 
-static ssize_t dispatching_store(struct sysdev_class *dev, const char *buf,
+static ssize_t dispatching_store(struct sysdev_class *dev,
+                                struct sysdev_class_attribute *attr,
+                                const char *buf,
                                 size_t count)
 {
        int val, rc;
index 86a74c9..7b6b0f8 100644 (file)
 #include "entry.h"
 
 /*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux for S/390 isn't able to handle more than 5
- * system call parameters, so these system calls used a memory
- * block for parameter passing..
+ * Perform the mmap() system call. Linux for S/390 isn't able to handle more
+ * than 5 system call parameters, so this system call uses a memory block
+ * for parameter passing.
  */
 
-struct mmap_arg_struct {
+struct s390_mmap_arg_struct {
        unsigned long addr;
        unsigned long len;
        unsigned long prot;
@@ -48,9 +47,9 @@ struct mmap_arg_struct {
        unsigned long offset;
 };
 
-SYSCALL_DEFINE1(mmap2, struct mmap_arg_struct __user *, arg)
+SYSCALL_DEFINE1(mmap2, struct s390_mmap_arg_struct __user *, arg)
 {
-       struct mmap_arg_struct a;
+       struct s390_mmap_arg_struct a;
        int error = -EFAULT;
 
        if (copy_from_user(&a, arg, sizeof(a)))
@@ -60,29 +59,12 @@ out:
        return error;
 }
 
-SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct __user *, arg)
-{
-       struct mmap_arg_struct a;
-       long error = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       error = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
  * This is really horribly ugly.
  */
-SYSCALL_DEFINE5(ipc, uint, call, int, first, unsigned long, second,
+SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
                unsigned long, third, void __user *, ptr)
 {
         struct ipc_kludge tmp;
@@ -149,17 +131,6 @@ SYSCALL_DEFINE5(ipc, uint, call, int, first, unsigned long, second,
 }
 
 #ifdef CONFIG_64BIT
-SYSCALL_DEFINE1(s390_newuname, struct new_utsname __user *, name)
-{
-       int ret = sys_newuname(name);
-
-       if (personality(current->personality) == PER_LINUX32 && !ret) {
-               ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
-               if (ret) ret = -EFAULT;
-       }
-       return ret;
-}
-
 SYSCALL_DEFINE1(s390_personality, unsigned long, personality)
 {
        int ret;
index 30eca07..201ce6b 100644 (file)
@@ -98,7 +98,7 @@ SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
 SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
 SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
 SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper)   /* old readdir syscall */
-SYSCALL(sys_s390_old_mmap,sys_s390_old_mmap,old32_mmap_wrapper)        /* 90 */
+SYSCALL(sys_old_mmap,sys_old_mmap,old32_mmap_wrapper)          /* 90 */
 SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
 SYSCALL(sys_truncate,sys_truncate,sys32_truncate_wrapper)
 SYSCALL(sys_ftruncate,sys_ftruncate,sys32_ftruncate_wrapper)
@@ -125,12 +125,12 @@ NI_SYSCALL                                                        /* vm86old for i386 */
 SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper)
 SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper)         /* 115 */
 SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
-SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper)
+SYSCALL(sys_s390_ipc,sys_s390_ipc,sys32_ipc_wrapper)
 SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
 SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
 SYSCALL(sys_clone,sys_clone,sys_clone_wrapper)                 /* 120 */
 SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
-SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper)
+SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper)
 NI_SYSCALL                                                     /* modify_ldt for i386 */
 SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
 SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper)      /* 125 */
index a8f93f1..aa2483e 100644 (file)
@@ -73,15 +73,15 @@ unsigned long long monotonic_clock(void)
 }
 EXPORT_SYMBOL(monotonic_clock);
 
-void tod_to_timeval(__u64 todval, struct timespec *xtime)
+void tod_to_timeval(__u64 todval, struct timespec *xt)
 {
        unsigned long long sec;
 
        sec = todval >> 12;
        do_div(sec, 1000000);
-       xtime->tv_sec = sec;
+       xt->tv_sec = sec;
        todval -= (sec * 1000000) << 12;
-       xtime->tv_nsec = ((todval * 1000) >> 12);
+       xt->tv_nsec = ((todval * 1000) >> 12);
 }
 EXPORT_SYMBOL(tod_to_timeval);
 
@@ -216,8 +216,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
        ++vdso_data->tb_update_count;
        smp_wmb();
        vdso_data->xtime_tod_stamp = clock->cycle_last;
-       vdso_data->xtime_clock_sec = xtime.tv_sec;
-       vdso_data->xtime_clock_nsec = xtime.tv_nsec;
+       vdso_data->xtime_clock_sec = wall_time->tv_sec;
+       vdso_data->xtime_clock_nsec = wall_time->tv_nsec;
        vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
        vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
        smp_wmb();
@@ -1116,14 +1116,18 @@ static struct sys_device etr_port1_dev = {
 /*
  * ETR class attributes
  */
-static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+static ssize_t etr_stepping_port_show(struct sysdev_class *class,
+                                       struct sysdev_class_attribute *attr,
+                                       char *buf)
 {
        return sprintf(buf, "%i\n", etr_port0.esw.p);
 }
 
 static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
 
-static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class,
+                                       struct sysdev_class_attribute *attr,
+                                       char *buf)
 {
        char *mode_str;
 
@@ -1584,7 +1588,9 @@ static struct sysdev_class stp_sysclass = {
        .name   = "stp",
 };
 
-static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_ctn_id_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online)
                return -ENODATA;
@@ -1594,7 +1600,9 @@ static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL);
 
-static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_ctn_type_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online)
                return -ENODATA;
@@ -1603,7 +1611,9 @@ static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL);
 
-static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_dst_offset_show(struct sysdev_class *class,
+                                  struct sysdev_class_attribute *attr,
+                                  char *buf)
 {
        if (!stp_online || !(stp_info.vbits & 0x2000))
                return -ENODATA;
@@ -1612,7 +1622,9 @@ static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL);
 
-static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_leap_seconds_show(struct sysdev_class *class,
+                                       struct sysdev_class_attribute *attr,
+                                       char *buf)
 {
        if (!stp_online || !(stp_info.vbits & 0x8000))
                return -ENODATA;
@@ -1621,7 +1633,9 @@ static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL);
 
-static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_stratum_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online)
                return -ENODATA;
@@ -1630,7 +1644,9 @@ static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(stratum, 0400, stp_stratum_show, NULL);
 
-static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_time_offset_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online || !(stp_info.vbits & 0x0800))
                return -ENODATA;
@@ -1639,7 +1655,9 @@ static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(time_offset, 0400, stp_time_offset_show, NULL);
 
-static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_time_zone_offset_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online || !(stp_info.vbits & 0x4000))
                return -ENODATA;
@@ -1649,7 +1667,9 @@ static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf)
 static SYSDEV_CLASS_ATTR(time_zone_offset, 0400,
                         stp_time_zone_offset_show, NULL);
 
-static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_timing_mode_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online)
                return -ENODATA;
@@ -1658,7 +1678,9 @@ static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL);
 
-static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_timing_state_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        if (!stp_online)
                return -ENODATA;
@@ -1667,12 +1689,15 @@ static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf)
 
 static SYSDEV_CLASS_ATTR(timing_state, 0400, stp_timing_state_show, NULL);
 
-static ssize_t stp_online_show(struct sysdev_class *class, char *buf)
+static ssize_t stp_online_show(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
+                               char *buf)
 {
        return sprintf(buf, "%i\n", stp_online);
 }
 
 static ssize_t stp_online_store(struct sysdev_class *class,
+                               struct sysdev_class_attribute *attr,
                                const char *buf, size_t count)
 {
        unsigned int value;
index cd54a1c..761ab8b 100644 (file)
@@ -2,7 +2,8 @@
 # Makefile for s390-specific library files..
 #
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o usercopy.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+obj-y += usercopy.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index 76a3637..f16bd04 100644 (file)
@@ -374,7 +374,7 @@ static struct ctl_table cmm_dir_table[] = {
 #ifdef CONFIG_CMM_IUCV
 #define SMSG_PREFIX "CMM"
 static void
-cmm_smsg_target(char *from, char *msg)
+cmm_smsg_target(const char *from, char *msg)
 {
        long nr, seconds;
 
index d40e691..e89dc9b 100644 (file)
@@ -90,8 +90,7 @@ extern int read_tsk_short(struct task_struct *, unsigned long,
                         unsigned short *);
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_SCORE_PTRACE_H */
index 05cef50..8d90564 100644 (file)
@@ -183,6 +183,9 @@ config DMA_COHERENT
 config DMA_NONCOHERENT
        def_bool !DMA_COHERENT
 
+config NEED_DMA_MAP_STATE
+       def_bool DMA_NONCOHERENT
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index 1042f7f..8bd952f 100644 (file)
@@ -83,25 +83,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
  */
 #define PCI_DMA_BUS_IS_PHYS    (dma_ops->is_phys)
 
-/* pci_unmap_{single,page} being a nop depends upon the
- * configuration.
- */
-#ifdef CONFIG_DMA_NONCOHERENT
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)         ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
-#else
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-#endif
-
 #ifdef CONFIG_PCI
 /*
  * None of the SH PCI controllers support MWI, it is always treated as a
index e11b14e..2168fde 100644 (file)
@@ -123,8 +123,6 @@ extern void show_regs(struct pt_regs *);
 struct task_struct;
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
 
 struct perf_event;
 struct perf_sample_data;
index c1e2b8d..507725a 100644 (file)
@@ -3,17 +3,12 @@
 
 #ifdef __KERNEL__
 
-struct old_utsname;
-
 asmlinkage int old_mmap(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
                        int fd, unsigned long off);
 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
                          unsigned long prot, unsigned long flags,
                          unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_ipc(uint call, int first, int second,
-                      int third, void __user *ptr, long fifth);
-asmlinkage int sys_uname(struct old_utsname __user *name);
 
 #ifdef CONFIG_SUPERH32
 # include "syscalls_32.h"
index 365744b..0e7f0fc 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index 25de158..0580c33 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index fc065f9..14726ee 100644 (file)
@@ -326,7 +326,7 @@ static struct attribute *sq_sysfs_attrs[] = {
        NULL,
 };
 
-static struct sysfs_ops sq_sysfs_ops = {
+static const struct sysfs_ops sq_sysfs_ops = {
        .show   = sq_sysfs_show,
        .store  = sq_sysfs_store,
 };
index 71399cd..81f5837 100644 (file)
@@ -53,110 +53,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc(uint call, int first, int second,
-                      int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMTIMEDOP)
-               switch (call) {
-               case SEMOP:
-                       return sys_semtimedop(first,
-                                             (struct sembuf __user *)ptr,
-                                             second, NULL);
-               case SEMTIMEDOP:
-                       return sys_semtimedop(first,
-                               (struct sembuf __user *)ptr, second,
-                               (const struct timespec __user *)fifth);
-               case SEMGET:
-                       return sys_semget (first, second, third);
-               case SEMCTL: {
-                       union semun fourth;
-                       if (!ptr)
-                               return -EINVAL;
-                       if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                               return -EFAULT;
-                       return sys_semctl (first, second, third, fourth);
-                       }
-               default:
-                       return -EINVAL;
-               }
-
-       if (call <= MSGCTL)
-               switch (call) {
-               case MSGSND:
-                       return sys_msgsnd (first, (struct msgbuf __user *) ptr,
-                                         second, third);
-               case MSGRCV:
-                       switch (version) {
-                       case 0:
-                       {
-                               struct ipc_kludge tmp;
-
-                               if (!ptr)
-                                       return -EINVAL;
-
-                               if (copy_from_user(&tmp,
-                                       (struct ipc_kludge __user *) ptr,
-                                                  sizeof (tmp)))
-                                       return -EFAULT;
-
-                               return sys_msgrcv (first, tmp.msgp, second,
-                                                  tmp.msgtyp, third);
-                       }
-                       default:
-                               return sys_msgrcv (first,
-                                                  (struct msgbuf __user *) ptr,
-                                                  second, fifth, third);
-                       }
-               case MSGGET:
-                       return sys_msgget ((key_t) first, second);
-               case MSGCTL:
-                       return sys_msgctl (first, second,
-                                          (struct msqid_ds __user *) ptr);
-               default:
-                       return -EINVAL;
-               }
-       if (call <= SHMCTL)
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       default: {
-                               ulong raddr;
-                               ret = do_shmat (first, (char __user *) ptr,
-                                                second, &raddr);
-                               if (ret)
-                                       return ret;
-                               return put_user (raddr, (ulong __user *) third);
-                       }
-                       case 1: /* iBCS2 emulator entry point */
-                               if (!segment_eq(get_fs(), get_ds()))
-                                       return -EINVAL;
-                               return do_shmat (first, (char __user *) ptr,
-                                                 second, (ulong *) third);
-                       }
-               case SHMDT:
-                       return sys_shmdt ((char __user *)ptr);
-               case SHMGET:
-                       return sys_shmget (first, second, third);
-               case SHMCTL:
-                       return sys_shmctl (first, second,
-                                          (struct shmid_ds __user *) ptr);
-               default:
-                       return -EINVAL;
-               }
-
-       return -EINVAL;
-}
-
 /* sys_cacheflush -- flush (part of) the processor cache.  */
 asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op)
 {
@@ -197,14 +93,3 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op)
        up_read(&current->mm->mmap_sem);
        return 0;
 }
-
-asmlinkage int sys_uname(struct old_utsname __user *name)
-{
-       int err;
-       if (!name)
-               return -EFAULT;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof(*name));
-       up_read(&uts_sem);
-       return err?-EFAULT:0;
-}
index 4097f6a..6db5136 100644 (file)
@@ -127,6 +127,9 @@ config ZONE_DMA
        bool
        default y if SPARC32
 
+config NEED_DMA_MAP_STATE
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y if SPARC32
index 0e70625..5016f76 100644 (file)
@@ -5,7 +5,8 @@
  */
 #include <linux/types.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "sparc\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 5a8c308..4b4a0c0 100644 (file)
@@ -8,7 +8,6 @@
 #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);
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
@@ -62,4 +61,17 @@ static inline int dma_get_cache_alignment(void)
        return (1 << INTERNODE_CACHE_SHIFT);
 }
 
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               if (!dev->dma_mask || !dma_supported(dev, mask))
+                       return -EINVAL;
+               *dev->dma_mask = mask;
+               return 0;
+       }
+#endif
+       return -EINVAL;
+}
+
 #endif
index e769f66..332ac9a 100644 (file)
@@ -32,20 +32,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
 
 struct pci_dev;
 
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index b0576df..5312782 100644 (file)
@@ -32,20 +32,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
  */
 #define PCI_DMA_BUS_IS_PHYS    (0)
 
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
-       dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
-       __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                 \
-       ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
-       (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                   \
-       ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
-       (((PTR)->LEN_NAME) = (VAL))
-
 /* PCI IOMMU mapping bypass support. */
 
 /* PCI 64-bit addressing works for all slots on all controller
index cb4b9bf..d0b3b01 100644 (file)
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#ifndef __32bit_syscall_numbers__
+#ifdef __32bit_syscall_numbers__
+#define __ARCH_WANT_SYS_IPC
+#else
 #define __ARCH_WANT_COMPAT_SYS_TIME
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #endif
index 5fad949..8414549 100644 (file)
@@ -862,13 +862,3 @@ int dma_supported(struct device *dev, u64 device_mask)
        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 -EINVAL;
-}
-EXPORT_SYMBOL(dma_set_mask);
index 3c8c44f..84e5386 100644 (file)
@@ -676,17 +676,6 @@ int dma_supported(struct device *dev, u64 mask)
 }
 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);
-
-
 #ifdef CONFIG_PROC_FS
 
 static int sparc_io_proc_show(struct seq_file *m, void *v)
index 3a82e65..ee995b7 100644 (file)
@@ -98,119 +98,6 @@ out:
        return error;
 }
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth)
-{
-       int version, err;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
-                       goto out;
-               case SEMTIMEDOP:
-                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, (const struct timespec __user *) fifth);
-                       goto out;
-               case SEMGET:
-                       err = sys_semget (first, second, third);
-                       goto out;
-               case SEMCTL: {
-                       union semun fourth;
-                       err = -EINVAL;
-                       if (!ptr)
-                               goto out;
-                       err = -EFAULT;
-                       if (get_user(fourth.__pad,
-                                    (void __user * __user *)ptr))
-                               goto out;
-                       err = sys_semctl (first, second, third, fourth);
-                       goto out;
-                       }
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       if (call <= MSGCTL) 
-               switch (call) {
-               case MSGSND:
-                       err = sys_msgsnd (first, (struct msgbuf __user *) ptr, 
-                                         second, third);
-                       goto out;
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               err = -EINVAL;
-                               if (!ptr)
-                                       goto out;
-                               err = -EFAULT;
-                               if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr, sizeof (tmp)))
-                                       goto out;
-                               err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
-                               goto out;
-                               }
-                       case 1: default:
-                               err = sys_msgrcv (first,
-                                                 (struct msgbuf __user *) ptr,
-                                                 second, fifth, third);
-                               goto out;
-                       }
-               case MSGGET:
-                       err = sys_msgget ((key_t) first, second);
-                       goto out;
-               case MSGCTL:
-                       err = sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
-                       goto out;
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       if (call <= SHMCTL) 
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       case 0: default: {
-                               ulong raddr;
-                               err = do_shmat (first, (char __user *) ptr, second, &raddr);
-                               if (err)
-                                       goto out;
-                               err = -EFAULT;
-                               if (put_user (raddr, (ulong __user *) third))
-                                       goto out;
-                               err = 0;
-                               goto out;
-                               }
-                       case 1: /* iBCS2 emulator entry point */
-                               err = -EINVAL;
-                               goto out;
-                       }
-               case SHMDT: 
-                       err = sys_shmdt ((char __user *)ptr);
-                       goto out;
-               case SHMGET:
-                       err = sys_shmget (first, second, third);
-                       goto out;
-               case SHMCTL:
-                       err = sys_shmctl (first, second, (struct shmid_ds __user *) ptr);
-                       goto out;
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       else
-               err = -ENOSYS;
-out:
-       return err;
-}
-
 int sparc_mmap_check(unsigned long addr, unsigned long len)
 {
        if (ARCH_SUN4C &&
index cb1bef6..3d435c4 100644 (file)
@@ -426,7 +426,7 @@ out:
  * This is really horribly ugly.
  */
 
-SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
+SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second,
                unsigned long, third, void __user *, ptr, long, fifth)
 {
        long err;
@@ -510,17 +510,6 @@ out:
        return err;
 }
 
-SYSCALL_DEFINE1(sparc64_newuname, struct new_utsname __user *, name)
-{
-       int ret = sys_newuname(name);
-       
-       if (current->personality == PER_LINUX32 && !ret) {
-               ret = (copy_to_user(name->machine, "sparc\0\0", 8)
-                      ? -EFAULT : 0);
-       }
-       return ret;
-}
-
 SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality)
 {
        int ret;
index 68312fe..118759c 100644 (file)
@@ -6,15 +6,12 @@
 #include <asm/utrap.h>
 #include <asm/signal.h>
 
-struct new_utsname;
-
 extern asmlinkage unsigned long sys_getpagesize(void);
 extern asmlinkage long sparc_pipe(struct pt_regs *regs);
-extern asmlinkage long sys_ipc(unsigned int call, int first,
+extern asmlinkage long sys_sparc_ipc(unsigned int call, int first,
                               unsigned long second,
                               unsigned long third,
                               void __user *ptr, long fifth);
-extern asmlinkage long sparc64_newuname(struct new_utsname __user *name);
 extern asmlinkage long sparc64_personality(unsigned long personality);
 extern asmlinkage long sys64_munmap(unsigned long addr, size_t len);
 extern asmlinkage unsigned long sys64_mremap(unsigned long addr,
index 1761425..9db058d 100644 (file)
@@ -55,7 +55,7 @@ sys_call_table32:
 /*170*/        .word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
        .word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/        .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
-       .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sys_sparc64_newuname
+       .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sys_newuname
 /*190*/        .word sys32_init_module, sys_sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl
        .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/        .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
@@ -130,13 +130,13 @@ sys_call_table:
 /*170*/        .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
        .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/        .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall
-       .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_sparc64_newuname
+       .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
 /*190*/        .word sys_init_module, sys_sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
        .word sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/        .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
        .word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
 /*210*/        .word sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
-       .word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex
+       .word sys_sparc_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex
 /*220*/        .word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
        .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
 /*230*/        .word sys_select, sys_nis_syscall, sys_splice, sys_stime, sys_statfs64
index 378de4b..b948c14 100644 (file)
@@ -103,14 +103,6 @@ dma_get_cache_alignment(void)
        return(0);
 }
 
-static inline void
-dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-{
-       BUG();
-}
-
 static inline void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
               enum dma_data_direction direction)
index 6c88990..2cd899f 100644 (file)
@@ -16,6 +16,8 @@ struct pt_regs {
        struct uml_pt_regs regs;
 };
 
+#define arch_has_single_step() (1)
+
 #define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS }
 
 #define PT_REGS_IP(r) UPT_IP(&(r)->regs)
index 8e3d69e..4845099 100644 (file)
 #endif
 #include "skas_ptrace.h"
 
-static inline void set_singlestepping(struct task_struct *child, int on)
+
+
+void user_enable_single_step(struct task_struct *child)
 {
-       if (on)
-               child->ptrace |= PT_DTRACE;
-       else
-               child->ptrace &= ~PT_DTRACE;
+       child->ptrace |= PT_DTRACE;
        child->thread.singlestep_syscall = 0;
 
 #ifdef SUBARCH_SET_SINGLESTEPPING
-       SUBARCH_SET_SINGLESTEPPING(child, on);
+       SUBARCH_SET_SINGLESTEPPING(child, 1);
+#endif
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       child->ptrace &= ~PT_DTRACE;
+       child->thread.singlestep_syscall = 0;
+
+#ifdef SUBARCH_SET_SINGLESTEPPING
+       SUBARCH_SET_SINGLESTEPPING(child, 0);
 #endif
 }
 
@@ -30,7 +39,7 @@ static inline void set_singlestepping(struct task_struct *child, int on)
  */
 void ptrace_disable(struct task_struct *child)
 {
-       set_singlestepping(child,0);
+       user_disable_single_step(child);
 }
 
 extern int peek_user(struct task_struct * child, long addr, long data);
@@ -69,53 +78,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = -EIO;
                break;
 
-       /* continue and stop at next (return from) syscall */
-       case PTRACE_SYSCALL:
-       /* restart after signal. */
-       case PTRACE_CONT: {
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-
-               set_singlestepping(child, 0);
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-               break;
-       }
-
-/*
- * make the child exit.  Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
-       case PTRACE_KILL: {
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-
-               set_singlestepping(child, 0);
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
-               break;
-       }
-
-       case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               set_singlestepping(child, 1);
-               child->exit_code = data;
-               /* give it a chance to run. */
-               wake_up_process(child);
-               ret = 0;
-               break;
-       }
-
 #ifdef PTRACE_GETREGS
        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
index cccab85..4393173 100644 (file)
@@ -51,51 +51,6 @@ long old_mmap(unsigned long addr, unsigned long len,
        return err;
 }
 
-long sys_uname(struct old_utsname __user * name)
-{
-       long err;
-       if (!name)
-               return -EFAULT;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof (*name));
-       up_read(&uts_sem);
-       return err?-EFAULT:0;
-}
-
-long sys_olduname(struct oldold_utsname __user * name)
-{
-       long error;
-
-       if (!name)
-               return -EFAULT;
-       if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
-               return -EFAULT;
-
-       down_read(&uts_sem);
-
-       error = __copy_to_user(&name->sysname, &utsname()->sysname,
-                              __OLD_UTS_LEN);
-       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->release, &utsname()->release,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->release + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->version, &utsname()->version,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->version + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->machine, &utsname()->machine,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
-
-       up_read(&uts_sem);
-
-       error = error ? -EFAULT : 0;
-
-       return error;
-}
-
 int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 {
        mm_segment_t fs;
index e778767..05cb796 100644 (file)
@@ -13,8 +13,6 @@ typedef long syscall_handler_t(struct pt_regs);
  */
 extern syscall_handler_t sys_rt_sigaction;
 
-extern syscall_handler_t old_mmap_i386;
-
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
index c6260dd..de27407 100644 (file)
@@ -7,7 +7,7 @@
 #define sys_vm86old sys_ni_syscall
 #define sys_vm86 sys_ni_syscall
 
-#define old_mmap old_mmap_i386
+#define old_mmap sys_old_mmap
 
 #define ptregs_fork sys_fork
 #define ptregs_execve sys_execve
index 857ca0b..70ca357 100644 (file)
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-extern int old_mmap(unsigned long addr, unsigned long len,
-                   unsigned long prot, unsigned long flags,
-                   unsigned long fd, unsigned long offset);
-
-long old_mmap_i386(struct mmap_arg_struct __user *arg)
-{
-       struct mmap_arg_struct a;
-       int err = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
- out:
-       return err;
-}
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set __user *inp;
-       fd_set __user *outp;
-       fd_set __user *exp;
-       struct timeval __user *tvp;
-};
-
-long old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
 /*
  * The prototype on i386 is:
  *
@@ -85,92 +34,6 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
        return ret;
 }
 
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-long sys_ipc (uint call, int first, int second,
-            int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *) ptr,
-                                     second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *) ptr,
-                                     second,
-                                     (const struct timespec __user *) fifth);
-       case SEMGET:
-               return sys_semget (first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd (first, (struct msgbuf *) ptr,
-                                  second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge *) ptr,
-                                          sizeof (tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-               }
-               default:
-                       panic("msgrcv with version != 0");
-                       return sys_msgrcv (first,
-                                          (struct msgbuf *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget ((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl (first, second, (struct msqid_ds *) ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = do_shmat (first, (char *) ptr, second, &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user (raddr, (ulong *) third);
-               }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               return -EINVAL;
-                       return do_shmat (first, (char *) ptr, second, (ulong *) third);
-               }
-       case SHMDT:
-               return sys_shmdt ((char *)ptr);
-       case SHMGET:
-               return sys_shmget (first, second, third);
-       case SHMCTL:
-               return sys_shmctl (first, second,
-                                  (struct shmid_ds *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
-
 long sys_sigaction(int sig, const struct old_sigaction __user *act,
                         struct old_sigaction __user *oact)
 {
index dd21d69..47d469e 100644 (file)
 
 /* On UML we call it this way ("old" means it's not mmap2) */
 #define sys_mmap old_mmap
-/*
- * On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
- * See arch/x86_64/kernel/sys_x86_64.c
- */
-#define sys_uname sys_uname64
 
 #define stub_clone sys_clone
 #define stub_fork sys_fork
index f1199fd..f3d82bb 100644 (file)
 #include "asm/uaccess.h"
 #include "os.h"
 
-asmlinkage long sys_uname64(struct new_utsname __user * name)
-{
-       int err;
-
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof (*name));
-       up_read(&uts_sem);
-
-       if (personality(current->personality) == PER_LINUX32)
-               err |= copy_to_user(&name->machine, "i686", 5);
-
-       return err ? -EFAULT : 0;
-}
-
 long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
 {
        unsigned long *ptr = addr, tmp;
index e984403..93936de 100644 (file)
@@ -102,6 +102,9 @@ config ZONE_DMA
 config SBUS
        bool
 
+config NEED_DMA_MAP_STATE
+       def_bool (X86_64 || DMAR || DMA_API_DEBUG)
+
 config GENERIC_ISA_DMA
        def_bool y
 
index 53147ad..59b4556 100644 (file)
@@ -563,7 +563,7 @@ ia32_sys_call_table:
        .quad quiet_ni_syscall                  /* old mpx syscall holder */
        .quad sys_setpgid
        .quad quiet_ni_syscall                  /* old ulimit syscall holder */
-       .quad sys32_olduname
+       .quad sys_olduname
        .quad sys_umask         /* 60 */
        .quad sys_chroot
        .quad compat_sys_ustat
@@ -586,7 +586,7 @@ ia32_sys_call_table:
        .quad compat_sys_settimeofday
        .quad sys_getgroups16   /* 80 */
        .quad sys_setgroups16
-       .quad sys32_old_select
+       .quad compat_sys_old_select
        .quad sys_symlink
        .quad sys_lstat
        .quad sys_readlink              /* 85 */
@@ -613,7 +613,7 @@ ia32_sys_call_table:
        .quad compat_sys_newstat
        .quad compat_sys_newlstat
        .quad compat_sys_newfstat
-       .quad sys32_uname
+       .quad sys_uname
        .quad stub32_iopl               /* 110 */
        .quad sys_vhangup
        .quad quiet_ni_syscall  /* old "idle" system call */
index 422572c..74c3543 100644 (file)
@@ -143,7 +143,7 @@ asmlinkage long sys32_fstatat(unsigned int dfd, char __user *filename,
  * block for parameter passing..
  */
 
-struct mmap_arg_struct {
+struct mmap_arg_struct32 {
        unsigned int addr;
        unsigned int len;
        unsigned int prot;
@@ -152,9 +152,9 @@ struct mmap_arg_struct {
        unsigned int offset;
 };
 
-asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg)
+asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg)
 {
-       struct mmap_arg_struct a;
+       struct mmap_arg_struct32 a;
 
        if (copy_from_user(&a, arg, sizeof(a)))
                return -EFAULT;
@@ -332,24 +332,6 @@ asmlinkage long sys32_alarm(unsigned int seconds)
        return alarm_setitimer(seconds);
 }
 
-struct sel_arg_struct {
-       unsigned int n;
-       unsigned int inp;
-       unsigned int outp;
-       unsigned int exp;
-       unsigned int tvp;
-};
-
-asmlinkage long sys32_old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
-                                compat_ptr(a.exp), compat_ptr(a.tvp));
-}
-
 asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
                              int options)
 {
@@ -466,58 +448,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
        return ret;
 }
 
-asmlinkage long sys32_olduname(struct oldold_utsname __user *name)
-{
-       char *arch = "x86_64";
-       int err;
-
-       if (!name)
-               return -EFAULT;
-       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
-               return -EFAULT;
-
-       down_read(&uts_sem);
-
-       err = __copy_to_user(&name->sysname, &utsname()->sysname,
-                            __OLD_UTS_LEN);
-       err |= __put_user(0, name->sysname+__OLD_UTS_LEN);
-       err |= __copy_to_user(&name->nodename, &utsname()->nodename,
-                             __OLD_UTS_LEN);
-       err |= __put_user(0, name->nodename+__OLD_UTS_LEN);
-       err |= __copy_to_user(&name->release, &utsname()->release,
-                             __OLD_UTS_LEN);
-       err |= __put_user(0, name->release+__OLD_UTS_LEN);
-       err |= __copy_to_user(&name->version, &utsname()->version,
-                             __OLD_UTS_LEN);
-       err |= __put_user(0, name->version+__OLD_UTS_LEN);
-
-       if (personality(current->personality) == PER_LINUX32)
-               arch = "i686";
-
-       err |= __copy_to_user(&name->machine, arch, strlen(arch) + 1);
-
-       up_read(&uts_sem);
-
-       err = err ? -EFAULT : 0;
-
-       return err;
-}
-
-long sys32_uname(struct old_utsname __user *name)
-{
-       int err;
-
-       if (!name)
-               return -EFAULT;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof(*name));
-       up_read(&uts_sem);
-       if (personality(current->personality) == PER_LINUX32)
-               err |= copy_to_user(&name->machine, "i686", 5);
-
-       return err ? -EFAULT : 0;
-}
-
 asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
                             compat_uptr_t __user *envp, struct pt_regs *regs)
 {
index 9a9c7bd..306160e 100644 (file)
@@ -8,7 +8,8 @@
 #include <linux/sched.h>
 #include <asm/user32.h>
 
-#define COMPAT_USER_HZ 100
+#define COMPAT_USER_HZ         100
+#define COMPAT_UTS_MACHINE     "i686\0\0"
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 3e002ca..404a880 100644 (file)
@@ -97,34 +97,6 @@ extern void pci_iommu_alloc(void);
 
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_DMAR) || defined(CONFIG_DMA_API_DEBUG)
-
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)       \
-               dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)         \
-               __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)                  \
-               ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)         \
-               (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)                    \
-               ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)           \
-               (((PTR)->LEN_NAME) = (VAL))
-
-#else
-
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)       dma_addr_t ADDR_NAME[0];
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) unsigned LEN_NAME[0];
-#define pci_unmap_addr(PTR, ADDR_NAME)  sizeof((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
-               do { break; } while (pci_unmap_addr(PTR, ADDR_NAME))
-#define pci_unmap_len(PTR, LEN_NAME)            sizeof((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
-               do { break; } while (pci_unmap_len(PTR, LEN_NAME))
-
-#endif
-
 #endif  /* __KERNEL__ */
 
 #ifdef CONFIG_X86_64
index 2010280..69a686a 100644 (file)
@@ -274,14 +274,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
                return 0;
 }
 
-/*
- * These are defined as per linux/ptrace.h, which see.
- */
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *);
-extern void user_disable_single_step(struct task_struct *);
-
-extern void user_enable_block_step(struct task_struct *);
 #ifdef CONFIG_X86_DEBUGCTLMSR
 #define arch_has_block_step()  (1)
 #else
index d5f6904..3ad4217 100644 (file)
@@ -26,8 +26,8 @@ asmlinkage long sys32_lstat64(char __user *, struct stat64 __user *);
 asmlinkage long sys32_fstat64(unsigned int, struct stat64 __user *);
 asmlinkage long sys32_fstatat(unsigned int, char __user *,
                              struct stat64 __user *, int);
-struct mmap_arg_struct;
-asmlinkage long sys32_mmap(struct mmap_arg_struct __user *);
+struct mmap_arg_struct32;
+asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *);
 asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long);
 
 struct sigaction32;
@@ -40,8 +40,6 @@ asmlinkage long sys32_rt_sigprocmask(int, compat_sigset_t __user *,
                                     compat_sigset_t __user *, unsigned int);
 asmlinkage long sys32_alarm(unsigned int);
 
-struct sel_arg_struct;
-asmlinkage long sys32_old_select(struct sel_arg_struct __user *);
 asmlinkage long sys32_waitpid(compat_pid_t, unsigned int *, int);
 asmlinkage long sys32_sysfs(int, u32, u32);
 
@@ -56,11 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, char __user *, u32, u32, u32);
 asmlinkage long sys32_personality(unsigned long);
 asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
 
-struct oldold_utsname;
-struct old_utsname;
-asmlinkage long sys32_olduname(struct oldold_utsname __user *);
-long sys32_uname(struct old_utsname __user *);
-
 asmlinkage long sys32_execve(char __user *, compat_uptr_t __user *,
                             compat_uptr_t __user *, struct pt_regs *);
 asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
index 8868b94..5c044b4 100644 (file)
@@ -50,18 +50,6 @@ asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
                             struct old_sigaction __user *);
 unsigned long sys_sigreturn(struct pt_regs *);
 
-/* kernel/sys_i386_32.c */
-struct mmap_arg_struct;
-struct sel_arg_struct;
-struct oldold_utsname;
-struct old_utsname;
-
-asmlinkage int old_mmap(struct mmap_arg_struct __user *);
-asmlinkage int old_select(struct sel_arg_struct __user *);
-asmlinkage int sys_ipc(uint, int, int, int, void __user *, long);
-asmlinkage int sys_uname(struct old_utsname __user *);
-asmlinkage int sys_olduname(struct oldold_utsname __user *);
-
 /* kernel/vm86_32.c */
 int sys_vm86old(struct vm86_struct __user *, struct pt_regs *);
 int sys_vm86(unsigned long, unsigned long, struct pt_regs *);
@@ -73,11 +61,8 @@ int sys_vm86(unsigned long, unsigned long, struct pt_regs *);
 long sys_arch_prctl(int, unsigned long);
 
 /* kernel/sys_x86_64.c */
-struct new_utsname;
-
 asmlinkage long sys_mmap(unsigned long, unsigned long, unsigned long,
                         unsigned long, unsigned long, unsigned long);
-asmlinkage long sys_uname(struct new_utsname __user *);
 
 #endif /* CONFIG_X86_32 */
 #endif /* _ASM_X86_SYSCALLS_H */
index 3baf379..beb9b5f 100644 (file)
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_SGETMASK
 #define __ARCH_WANT_SYS_SIGNAL
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
+#define __ARCH_WANT_SYS_OLD_MMAP
+#define __ARCH_WANT_SYS_OLD_SELECT
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index 4843f7b..ff4307b 100644 (file)
@@ -146,7 +146,7 @@ __SYSCALL(__NR_wait4, sys_wait4)
 #define __NR_kill                              62
 __SYSCALL(__NR_kill, sys_kill)
 #define __NR_uname                             63
-__SYSCALL(__NR_uname, sys_uname)
+__SYSCALL(__NR_uname, sys_newuname)
 
 #define __NR_semget                            64
 __SYSCALL(__NR_semget, sys_semget)
@@ -680,6 +680,7 @@ __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_SYS_OLD_UNAME
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
index eddb1bd..b3eeb66 100644 (file)
@@ -903,7 +903,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
        .show   = show,
        .store  = store,
 };
index a8aacd4..28cba46 100644 (file)
@@ -2044,6 +2044,7 @@ static __init void mce_init_banks(void)
                struct mce_bank *b = &mce_banks[i];
                struct sysdev_attribute *a = &b->attr;
 
+               sysfs_attr_init(&a->attr);
                a->attr.name    = b->attrname;
                snprintf(b->attrname, ATTR_LEN, "bank%d", i);
 
index 83a3d1f..cda932c 100644 (file)
@@ -388,7 +388,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops threshold_ops = {
+static const struct sysfs_ops threshold_ops = {
        .show                   = show,
        .store                  = store,
 };
index dee1ff7..196552b 100644 (file)
 
 #include <asm/syscalls.h>
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-
-struct mmap_arg_struct {
-       unsigned long addr;
-       unsigned long len;
-       unsigned long prot;
-       unsigned long flags;
-       unsigned long fd;
-       unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
-{
-       struct mmap_arg_struct a;
-       int err = -EFAULT;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               goto out;
-
-       err = -EINVAL;
-       if (a.offset & ~PAGE_MASK)
-               goto out;
-
-       err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags,
-                       a.fd, a.offset >> PAGE_SHIFT);
-out:
-       return err;
-}
-
-
-struct sel_arg_struct {
-       unsigned long n;
-       fd_set __user *inp, *outp, *exp;
-       struct timeval __user *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct __user *arg)
-{
-       struct sel_arg_struct a;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-       /* sys_select() does the appropriate kernel locking */
-       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-asmlinkage int sys_ipc(uint call, int first, int second,
-                       int third, void __user *ptr, long fifth)
-{
-       int version, ret;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       switch (call) {
-       case SEMOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second, NULL);
-       case SEMTIMEDOP:
-               return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
-                                       (const struct timespec __user *)fifth);
-
-       case SEMGET:
-               return sys_semget(first, second, third);
-       case SEMCTL: {
-               union semun fourth;
-               if (!ptr)
-                       return -EINVAL;
-               if (get_user(fourth.__pad, (void __user * __user *) ptr))
-                       return -EFAULT;
-               return sys_semctl(first, second, third, fourth);
-       }
-
-       case MSGSND:
-               return sys_msgsnd(first, (struct msgbuf __user *) ptr,
-                                  second, third);
-       case MSGRCV:
-               switch (version) {
-               case 0: {
-                       struct ipc_kludge tmp;
-                       if (!ptr)
-                               return -EINVAL;
-
-                       if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr,
-                                          sizeof(tmp)))
-                               return -EFAULT;
-                       return sys_msgrcv(first, tmp.msgp, second,
-                                          tmp.msgtyp, third);
-               }
-               default:
-                       return sys_msgrcv(first,
-                                          (struct msgbuf __user *) ptr,
-                                          second, fifth, third);
-               }
-       case MSGGET:
-               return sys_msgget((key_t) first, second);
-       case MSGCTL:
-               return sys_msgctl(first, second, (struct msqid_ds __user *) ptr);
-
-       case SHMAT:
-               switch (version) {
-               default: {
-                       ulong raddr;
-                       ret = do_shmat(first, (char __user *) ptr, second, &raddr);
-                       if (ret)
-                               return ret;
-                       return put_user(raddr, (ulong __user *) third);
-               }
-               case 1: /* iBCS2 emulator entry point */
-                       if (!segment_eq(get_fs(), get_ds()))
-                               return -EINVAL;
-                       /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
-                       return do_shmat(first, (char __user *) ptr, second, (ulong *) third);
-               }
-       case SHMDT:
-               return sys_shmdt((char __user *)ptr);
-       case SHMGET:
-               return sys_shmget(first, second, third);
-       case SHMCTL:
-               return sys_shmctl(first, second,
-                                  (struct shmid_ds __user *) ptr);
-       default:
-               return -ENOSYS;
-       }
-}
-
-/*
- * Old cruft
- */
-asmlinkage int sys_uname(struct old_utsname __user *name)
-{
-       int err;
-       if (!name)
-               return -EFAULT;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof(*name));
-       up_read(&uts_sem);
-       return err? -EFAULT:0;
-}
-
-asmlinkage int sys_olduname(struct oldold_utsname __user *name)
-{
-       int error;
-
-       if (!name)
-               return -EFAULT;
-       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
-               return -EFAULT;
-
-       down_read(&uts_sem);
-
-       error = __copy_to_user(&name->sysname, &utsname()->sysname,
-                              __OLD_UTS_LEN);
-       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->release, &utsname()->release,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->release + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->version, &utsname()->version,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->version + __OLD_UTS_LEN);
-       error |= __copy_to_user(&name->machine, &utsname()->machine,
-                               __OLD_UTS_LEN);
-       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
-
-       up_read(&uts_sem);
-
-       error = error ? -EFAULT : 0;
-
-       return error;
-}
-
-
 /*
  * Do a system call from kernel instead of calling sys_execve so we
  * end up with proper pt_regs.
index 8aa2057..ff14a50 100644 (file)
@@ -209,15 +209,3 @@ bottomup:
 
        return addr;
 }
-
-
-SYSCALL_DEFINE1(uname, struct new_utsname __user *, name)
-{
-       int err;
-       down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof(*name));
-       up_read(&uts_sem);
-       if (personality(current->personality) == PER_LINUX32)
-               err |= copy_to_user(&name->machine, "i686", 5);
-       return err ? -EFAULT : 0;
-}
index 15228b5..8b37293 100644 (file)
@@ -81,7 +81,7 @@ ENTRY(sys_call_table)
        .long sys_settimeofday
        .long sys_getgroups16   /* 80 */
        .long sys_setgroups16
-       .long old_select
+       .long sys_old_select
        .long sys_symlink
        .long sys_lstat
        .long sys_readlink      /* 85 */
@@ -89,7 +89,7 @@ ENTRY(sys_call_table)
        .long sys_swapon
        .long sys_reboot
        .long sys_old_readdir
-       .long old_mmap          /* 90 */
+       .long sys_old_mmap      /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
index 66410ac..4609b0f 100644 (file)
@@ -56,14 +56,6 @@ struct pci_dev;
 
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
-/* pci_unmap_{page,single} is a no-op, so */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_ubnmap_len(PTR, LEN_NAME)          (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
 /* Map a range of PCI memory or I/O space for a device into user space */
 int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
                         enum pci_mmap_state mmap_state, int write_combine);
index 905e1e6..3c549f7 100644 (file)
@@ -113,6 +113,7 @@ struct pt_regs {
 
 #include <variant/core.h>
 
+# define arch_has_single_step()        (1)
 # define task_pt_regs(tsk) ((struct pt_regs*) \
   (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1)
 # define user_mode(regs) (((regs)->ps & 0x00000020)!=0)
index 9486882..9d4e1ce 100644 (file)
 #include <asm/elf.h>
 #include <asm/coprocessor.h>
 
+
+void user_enable_single_step(struct task_struct *child)
+{
+       child->ptrace |= PT_SINGLESTEP;
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       child->ptrace &= ~PT_SINGLESTEP;
+}
+
 /*
  * Called by kernel/ptrace.c when detaching to disable single stepping.
  */
@@ -268,51 +279,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_pokeusr(child, addr, data);
                break;
 
-       /* continue and stop at next (return from) syscall */
-
-       case PTRACE_SYSCALL:
-       case PTRACE_CONT: /* restart after signal. */
-       {
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL)
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               else
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->exit_code = data;
-               /* Make sure the single step bit is not set. */
-               child->ptrace &= ~PT_SINGLESTEP;
-               wake_up_process(child);
-               ret = 0;
-               break;
-       }
-
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               child->ptrace &= ~PT_SINGLESTEP;
-               wake_up_process(child);
-               break;
-
-       case PTRACE_SINGLESTEP:
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               child->ptrace |= PT_SINGLESTEP;
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
-               break;
-
        case PTRACE_GETREGS:
                ret = ptrace_getregs(child, (void __user *) data);
                break;
index e20fbde..62a5921 100644 (file)
@@ -78,7 +78,7 @@ config BLK_DEV_INTEGRITY
        Protection.  If in doubt, say N.
 
 config BLK_CGROUP
-       bool
+       tristate
        depends on CGROUPS
        default n
        ---help---
index b71abfb..fc71cf0 100644 (file)
@@ -23,6 +23,7 @@ config IOSCHED_DEADLINE
 
 config IOSCHED_CFQ
        tristate "CFQ I/O scheduler"
+       select BLK_CGROUP if CFQ_GROUP_IOSCHED
        default y
        ---help---
          The CFQ I/O scheduler tries to distribute bandwidth equally
@@ -35,7 +36,6 @@ config IOSCHED_CFQ
 config CFQ_GROUP_IOSCHED
        bool "CFQ Group Scheduling support"
        depends on IOSCHED_CFQ && CGROUPS
-       select BLK_CGROUP
        default n
        ---help---
          Enable group IO scheduling in CFQ.
index c85d74c..4b686ad 100644 (file)
@@ -23,6 +23,31 @@ static LIST_HEAD(blkio_list);
 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
 EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
+static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
+                                                 struct cgroup *);
+static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
+                             struct task_struct *, bool);
+static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
+                          struct cgroup *, struct task_struct *, bool);
+static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
+static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
+
+struct cgroup_subsys blkio_subsys = {
+       .name = "blkio",
+       .create = blkiocg_create,
+       .can_attach = blkiocg_can_attach,
+       .attach = blkiocg_attach,
+       .destroy = blkiocg_destroy,
+       .populate = blkiocg_populate,
+#ifdef CONFIG_BLK_CGROUP
+       /* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
+       .subsys_id = blkio_subsys_id,
+#endif
+       .use_id = 1,
+       .module = THIS_MODULE,
+};
+EXPORT_SYMBOL_GPL(blkio_subsys);
+
 struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
 {
        return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
@@ -253,7 +278,8 @@ remove_entry:
 done:
        free_css_id(&blkio_subsys, &blkcg->css);
        rcu_read_unlock();
-       kfree(blkcg);
+       if (blkcg != &blkio_root_cgroup)
+               kfree(blkcg);
 }
 
 static struct cgroup_subsys_state *
@@ -319,17 +345,6 @@ static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
        task_unlock(tsk);
 }
 
-struct cgroup_subsys blkio_subsys = {
-       .name = "blkio",
-       .create = blkiocg_create,
-       .can_attach = blkiocg_can_attach,
-       .attach = blkiocg_attach,
-       .destroy = blkiocg_destroy,
-       .populate = blkiocg_populate,
-       .subsys_id = blkio_subsys_id,
-       .use_id = 1,
-};
-
 void blkio_policy_register(struct blkio_policy_type *blkiop)
 {
        spin_lock(&blkio_list_lock);
@@ -345,3 +360,17 @@ void blkio_policy_unregister(struct blkio_policy_type *blkiop)
        spin_unlock(&blkio_list_lock);
 }
 EXPORT_SYMBOL_GPL(blkio_policy_unregister);
+
+static int __init init_cgroup_blkio(void)
+{
+       return cgroup_load_subsys(&blkio_subsys);
+}
+
+static void __exit exit_cgroup_blkio(void)
+{
+       cgroup_unload_subsys(&blkio_subsys);
+}
+
+module_init(init_cgroup_blkio);
+module_exit(exit_cgroup_blkio);
+MODULE_LICENSE("GPL");
index 84bf745..8ccc204 100644 (file)
 
 #include <linux/cgroup.h>
 
-#ifdef CONFIG_BLK_CGROUP
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
+
+#ifndef CONFIG_BLK_CGROUP
+/* When blk-cgroup is a module, its subsys_id isn't a compile-time constant */
+extern struct cgroup_subsys blkio_subsys;
+#define blkio_subsys_id blkio_subsys.subsys_id
+#endif
 
 struct blkio_cgroup {
        struct cgroup_subsys_state css;
@@ -91,7 +97,7 @@ static inline void blkiocg_update_blkio_group_dequeue_stats(
                        struct blkio_group *blkg, unsigned long dequeue) {}
 #endif
 
-#ifdef CONFIG_BLK_CGROUP
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
 extern struct blkio_cgroup blkio_root_cgroup;
 extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
 extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
index 15c6308..96e83c2 100644 (file)
@@ -278,7 +278,7 @@ static struct attribute *integrity_attrs[] = {
        NULL,
 };
 
-static struct sysfs_ops integrity_ops = {
+static const struct sysfs_ops integrity_ops = {
        .show   = &integrity_attr_show,
        .store  = &integrity_attr_store,
 };
index e854424..2ae2cb3 100644 (file)
@@ -450,7 +450,7 @@ static void blk_release_queue(struct kobject *kobj)
        kmem_cache_free(blk_requestq_cachep, q);
 }
 
-static struct sysfs_ops queue_sysfs_ops = {
+static const struct sysfs_ops queue_sysfs_ops = {
        .show   = queue_attr_show,
        .store  = queue_attr_store,
 };
index ee3a883..df75676 100644 (file)
@@ -892,7 +892,7 @@ elv_attr_store(struct kobject *kobj, struct attribute *attr,
        return error;
 }
 
-static struct sysfs_ops elv_sysfs_ops = {
+static const struct sysfs_ops elv_sysfs_ops = {
        .show   = elv_attr_show,
        .store  = elv_attr_store,
 };
index a206a12..743f244 100644 (file)
@@ -101,6 +101,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
        struct acpi_table_header *header = NULL;
        struct acpi_table_attr *attr = NULL;
 
+       sysfs_attr_init(&table_attr->attr.attr);
        if (table_header->signature[0] != '\0')
                memcpy(table_attr->name, table_header->signature,
                        ACPI_NAME_SIZE);
@@ -475,6 +476,7 @@ void acpi_irq_stats_init(void)
                        goto fail;
                strncpy(name, buffer, strlen(buffer) + 1);
 
+               sysfs_attr_init(&counter_attrs[i].attr);
                counter_attrs[i].attr.name = name;
                counter_attrs[i].attr.mode = 0644;
                counter_attrs[i].show = counter_show;
index fe3a865..b0ca5a4 100644 (file)
@@ -81,7 +81,7 @@ static struct fb_ops cfag12864bfb_ops = {
        .fb_mmap = cfag12864bfb_mmap,
 };
 
-static int __init cfag12864bfb_probe(struct platform_device *device)
+static int __devinit cfag12864bfb_probe(struct platform_device *device)
 {
        int ret = -EINVAL;
        struct fb_info *info = framebuffer_alloc(0, &device->dev);
index ee37727..fd52c48 100644 (file)
@@ -3,35 +3,50 @@ menu "Generic Driver Options"
 config UEVENT_HELPER_PATH
        string "path to uevent helper"
        depends on HOTPLUG
-       default "/sbin/hotplug"
+       default ""
        help
          Path to uevent helper program forked by the kernel for
          every uevent.
+         Before the switch to the netlink-based uevent source, this was
+         used to hook hotplug scripts into kernel device events. It
+         usually pointed to a shell script at /sbin/hotplug.
+         This should not be used today, because usual systems create
+         many events at bootup or device discovery in a very short time
+         frame. One forked process per event can create so many processes
+         that it creates a high system load, or on smaller systems
+         it is known to create out-of-memory situations during bootup.
 
 config DEVTMPFS
-       bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)"
+       bool "Maintain a devtmpfs filesystem to mount at /dev"
        depends on HOTPLUG && SHMEM && TMPFS
        help
-         This creates a tmpfs filesystem, and mounts it at bootup
-         and mounts it at /dev. The kernel driver core creates device
-         nodes for all registered devices in that filesystem. All device
-         nodes are owned by root and have the default mode of 0600.
-         Userspace can add and delete the nodes as needed. This is
-         intended to simplify bootup, and make it possible to delay
-         the initial coldplug at bootup done by udev in userspace.
-         It should also provide a simpler way for rescue systems
-         to bring up a kernel with dynamic major/minor numbers.
-         Meaningful symlinks, permissions and device ownership must
-         still be handled by userspace.
-         If unsure, say N here.
+         This creates a tmpfs filesystem instance early at bootup.
+         In this filesystem, the kernel driver core maintains device
+         nodes with their default names and permissions for all
+         registered devices with an assigned major/minor number.
+         Userspace can modify the filesystem content as needed, add
+         symlinks, and apply needed permissions.
+         It provides a fully functional /dev directory, where usually
+         udev runs on top, managing permissions and adding meaningful
+         symlinks.
+         In very limited environments, it may provide a sufficient
+         functional /dev without any further help. It also allows simple
+         rescue systems, and reliably handles dynamic major/minor numbers.
 
 config DEVTMPFS_MOUNT
-       bool "Automount devtmpfs at /dev"
+       bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
        depends on DEVTMPFS
        help
-         This will mount devtmpfs at /dev if the kernel mounts the root
-         filesystem. It will not affect initramfs based mounting.
-         If unsure, say N here.
+         This will instruct the kernel to automatically mount the
+         devtmpfs filesystem at /dev, directly after the kernel has
+         mounted the root filesystem. The behavior can be overridden
+         with the commandline parameter: devtmpfs.mount=0|1.
+         This option does not affect initramfs based booting, here
+         the devtmpfs filesystem always needs to be mounted manually
+         after the roots is mounted.
+         With this option enabled, it allows to bring up a system in
+         rescue mode with init=/bin/sh, even when the /dev directory
+         on the rootfs is completely empty.
 
 config STANDALONE
        bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
index c0c5a43..71f6af5 100644 (file)
@@ -70,7 +70,7 @@ static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops driver_sysfs_ops = {
+static const struct sysfs_ops driver_sysfs_ops = {
        .show   = drv_attr_show,
        .store  = drv_attr_store,
 };
@@ -115,7 +115,7 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops bus_sysfs_ops = {
+static const struct sysfs_ops bus_sysfs_ops = {
        .show   = bus_attr_show,
        .store  = bus_attr_store,
 };
@@ -154,7 +154,7 @@ static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
        return 0;
 }
 
-static struct kset_uevent_ops bus_uevent_ops = {
+static const struct kset_uevent_ops bus_uevent_ops = {
        .filter = bus_uevent_filter,
 };
 
@@ -173,10 +173,10 @@ static ssize_t driver_unbind(struct device_driver *drv,
        dev = bus_find_device_by_name(bus, NULL, buf);
        if (dev && dev->driver == drv) {
                if (dev->parent)        /* Needed for USB */
-                       down(&dev->parent->sem);
+                       device_lock(dev->parent);
                device_release_driver(dev);
                if (dev->parent)
-                       up(&dev->parent->sem);
+                       device_unlock(dev->parent);
                err = count;
        }
        put_device(dev);
@@ -200,12 +200,12 @@ static ssize_t driver_bind(struct device_driver *drv,
        dev = bus_find_device_by_name(bus, NULL, buf);
        if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
                if (dev->parent)        /* Needed for USB */
-                       down(&dev->parent->sem);
-               down(&dev->sem);
+                       device_lock(dev->parent);
+               device_lock(dev);
                err = driver_probe_device(drv, dev);
-               up(&dev->sem);
+               device_unlock(dev);
                if (dev->parent)
-                       up(&dev->parent->sem);
+                       device_unlock(dev->parent);
 
                if (err > 0) {
                        /* success */
@@ -744,10 +744,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
 
        if (!dev->driver) {
                if (dev->parent)        /* Needed for USB */
-                       down(&dev->parent->sem);
+                       device_lock(dev->parent);
                ret = device_attach(dev);
                if (dev->parent)
-                       up(&dev->parent->sem);
+                       device_unlock(dev->parent);
        }
        return ret < 0 ? ret : 0;
 }
@@ -779,10 +779,10 @@ int device_reprobe(struct device *dev)
 {
        if (dev->driver) {
                if (dev->parent)        /* Needed for USB */
-                       down(&dev->parent->sem);
+                       device_lock(dev->parent);
                device_release_driver(dev);
                if (dev->parent)
-                       up(&dev->parent->sem);
+                       device_unlock(dev->parent);
        }
        return bus_rescan_devices_helper(dev, NULL);
 }
index 6e2c3b0..0147f47 100644 (file)
@@ -31,7 +31,7 @@ static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
        ssize_t ret = -EIO;
 
        if (class_attr->show)
-               ret = class_attr->show(cp->class, buf);
+               ret = class_attr->show(cp->class, class_attr, buf);
        return ret;
 }
 
@@ -43,7 +43,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
        ssize_t ret = -EIO;
 
        if (class_attr->store)
-               ret = class_attr->store(cp->class, buf, count);
+               ret = class_attr->store(cp->class, class_attr, buf, count);
        return ret;
 }
 
@@ -63,7 +63,7 @@ static void class_release(struct kobject *kobj)
        kfree(cp);
 }
 
-static struct sysfs_ops class_sysfs_ops = {
+static const struct sysfs_ops class_sysfs_ops = {
        .show   = class_attr_show,
        .store  = class_attr_store,
 };
@@ -490,6 +490,16 @@ void class_interface_unregister(struct class_interface *class_intf)
        class_put(parent);
 }
 
+ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr,
+                               char *buf)
+{
+       struct class_attribute_string *cs;
+       cs = container_of(attr, struct class_attribute_string, attr);
+       return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
+}
+
+EXPORT_SYMBOL_GPL(show_class_attr_string);
+
 struct class_compat {
        struct kobject *kobj;
 };
index 2820257..ef55df3 100644 (file)
@@ -100,7 +100,7 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops dev_sysfs_ops = {
+static const struct sysfs_ops dev_sysfs_ops = {
        .show   = dev_attr_show,
        .store  = dev_attr_store,
 };
@@ -252,7 +252,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        return retval;
 }
 
-static struct kset_uevent_ops device_uevent_ops = {
+static const struct kset_uevent_ops device_uevent_ops = {
        .filter =       dev_uevent_filter,
        .name =         dev_uevent_name,
        .uevent =       dev_uevent,
@@ -306,15 +306,10 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 {
        enum kobject_action action;
 
-       if (kobject_action_type(buf, count, &action) == 0) {
+       if (kobject_action_type(buf, count, &action) == 0)
                kobject_uevent(&dev->kobj, action);
-               goto out;
-       }
-
-       dev_err(dev, "uevent: unsupported action-string; this will "
-                    "be ignored in a future kernel version\n");
-       kobject_uevent(&dev->kobj, KOBJ_ADD);
-out:
+       else
+               dev_err(dev, "uevent: unknown action-string\n");
        return count;
 }
 
@@ -607,6 +602,7 @@ static struct kobject *get_device_parent(struct device *dev,
        int retval;
 
        if (dev->class) {
+               static DEFINE_MUTEX(gdp_mutex);
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
                struct kobject *k;
@@ -623,6 +619,8 @@ static struct kobject *get_device_parent(struct device *dev,
                else
                        parent_kobj = &parent->kobj;
 
+               mutex_lock(&gdp_mutex);
+
                /* find our class-directory at the parent and reference it */
                spin_lock(&dev->class->p->class_dirs.list_lock);
                list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
@@ -631,20 +629,26 @@ static struct kobject *get_device_parent(struct device *dev,
                                break;
                        }
                spin_unlock(&dev->class->p->class_dirs.list_lock);
-               if (kobj)
+               if (kobj) {
+                       mutex_unlock(&gdp_mutex);
                        return kobj;
+               }
 
                /* or create a new class-directory at the parent device */
                k = kobject_create();
-               if (!k)
+               if (!k) {
+                       mutex_unlock(&gdp_mutex);
                        return NULL;
+               }
                k->kset = &dev->class->p->class_dirs;
                retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
                if (retval < 0) {
+                       mutex_unlock(&gdp_mutex);
                        kobject_put(k);
                        return NULL;
                }
                /* do not emit an uevent for this simple "glue" directory */
+               mutex_unlock(&gdp_mutex);
                return k;
        }
 
@@ -1574,22 +1578,16 @@ int device_rename(struct device *dev, char *new_name)
        if (old_class_name) {
                new_class_name = make_class_name(dev->class->name, &dev->kobj);
                if (new_class_name) {
-                       error = sysfs_create_link_nowarn(&dev->parent->kobj,
-                                                        &dev->kobj,
-                                                        new_class_name);
-                       if (error)
-                               goto out;
-                       sysfs_remove_link(&dev->parent->kobj, old_class_name);
+                       error = sysfs_rename_link(&dev->parent->kobj,
+                                                 &dev->kobj,
+                                                 old_class_name,
+                                                 new_class_name);
                }
        }
 #else
        if (dev->class) {
-               error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj,
-                                                &dev->kobj, dev_name(dev));
-               if (error)
-                       goto out;
-               sysfs_remove_link(&dev->class->p->class_subsys.kobj,
-                                 old_device_name);
+               error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
+                                         &dev->kobj, old_device_name, new_name);
        }
 #endif
 
index 958bd15..7036e8e 100644 (file)
 
 #include "base.h"
 
+static struct sysdev_class_attribute *cpu_sysdev_class_attrs[];
+
 struct sysdev_class cpu_sysdev_class = {
        .name = "cpu",
+       .attrs = cpu_sysdev_class_attrs,
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
@@ -76,34 +79,24 @@ void unregister_cpu(struct cpu *cpu)
 }
 
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-static ssize_t cpu_probe_store(struct class *class, const char *buf,
+static ssize_t cpu_probe_store(struct sys_device *dev,
+                               struct sysdev_attribute *attr,
+                               const char *buf,
                               size_t count)
 {
        return arch_cpu_probe(buf, count);
 }
 
-static ssize_t cpu_release_store(struct class *class, const char *buf,
+static ssize_t cpu_release_store(struct sys_device *dev,
+                               struct sysdev_attribute *attr,
+                               const char *buf,
                                 size_t count)
 {
        return arch_cpu_release(buf, count);
 }
 
-static CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
-static CLASS_ATTR(release, S_IWUSR, NULL, cpu_release_store);
-
-int __init cpu_probe_release_init(void)
-{
-       int rc;
-
-       rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
-                              &class_attr_probe.attr);
-       if (!rc)
-               rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
-                                      &class_attr_release.attr);
-
-       return rc;
-}
-device_initcall(cpu_probe_release_init);
+static SYSDEV_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
+static SYSDEV_ATTR(release, S_IWUSR, NULL, cpu_release_store);
 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
@@ -141,31 +134,39 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
 /*
  * Print cpu online, possible, present, and system maps
  */
-static ssize_t print_cpus_map(char *buf, const struct cpumask *map)
+
+struct cpu_attr {
+       struct sysdev_class_attribute attr;
+       const struct cpumask *const * const map;
+};
+
+static ssize_t show_cpus_attr(struct sysdev_class *class,
+                             struct sysdev_class_attribute *attr,
+                             char *buf)
 {
-       int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map);
+       struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr);
+       int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *(ca->map));
 
        buf[n++] = '\n';
        buf[n] = '\0';
        return n;
 }
 
-#define        print_cpus_func(type) \
-static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf)        \
-{                                                                      \
-       return print_cpus_map(buf, cpu_##type##_mask);                  \
-}                                                                      \
-static struct sysdev_class_attribute attr_##type##_map =               \
-       _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL)
+#define _CPU_ATTR(name, map)                                           \
+       { _SYSDEV_CLASS_ATTR(name, 0444, show_cpus_attr, NULL), map }
 
-print_cpus_func(online);
-print_cpus_func(possible);
-print_cpus_func(present);
+/* Keep in sync with cpu_sysdev_class_attrs */
+static struct cpu_attr cpu_attrs[] = {
+       _CPU_ATTR(online, &cpu_online_mask),
+       _CPU_ATTR(possible, &cpu_possible_mask),
+       _CPU_ATTR(present, &cpu_present_mask),
+};
 
 /*
  * Print values for NR_CPUS and offlined cpus
  */
-static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf)
+static ssize_t print_cpus_kernel_max(struct sysdev_class *class,
+                                    struct sysdev_class_attribute *attr, char *buf)
 {
        int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
        return n;
@@ -175,7 +176,8 @@ static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
 /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
 unsigned int total_cpus;
 
-static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
+static ssize_t print_cpus_offline(struct sysdev_class *class,
+                                 struct sysdev_class_attribute *attr, char *buf)
 {
        int n = 0, len = PAGE_SIZE-2;
        cpumask_var_t offline;
@@ -204,29 +206,6 @@ static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
 }
 static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL);
 
-static struct sysdev_class_attribute *cpu_state_attr[] = {
-       &attr_online_map,
-       &attr_possible_map,
-       &attr_present_map,
-       &attr_kernel_max,
-       &attr_offline,
-};
-
-static int cpu_states_init(void)
-{
-       int i;
-       int err = 0;
-
-       for (i = 0;  i < ARRAY_SIZE(cpu_state_attr); i++) {
-               int ret;
-               ret = sysdev_class_create_file(&cpu_sysdev_class,
-                                               cpu_state_attr[i]);
-               if (!err)
-                       err = ret;
-       }
-       return err;
-}
-
 /*
  * register_cpu - Setup a sysfs device for a CPU.
  * @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -272,9 +251,6 @@ int __init cpu_dev_init(void)
        int err;
 
        err = sysdev_class_register(&cpu_sysdev_class);
-       if (!err)
-               err = cpu_states_init();
-
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
        if (!err)
                err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
@@ -282,3 +258,16 @@ int __init cpu_dev_init(void)
 
        return err;
 }
+
+static struct sysdev_class_attribute *cpu_sysdev_class_attrs[] = {
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+       &attr_probe,
+       &attr_release,
+#endif
+       &cpu_attrs[0].attr,
+       &cpu_attrs[1].attr,
+       &cpu_attrs[2].attr,
+       &attr_kernel_max,
+       &attr_offline,
+       NULL
+};
index ee95c76..c89291f 100644 (file)
@@ -85,7 +85,7 @@ static void driver_sysfs_remove(struct device *dev)
  * for before calling this. (It is ok to call with no other effort
  * from a driver's probe() method.)
  *
- * This function must be called with @dev->sem held.
+ * This function must be called with the device lock held.
  */
 int device_bind_driver(struct device *dev)
 {
@@ -190,8 +190,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
  * This function returns -ENODEV if the device is not registered,
  * 1 if the device is bound successfully and 0 otherwise.
  *
- * This function must be called with @dev->sem held.  When called for a
- * USB interface, @dev->parent->sem must be held as well.
+ * This function must be called with @dev lock held.  When called for a
+ * USB interface, @dev->parent lock must be held as well.
  */
 int driver_probe_device(struct device_driver *drv, struct device *dev)
 {
@@ -233,13 +233,13 @@ static int __device_attach(struct device_driver *drv, void *data)
  * 0 if no matching driver was found;
  * -ENODEV if the device is not registered.
  *
- * When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent lock must be held.
  */
 int device_attach(struct device *dev)
 {
        int ret = 0;
 
-       down(&dev->sem);
+       device_lock(dev);
        if (dev->driver) {
                ret = device_bind_driver(dev);
                if (ret == 0)
@@ -253,7 +253,7 @@ int device_attach(struct device *dev)
                ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
                pm_runtime_put_sync(dev);
        }
-       up(&dev->sem);
+       device_unlock(dev);
        return ret;
 }
 EXPORT_SYMBOL_GPL(device_attach);
@@ -276,13 +276,13 @@ static int __driver_attach(struct device *dev, void *data)
                return 0;
 
        if (dev->parent)        /* Needed for USB */
-               down(&dev->parent->sem);
-       down(&dev->sem);
+               device_lock(dev->parent);
+       device_lock(dev);
        if (!dev->driver)
                driver_probe_device(drv, dev);
-       up(&dev->sem);
+       device_unlock(dev);
        if (dev->parent)
-               up(&dev->parent->sem);
+               device_unlock(dev->parent);
 
        return 0;
 }
@@ -303,8 +303,8 @@ int driver_attach(struct device_driver *drv)
 EXPORT_SYMBOL_GPL(driver_attach);
 
 /*
- * __device_release_driver() must be called with @dev->sem held.
- * When called for a USB interface, @dev->parent->sem must be held as well.
+ * __device_release_driver() must be called with @dev lock held.
+ * When called for a USB interface, @dev->parent lock must be held as well.
  */
 static void __device_release_driver(struct device *dev)
 {
@@ -343,7 +343,7 @@ static void __device_release_driver(struct device *dev)
  * @dev: device.
  *
  * Manually detach device from driver.
- * When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent lock must be held.
  */
 void device_release_driver(struct device *dev)
 {
@@ -352,9 +352,9 @@ void device_release_driver(struct device *dev)
         * within their ->remove callback for the same device, they
         * will deadlock right here.
         */
-       down(&dev->sem);
+       device_lock(dev);
        __device_release_driver(dev);
-       up(&dev->sem);
+       device_unlock(dev);
 }
 EXPORT_SYMBOL_GPL(device_release_driver);
 
@@ -381,13 +381,13 @@ void driver_detach(struct device_driver *drv)
                spin_unlock(&drv->p->klist_devices.k_lock);
 
                if (dev->parent)        /* Needed for USB */
-                       down(&dev->parent->sem);
-               down(&dev->sem);
+                       device_lock(dev->parent);
+               device_lock(dev);
                if (dev->driver == drv)
                        __device_release_driver(dev);
-               up(&dev->sem);
+               device_unlock(dev);
                if (dev->parent)
-                       up(&dev->parent->sem);
+                       device_unlock(dev->parent);
                put_device(dev);
        }
 }
index 42ae452..dac478c 100644 (file)
@@ -301,6 +301,19 @@ int devtmpfs_delete_node(struct device *dev)
                if (dentry->d_inode) {
                        err = vfs_getattr(nd.path.mnt, dentry, &stat);
                        if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+                               struct iattr newattrs;
+                               /*
+                                * before unlinking this node, reset permissions
+                                * of possible references like hardlinks
+                                */
+                               newattrs.ia_uid = 0;
+                               newattrs.ia_gid = 0;
+                               newattrs.ia_mode = stat.mode & ~0777;
+                               newattrs.ia_valid =
+                                       ATTR_UID|ATTR_GID|ATTR_MODE;
+                               mutex_lock(&dentry->d_inode->i_mutex);
+                               notify_change(dentry, &newattrs);
+                               mutex_unlock(&dentry->d_inode->i_mutex);
                                err = vfs_unlink(nd.path.dentry->d_inode,
                                                 dentry);
                                if (!err || err == -ENOENT)
index a950241..d0dc26a 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kthread.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
-#include "base.h"
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -69,7 +68,9 @@ fw_load_abort(struct firmware_priv *fw_priv)
 }
 
 static ssize_t
-firmware_timeout_show(struct class *class, char *buf)
+firmware_timeout_show(struct class *class,
+                     struct class_attribute *attr,
+                     char *buf)
 {
        return sprintf(buf, "%d\n", loading_timeout);
 }
@@ -87,7 +88,9 @@ firmware_timeout_show(struct class *class, char *buf)
  *     Note: zero means 'wait forever'.
  **/
 static ssize_t
-firmware_timeout_store(struct class *class, const char *buf, size_t count)
+firmware_timeout_store(struct class *class,
+                       struct class_attribute *attr,
+                       const char *buf, size_t count)
 {
        loading_timeout = simple_strtol(buf, NULL, 10);
        if (loading_timeout < 0)
@@ -610,7 +613,7 @@ request_firmware_work_func(void *arg)
 }
 
 /**
- * request_firmware_nowait: asynchronous version of request_firmware
+ * request_firmware_nowait - asynchronous version of request_firmware
  * @module: module requesting the firmware
  * @uevent: sends uevent to copy the firmware image if this flag
  *     is non-zero else the firmware copy must be done manually.
index bd02505..2f86915 100644 (file)
@@ -44,7 +44,7 @@ static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uev
        return retval;
 }
 
-static struct kset_uevent_ops memory_uevent_ops = {
+static const struct kset_uevent_ops memory_uevent_ops = {
        .name           = memory_uevent_name,
        .uevent         = memory_uevent,
 };
@@ -309,17 +309,18 @@ static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
  * Block size attribute stuff
  */
 static ssize_t
-print_block_size(struct class *class, char *buf)
+print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
+                char *buf)
 {
        return sprintf(buf, "%#lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
 }
 
-static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
+static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
 
 static int block_size_init(void)
 {
        return sysfs_create_file(&memory_sysdev_class.kset.kobj,
-                               &class_attr_block_size_bytes.attr);
+                               &attr_block_size_bytes.attr);
 }
 
 /*
@@ -330,7 +331,8 @@ static int block_size_init(void)
  */
 #ifdef CONFIG_ARCH_MEMORY_PROBE
 static ssize_t
-memory_probe_store(struct class *class, const char *buf, size_t count)
+memory_probe_store(struct class *class, struct class_attribute *attr,
+                  const char *buf, size_t count)
 {
        u64 phys_addr;
        int nid;
@@ -367,7 +369,9 @@ static inline int memory_probe_init(void)
 
 /* Soft offline a page */
 static ssize_t
-store_soft_offline_page(struct class *class, const char *buf, size_t count)
+store_soft_offline_page(struct class *class,
+                       struct class_attribute *attr,
+                       const char *buf, size_t count)
 {
        int ret;
        u64 pfn;
@@ -384,7 +388,9 @@ store_soft_offline_page(struct class *class, const char *buf, size_t count)
 
 /* Forcibly offline a page, including killing processes. */
 static ssize_t
-store_hard_offline_page(struct class *class, const char *buf, size_t count)
+store_hard_offline_page(struct class *class,
+                       struct class_attribute *attr,
+                       const char *buf, size_t count)
 {
        int ret;
        u64 pfn;
index 7012279..ad43185 100644 (file)
 #include <linux/device.h>
 #include <linux/swap.h>
 
+static struct sysdev_class_attribute *node_state_attrs[];
+
 static struct sysdev_class node_class = {
        .name = "node",
+       .attrs = node_state_attrs,
 };
 
 
@@ -544,76 +547,52 @@ static ssize_t print_nodes_state(enum node_states state, char *buf)
        return n;
 }
 
-static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf)
-{
-       return print_nodes_state(N_POSSIBLE, buf);
-}
-
-static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
-{
-       return print_nodes_state(N_ONLINE, buf);
-}
-
-static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
-                                               char *buf)
-{
-       return print_nodes_state(N_NORMAL_MEMORY, buf);
-}
+struct node_attr {
+       struct sysdev_class_attribute attr;
+       enum node_states state;
+};
 
-static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf)
+static ssize_t show_node_state(struct sysdev_class *class,
+                              struct sysdev_class_attribute *attr, char *buf)
 {
-       return print_nodes_state(N_CPU, buf);
+       struct node_attr *na = container_of(attr, struct node_attr, attr);
+       return print_nodes_state(na->state, buf);
 }
 
-static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL);
-static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL);
-static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
-                                                                       NULL);
-static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
+#define _NODE_ATTR(name, state) \
+       { _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state }
 
+static struct node_attr node_state_attr[] = {
+       _NODE_ATTR(possible, N_POSSIBLE),
+       _NODE_ATTR(online, N_ONLINE),
+       _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY),
+       _NODE_ATTR(has_cpu, N_CPU),
 #ifdef CONFIG_HIGHMEM
-static ssize_t print_nodes_has_high_memory(struct sysdev_class *class,
-                                                char *buf)
-{
-       return print_nodes_state(N_HIGH_MEMORY, buf);
-}
-
-static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
-                                                                        NULL);
+       _NODE_ATTR(has_high_memory, N_HIGH_MEMORY),
 #endif
+};
 
-struct sysdev_class_attribute *node_state_attr[] = {
-       &attr_possible,
-       &attr_online,
-       &attr_has_normal_memory,
+static struct sysdev_class_attribute *node_state_attrs[] = {
+       &node_state_attr[0].attr,
+       &node_state_attr[1].attr,
+       &node_state_attr[2].attr,
+       &node_state_attr[3].attr,
 #ifdef CONFIG_HIGHMEM
-       &attr_has_high_memory,
+       &node_state_attr[4].attr,
 #endif
-       &attr_has_cpu,
+       NULL
 };
 
-static int node_states_init(void)
-{
-       int i;
-       int err = 0;
-
-       for (i = 0;  i < NR_NODE_STATES; i++) {
-               int ret;
-               ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
-               if (!err)
-                       err = ret;
-       }
-       return err;
-}
-
 #define NODE_CALLBACK_PRI      2       /* lower than SLAB */
 static int __init register_node_type(void)
 {
        int ret;
 
+       BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES);
+       BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES);
+
        ret = sysdev_class_register(&node_class);
        if (!ret) {
-               ret = node_states_init();
                hotplug_memory_notifier(node_memory_callback,
                                        NODE_CALLBACK_PRI);
        }
index 58efaf2..1ba9d61 100644 (file)
@@ -128,7 +128,7 @@ struct platform_object {
 };
 
 /**
- * platform_device_put
+ * platform_device_put - destroy a platform device
  * @pdev: platform device to free
  *
  * Free all memory associated with a platform device.  This function must
@@ -152,7 +152,7 @@ static void platform_device_release(struct device *dev)
 }
 
 /**
- * platform_device_alloc
+ * platform_device_alloc - create a platform device
  * @name: base name of the device we're adding
  * @id: instance id
  *
@@ -177,7 +177,7 @@ struct platform_device *platform_device_alloc(const char *name, int id)
 EXPORT_SYMBOL_GPL(platform_device_alloc);
 
 /**
- * platform_device_add_resources
+ * platform_device_add_resources - add resources to a platform device
  * @pdev: platform device allocated by platform_device_alloc to add resources to
  * @res: set of resources that needs to be allocated for the device
  * @num: number of resources
@@ -202,7 +202,7 @@ int platform_device_add_resources(struct platform_device *pdev,
 EXPORT_SYMBOL_GPL(platform_device_add_resources);
 
 /**
- * platform_device_add_data
+ * platform_device_add_data - add platform-specific data to a platform device
  * @pdev: platform device allocated by platform_device_alloc to add resources to
  * @data: platform specific data for this platform device
  * @size: size of platform specific data
@@ -344,7 +344,7 @@ void platform_device_unregister(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_unregister);
 
 /**
- * platform_device_register_simple
+ * platform_device_register_simple - add a platform-level device and its resources
  * @name: base name of the device we're adding
  * @id: instance id
  * @res: set of resources that needs to be allocated for the device
@@ -396,7 +396,7 @@ error:
 EXPORT_SYMBOL_GPL(platform_device_register_simple);
 
 /**
- * platform_device_register_data
+ * platform_device_register_data - add a platform-level device with platform-specific data
  * @parent: parent device for the device we're adding
  * @name: base name of the device we're adding
  * @id: instance id
@@ -473,7 +473,7 @@ static void platform_drv_shutdown(struct device *_dev)
 }
 
 /**
- * platform_driver_register
+ * platform_driver_register - register a driver for platform-level devices
  * @drv: platform driver structure
  */
 int platform_driver_register(struct platform_driver *drv)
@@ -491,7 +491,7 @@ int platform_driver_register(struct platform_driver *drv)
 EXPORT_SYMBOL_GPL(platform_driver_register);
 
 /**
- * platform_driver_unregister
+ * platform_driver_unregister - unregister a driver for platform-level devices
  * @drv: platform driver structure
  */
 void platform_driver_unregister(struct platform_driver *drv)
@@ -548,6 +548,64 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
 }
 EXPORT_SYMBOL_GPL(platform_driver_probe);
 
+/**
+ * platform_create_bundle - register driver and create corresponding device
+ * @driver: platform driver structure
+ * @probe: the driver probe routine, probably from an __init section
+ * @res: set of resources that needs to be allocated for the device
+ * @n_res: number of resources
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * Use this in legacy-style modules that probe hardware directly and
+ * register a single platform device and corresponding platform driver.
+ */
+struct platform_device * __init_or_module platform_create_bundle(
+                       struct platform_driver *driver,
+                       int (*probe)(struct platform_device *),
+                       struct resource *res, unsigned int n_res,
+                       const void *data, size_t size)
+{
+       struct platform_device *pdev;
+       int error;
+
+       pdev = platform_device_alloc(driver->driver.name, -1);
+       if (!pdev) {
+               error = -ENOMEM;
+               goto err_out;
+       }
+
+       if (res) {
+               error = platform_device_add_resources(pdev, res, n_res);
+               if (error)
+                       goto err_pdev_put;
+       }
+
+       if (data) {
+               error = platform_device_add_data(pdev, data, size);
+               if (error)
+                       goto err_pdev_put;
+       }
+
+       error = platform_device_add(pdev);
+       if (error)
+               goto err_pdev_put;
+
+       error = platform_driver_probe(driver, probe);
+       if (error)
+               goto err_pdev_del;
+
+       return pdev;
+
+err_pdev_del:
+       platform_device_del(pdev);
+err_pdev_put:
+       platform_device_put(pdev);
+err_out:
+       return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(platform_create_bundle);
+
 /* modalias support enables more hands-off userspace setup:
  * (a) environment variable lets new-style hotplug events work once system is
  *     fully running:  "modprobe $MODALIAS"
@@ -578,7 +636,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 }
 
 static const struct platform_device_id *platform_match_id(
-                       struct platform_device_id *id,
+                       const struct platform_device_id *id,
                        struct platform_device *pdev)
 {
        while (id->name[0]) {
index 0e26a6f..d477f4d 100644 (file)
@@ -35,8 +35,8 @@
  * because children are guaranteed to be discovered after parents, and
  * are inserted at the back of the list on discovery.
  *
- * Since device_pm_add() may be called with a device semaphore held,
- * we must never try to acquire a device semaphore while holding
+ * Since device_pm_add() may be called with a device lock held,
+ * we must never try to acquire a device lock while holding
  * dpm_list_mutex.
  */
 
@@ -508,7 +508,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        TRACE_RESUME(0);
 
        dpm_wait(dev->parent, async);
-       down(&dev->sem);
+       device_lock(dev);
 
        dev->power.status = DPM_RESUMING;
 
@@ -543,7 +543,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
                }
        }
  End:
-       up(&dev->sem);
+       device_unlock(dev);
        complete_all(&dev->power.completion);
 
        TRACE_RESUME(error);
@@ -629,7 +629,7 @@ static void dpm_resume(pm_message_t state)
  */
 static void device_complete(struct device *dev, pm_message_t state)
 {
-       down(&dev->sem);
+       device_lock(dev);
 
        if (dev->class && dev->class->pm && dev->class->pm->complete) {
                pm_dev_dbg(dev, state, "completing class ");
@@ -646,7 +646,7 @@ static void device_complete(struct device *dev, pm_message_t state)
                dev->bus->pm->complete(dev);
        }
 
-       up(&dev->sem);
+       device_unlock(dev);
 }
 
 /**
@@ -809,7 +809,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        int error = 0;
 
        dpm_wait_for_children(dev, async);
-       down(&dev->sem);
+       device_lock(dev);
 
        if (async_error)
                goto End;
@@ -849,7 +849,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                dev->power.status = DPM_OFF;
 
  End:
-       up(&dev->sem);
+       device_unlock(dev);
        complete_all(&dev->power.completion);
 
        return error;
@@ -938,7 +938,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
-       down(&dev->sem);
+       device_lock(dev);
 
        if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
                pm_dev_dbg(dev, state, "preparing ");
@@ -962,7 +962,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
                suspend_report_result(dev->class->pm->prepare, error);
        }
  End:
-       up(&dev->sem);
+       device_unlock(dev);
 
        return error;
 }
index 0d90390..8980fee 100644 (file)
@@ -54,7 +54,7 @@ sysdev_store(struct kobject *kobj, struct attribute *attr,
        return -EIO;
 }
 
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
        .show   = sysdev_show,
        .store  = sysdev_store,
 };
@@ -89,7 +89,7 @@ static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
        struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
 
        if (class_attr->show)
-               return class_attr->show(class, buffer);
+               return class_attr->show(class, class_attr, buffer);
        return -EIO;
 }
 
@@ -100,11 +100,11 @@ static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
        struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
 
        if (class_attr->store)
-               return class_attr->store(class, buffer, count);
+               return class_attr->store(class, class_attr, buffer, count);
        return -EIO;
 }
 
-static struct sysfs_ops sysfs_class_ops = {
+static const struct sysfs_ops sysfs_class_ops = {
        .show   = sysdev_class_show,
        .store  = sysdev_class_store,
 };
@@ -145,13 +145,20 @@ int sysdev_class_register(struct sysdev_class *cls)
        if (retval)
                return retval;
 
-       return kset_register(&cls->kset);
+       retval = kset_register(&cls->kset);
+       if (!retval && cls->attrs)
+               retval = sysfs_create_files(&cls->kset.kobj,
+                                           (const struct attribute **)cls->attrs);
+       return retval;
 }
 
 void sysdev_class_unregister(struct sysdev_class *cls)
 {
        pr_debug("Unregistering sysdev class '%s'\n",
                 kobject_name(&cls->kset.kobj));
+       if (cls->attrs)
+               sysfs_remove_files(&cls->kset.kobj,
+                                  (const struct attribute **)cls->attrs);
        kset_unregister(&cls->kset);
 }
 
index b9b1170..90c4038 100644 (file)
  * Better audit of register_blkdev.
  */
 
-#define FLOPPY_SANITY_CHECK
 #undef  FLOPPY_SILENT_DCL_CLEAR
 
 #define REALLY_SLOW_IO
 
 #define DEBUGT 2
-#define DCL_DEBUG      /* debug disk change line */
+
+#define DPRINT(format, args...) \
+       pr_info("floppy%d: " format, current_drive, ##args)
+
+#define DCL_DEBUG              /* debug disk change line */
+#ifdef DCL_DEBUG
+#define debug_dcl(test, fmt, args...) \
+       do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
+#else
+#define debug_dcl(test, fmt, args...) \
+       do { if (0) DPRINT(fmt, ##args); } while (0)
+#endif
 
 /* do print messages for unexpected interrupts */
 static int print_unex = 1;
@@ -180,6 +190,8 @@ static int print_unex = 1;
 #include <linux/mod_devicetable.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
 #include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
 
 /*
  * PS/2 floppies have much slower step rates than regular floppies.
@@ -191,8 +203,6 @@ static int slow_floppy;
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
 
 static int FLOPPY_IRQ = 6;
 static int FLOPPY_DMA = 2;
@@ -241,8 +251,6 @@ static int allowed_drive_mask = 0x33;
 
 static int irqdma_allocated;
 
-#define DEVICE_NAME "floppy"
-
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/cdrom.h>       /* for the compatibility eject ioctl */
@@ -250,7 +258,7 @@ static int irqdma_allocated;
 
 static struct request *current_req;
 static struct request_queue *floppy_queue;
-static void do_fd_request(struct request_queue * q);
+static void do_fd_request(struct request_queue *q);
 
 #ifndef fd_get_dma_residue
 #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -263,7 +271,7 @@ static void do_fd_request(struct request_queue * q);
 #endif
 
 #ifndef fd_dma_mem_alloc
-#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
+#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
 #endif
 
 static inline void fallback_on_nodma_alloc(char **addr, size_t l)
@@ -273,7 +281,7 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
                return;         /* we have the memory */
        if (can_use_virtual_dma != 2)
                return;         /* no fallback allowed */
-       printk("DMA memory shortage. Temporarily falling back on virtual DMA\n");
+       pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
        *addr = (char *)nodma_mem_alloc(l);
 #else
        return;
@@ -283,59 +291,50 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
 /* End dma memory related stuff */
 
 static unsigned long fake_change;
-static int initialising = 1;
+static bool initialized;
 
-#define ITYPE(x) (((x)>>2) & 0x1f)
-#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
-#define UNIT(x) ((x) & 0x03)   /* drive on fdc */
-#define FDC(x) (((x) & 0x04) >> 2)     /* fdc of drive */
+#define ITYPE(x)       (((x) >> 2) & 0x1f)
+#define TOMINOR(x)     ((x & 3) | ((x & 4) << 5))
+#define UNIT(x)                ((x) & 0x03)            /* drive on fdc */
+#define FDC(x)         (((x) & 0x04) >> 2)     /* fdc of drive */
        /* reverse mapping from unit and fdc to drive */
 #define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
-#define DP (&drive_params[current_drive])
-#define DRS (&drive_state[current_drive])
-#define DRWE (&write_errors[current_drive])
-#define FDCS (&fdc_state[fdc])
-#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
-#define SETF(x) set_bit(x##_BIT, &DRS->flags)
-#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
 
-#define UDP (&drive_params[drive])
-#define UDRS (&drive_state[drive])
-#define UDRWE (&write_errors[drive])
-#define UFDCS (&fdc_state[FDC(drive)])
-#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
-#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
-#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
+#define DP     (&drive_params[current_drive])
+#define DRS    (&drive_state[current_drive])
+#define DRWE   (&write_errors[current_drive])
+#define FDCS   (&fdc_state[fdc])
 
-#define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
+#define UDP    (&drive_params[drive])
+#define UDRS   (&drive_state[drive])
+#define UDRWE  (&write_errors[drive])
+#define UFDCS  (&fdc_state[FDC(drive)])
 
-#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
-#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
-
-#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
+#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
+#define STRETCH(floppy)        ((floppy)->stretch & FD_STRETCH)
 
 /* read/write */
-#define COMMAND raw_cmd->cmd[0]
-#define DR_SELECT raw_cmd->cmd[1]
-#define TRACK raw_cmd->cmd[2]
-#define HEAD raw_cmd->cmd[3]
-#define SECTOR raw_cmd->cmd[4]
-#define SIZECODE raw_cmd->cmd[5]
-#define SECT_PER_TRACK raw_cmd->cmd[6]
-#define GAP raw_cmd->cmd[7]
-#define SIZECODE2 raw_cmd->cmd[8]
+#define COMMAND                (raw_cmd->cmd[0])
+#define DR_SELECT      (raw_cmd->cmd[1])
+#define TRACK          (raw_cmd->cmd[2])
+#define HEAD           (raw_cmd->cmd[3])
+#define SECTOR         (raw_cmd->cmd[4])
+#define SIZECODE       (raw_cmd->cmd[5])
+#define SECT_PER_TRACK (raw_cmd->cmd[6])
+#define GAP            (raw_cmd->cmd[7])
+#define SIZECODE2      (raw_cmd->cmd[8])
 #define NR_RW 9
 
 /* format */
-#define F_SIZECODE raw_cmd->cmd[2]
-#define F_SECT_PER_TRACK raw_cmd->cmd[3]
-#define F_GAP raw_cmd->cmd[4]
-#define F_FILL raw_cmd->cmd[5]
+#define F_SIZECODE     (raw_cmd->cmd[2])
+#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
+#define F_GAP          (raw_cmd->cmd[4])
+#define F_FILL         (raw_cmd->cmd[5])
 #define NR_F 6
 
 /*
- * Maximum disk size (in kilobytes). This default is used whenever the
- * current disk size is unknown.
+ * Maximum disk size (in kilobytes).
+ * This default is used whenever the current disk size is unknown.
  * [Now it is rather a minimum]
  */
 #define MAX_DISK_SIZE 4                /* 3984 */
@@ -345,16 +344,17 @@ static int initialising = 1;
  */
 #define MAX_REPLIES 16
 static unsigned char reply_buffer[MAX_REPLIES];
-static int inr;                        /* size of reply buffer, when called from interrupt */
-#define ST0 (reply_buffer[0])
-#define ST1 (reply_buffer[1])
-#define ST2 (reply_buffer[2])
-#define ST3 (reply_buffer[0])  /* result of GETSTATUS */
-#define R_TRACK (reply_buffer[3])
-#define R_HEAD (reply_buffer[4])
-#define R_SECTOR (reply_buffer[5])
-#define R_SIZECODE (reply_buffer[6])
-#define SEL_DLY (2*HZ/100)
+static int inr;                /* size of reply buffer, when called from interrupt */
+#define ST0            (reply_buffer[0])
+#define ST1            (reply_buffer[1])
+#define ST2            (reply_buffer[2])
+#define ST3            (reply_buffer[0])       /* result of GETSTATUS */
+#define R_TRACK                (reply_buffer[3])
+#define R_HEAD         (reply_buffer[4])
+#define R_SECTOR       (reply_buffer[5])
+#define R_SIZECODE     (reply_buffer[6])
+
+#define SEL_DLY                (2 * HZ / 100)
 
 /*
  * this struct defines the different floppy drive types.
@@ -505,9 +505,9 @@ static char floppy_device_name[] = "floppy";
 static int probing;
 
 /* Synchronization of FDC access. */
-#define FD_COMMAND_NONE -1
-#define FD_COMMAND_ERROR 2
-#define FD_COMMAND_OKAY 3
+#define FD_COMMAND_NONE                -1
+#define FD_COMMAND_ERROR       2
+#define FD_COMMAND_OKAY                3
 
 static volatile int command_status = FD_COMMAND_NONE;
 static unsigned long fdc_busy;
@@ -515,11 +515,6 @@ static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
 static DECLARE_WAIT_QUEUE_HEAD(command_done);
 
 #define NO_SIGNAL (!interruptible || !signal_pending(current))
-#define CALL(x) if ((x) == -EINTR) return -EINTR
-#define ECALL(x) if ((ret = (x))) return ret;
-#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
-#define WAIT(x) _WAIT((x),interruptible)
-#define IWAIT(x) _WAIT((x),1)
 
 /* Errors during formatting are counted here. */
 static int format_errors;
@@ -545,8 +540,9 @@ static int max_buffer_sectors;
 static int *errors;
 typedef void (*done_f)(int);
 static struct cont_t {
-       void (*interrupt)(void);        /* this is called after the interrupt of the
-                                        * main command */
+       void (*interrupt)(void);
+                               /* this is called after the interrupt of the
+                                * main command */
        void (*redo)(void);     /* this is called to retry the operation */
        void (*error)(void);    /* this is called to tally an error */
        done_f done;            /* this is called to say if the operation has
@@ -571,7 +567,6 @@ static void floppy_release_irq_and_dma(void);
  * reset doesn't need to be tested before sending commands, because
  * output_byte is automatically disabled when reset is set.
  */
-#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }
 static void reset_fdc(void);
 
 /*
@@ -579,9 +574,9 @@ static void reset_fdc(void);
  * information to interrupts. They are the data used for the current
  * request.
  */
-#define NO_TRACK -1
-#define NEED_1_RECAL -2
-#define NEED_2_RECAL -3
+#define NO_TRACK       -1
+#define NEED_1_RECAL   -2
+#define NEED_2_RECAL   -3
 
 static int usage_count;
 
@@ -621,39 +616,35 @@ static inline void set_debugt(void)
        debugtimer = jiffies;
 }
 
-static inline void debugt(const char *message)
+static inline void debugt(const char *func, const char *msg)
 {
        if (DP->flags & DEBUGT)
-               printk("%s dtime=%lu\n", message, jiffies - debugtimer);
+               pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
 }
 #else
 static inline void set_debugt(void) { }
-static inline void debugt(const char *message) { }
+static inline void debugt(const char *func, const char *msg) { }
 #endif /* DEBUGT */
 
-typedef void (*timeout_fn) (unsigned long);
+typedef void (*timeout_fn)(unsigned long);
 static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
 
 static const char *timeout_message;
 
-#ifdef FLOPPY_SANITY_CHECK
-static void is_alive(const char *message)
+static void is_alive(const char *func, const char *message)
 {
        /* this routine checks whether the floppy driver is "alive" */
-       if (test_bit(0, &fdc_busy) && command_status < 2
-           && !timer_pending(&fd_timeout)) {
-               DPRINT("timeout handler died: %s\n", message);
+       if (test_bit(0, &fdc_busy) && command_status < 2 &&
+           !timer_pending(&fd_timeout)) {
+               DPRINT("%s: timeout handler died.  %s\n", func, message);
        }
 }
-#endif
 
-static void (*do_floppy) (void) = NULL;
-
-#ifdef FLOPPY_SANITY_CHECK
+static void (*do_floppy)(void) = NULL;
 
 #define OLOGSIZE 20
 
-static void (*lasthandler) (void);
+static void (*lasthandler)(void);
 static unsigned long interruptjiffies;
 static unsigned long resultjiffies;
 static int resultsize;
@@ -666,12 +657,11 @@ static struct output_log {
 } output_log[OLOGSIZE];
 
 static int output_log_pos;
-#endif
 
 #define current_reqD -1
 #define MAXTIMEOUT -2
 
-static void __reschedule_timeout(int drive, const char *message, int marg)
+static void __reschedule_timeout(int drive, const char *message)
 {
        if (drive == current_reqD)
                drive = current_drive;
@@ -682,25 +672,22 @@ static void __reschedule_timeout(int drive, const char *message, int marg)
        } else
                fd_timeout.expires = jiffies + UDP->timeout;
        add_timer(&fd_timeout);
-       if (UDP->flags & FD_DEBUG) {
-               DPRINT("reschedule timeout ");
-               printk(message, marg);
-               printk("\n");
-       }
+       if (UDP->flags & FD_DEBUG)
+               DPRINT("reschedule timeout %s\n", message);
        timeout_message = message;
 }
 
-static void reschedule_timeout(int drive, const char *message, int marg)
+static void reschedule_timeout(int drive, const char *message)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&floppy_lock, flags);
-       __reschedule_timeout(drive, message, marg);
+       __reschedule_timeout(drive, message);
        spin_unlock_irqrestore(&floppy_lock, flags);
 }
 
-#define INFBOUND(a,b) (a)=max_t(int, a, b)
-#define SUPBOUND(a,b) (a)=min_t(int, a, b)
+#define INFBOUND(a, b) (a) = max_t(int, a, b)
+#define SUPBOUND(a, b) (a) = min_t(int, a, b)
 
 /*
  * Bottom half floppy driver.
@@ -739,7 +726,6 @@ static int disk_change(int drive)
 {
        int fdc = FDC(drive);
 
-#ifdef FLOPPY_SANITY_CHECK
        if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
                DPRINT("WARNING disk change called early\n");
        if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
@@ -748,31 +734,27 @@ static int disk_change(int drive)
                DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
                       (unsigned int)FDCS->dor);
        }
-#endif
 
-#ifdef DCL_DEBUG
-       if (UDP->flags & FD_DEBUG) {
-               DPRINT("checking disk change line for drive %d\n", drive);
-               DPRINT("jiffies=%lu\n", jiffies);
-               DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
-               DPRINT("flags=%lx\n", UDRS->flags);
-       }
-#endif
+       debug_dcl(UDP->flags,
+                 "checking disk change line for drive %d\n", drive);
+       debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
+       debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
+       debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
+
        if (UDP->flags & FD_BROKEN_DCL)
-               return UTESTF(FD_DISK_CHANGED);
+               return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
        if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
-               USETF(FD_VERIFY);       /* verify write protection */
-               if (UDRS->maxblock) {
-                       /* mark it changed */
-                       USETF(FD_DISK_CHANGED);
-               }
+               set_bit(FD_VERIFY_BIT, &UDRS->flags);
+                                       /* verify write protection */
+
+               if (UDRS->maxblock)     /* mark it changed */
+                       set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
 
                /* invalidate its geometry */
                if (UDRS->keep_data >= 0) {
                        if ((UDP->flags & FTD_MSG) &&
                            current_type[drive] != NULL)
-                               DPRINT("Disk type is undefined after "
-                                      "disk change\n");
+                               DPRINT("Disk type is undefined after disk change\n");
                        current_type[drive] = NULL;
                        floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
                }
@@ -780,7 +762,7 @@ static int disk_change(int drive)
                return 1;
        } else {
                UDRS->last_checked = jiffies;
-               UCLEARF(FD_DISK_NEWCHANGE);
+               clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
        }
        return 0;
 }
@@ -790,6 +772,12 @@ static inline int is_selected(int dor, int unit)
        return ((dor & (0x10 << unit)) && (dor & 3) == unit);
 }
 
+static bool is_ready_state(int status)
+{
+       int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
+       return state == STATUS_READY;
+}
+
 static int set_dor(int fdc, char mask, char data)
 {
        unsigned char unit;
@@ -806,11 +794,8 @@ static int set_dor(int fdc, char mask, char data)
                unit = olddor & 0x3;
                if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
                        drive = REVDRIVE(fdc, unit);
-#ifdef DCL_DEBUG
-                       if (UDP->flags & FD_DEBUG) {
-                               DPRINT("calling disk change from set_dor\n");
-                       }
-#endif
+                       debug_dcl(UDP->flags,
+                                 "calling disk change from set_dor\n");
                        disk_change(drive);
                }
                FDCS->dor = newdor;
@@ -834,8 +819,10 @@ static void twaddle(void)
        DRS->select_date = jiffies;
 }
 
-/* reset all driver information about the current fdc. This is needed after
- * a reset, and after a raw command. */
+/*
+ * Reset all driver information about the current fdc.
+ * This is needed after a reset, and after a raw command.
+ */
 static void reset_fdc_info(int mode)
 {
        int drive;
@@ -857,7 +844,7 @@ static void set_fdc(int drive)
                current_drive = drive;
        }
        if (fdc != 1 && fdc != 0) {
-               printk("bad fdc value\n");
+               pr_info("bad fdc value\n");
                return;
        }
        set_dor(fdc, ~0, 8);
@@ -871,11 +858,10 @@ static void set_fdc(int drive)
 }
 
 /* locks the driver */
-static int _lock_fdc(int drive, int interruptible, int line)
+static int _lock_fdc(int drive, bool interruptible, int line)
 {
        if (!usage_count) {
-               printk(KERN_ERR
-                      "Trying to lock fdc while usage count=0 at line %d\n",
+               pr_err("Trying to lock fdc while usage count=0 at line %d\n",
                       line);
                return -1;
        }
@@ -904,15 +890,13 @@ static int _lock_fdc(int drive, int interruptible, int line)
        }
        command_status = FD_COMMAND_NONE;
 
-       __reschedule_timeout(drive, "lock fdc", 0);
+       __reschedule_timeout(drive, "lock fdc");
        set_fdc(drive);
        return 0;
 }
 
-#define lock_fdc(drive,interruptible) _lock_fdc(drive,interruptible, __LINE__)
-
-#define LOCK_FDC(drive,interruptible) \
-if (lock_fdc(drive,interruptible)) return -EINTR;
+#define lock_fdc(drive, interruptible)                 \
+       _lock_fdc(drive, interruptible, __LINE__)
 
 /* unlocks the driver */
 static inline void unlock_fdc(void)
@@ -924,7 +908,7 @@ static inline void unlock_fdc(void)
                DPRINT("FDC access conflict!\n");
 
        if (do_floppy)
-               DPRINT("device interrupt still active at FDC release: %p!\n",
+               DPRINT("device interrupt still active at FDC release: %pf!\n",
                       do_floppy);
        command_status = FD_COMMAND_NONE;
        spin_lock_irqsave(&floppy_lock, flags);
@@ -1003,7 +987,7 @@ static void empty(void)
 
 static DECLARE_WORK(floppy_work, NULL);
 
-static void schedule_bh(void (*handler) (void))
+static void schedule_bh(void (*handler)(void))
 {
        PREPARE_WORK(&floppy_work, (work_func_t)handler);
        schedule_work(&floppy_work);
@@ -1026,11 +1010,7 @@ static void cancel_activity(void)
  * transfer */
 static void fd_watchdog(void)
 {
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("calling disk change from watchdog\n");
-       }
-#endif
+       debug_dcl(DP->flags, "calling disk change from watchdog\n");
 
        if (disk_change(current_drive)) {
                DPRINT("disk removed during i/o\n");
@@ -1039,7 +1019,7 @@ static void fd_watchdog(void)
                reset_fdc();
        } else {
                del_timer(&fd_timer);
-               fd_timer.function = (timeout_fn) fd_watchdog;
+               fd_timer.function = (timeout_fn)fd_watchdog;
                fd_timer.expires = jiffies + HZ / 10;
                add_timer(&fd_timer);
        }
@@ -1105,25 +1085,23 @@ static void setup_DMA(void)
 {
        unsigned long f;
 
-#ifdef FLOPPY_SANITY_CHECK
        if (raw_cmd->length == 0) {
                int i;
 
-               printk("zero dma transfer size:");
+               pr_info("zero dma transfer size:");
                for (i = 0; i < raw_cmd->cmd_count; i++)
-                       printk("%x,", raw_cmd->cmd[i]);
-               printk("\n");
+                       pr_cont("%x,", raw_cmd->cmd[i]);
+               pr_cont("\n");
                cont->done(0);
                FDCS->reset = 1;
                return;
        }
        if (((unsigned long)raw_cmd->kernel_data) % 512) {
-               printk("non aligned address: %p\n", raw_cmd->kernel_data);
+               pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
                cont->done(0);
                FDCS->reset = 1;
                return;
        }
-#endif
        f = claim_dma_lock();
        fd_disable_dma();
 #ifdef fd_dma_setup
@@ -1165,7 +1143,7 @@ static int wait_til_ready(void)
                if (status & STATUS_READY)
                        return status;
        }
-       if (!initialising) {
+       if (initialized) {
                DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
                show_floppy();
        }
@@ -1176,22 +1154,21 @@ static int wait_til_ready(void)
 /* sends a command byte to the fdc */
 static int output_byte(char byte)
 {
-       int status;
+       int status = wait_til_ready();
 
-       if ((status = wait_til_ready()) < 0)
+       if (status < 0)
                return -1;
-       if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
+
+       if (is_ready_state(status)) {
                fd_outb(byte, FD_DATA);
-#ifdef FLOPPY_SANITY_CHECK
                output_log[output_log_pos].data = byte;
                output_log[output_log_pos].status = status;
                output_log[output_log_pos].jiffies = jiffies;
                output_log_pos = (output_log_pos + 1) % OLOGSIZE;
-#endif
                return 0;
        }
        FDCS->reset = 1;
-       if (!initialising) {
+       if (initialized) {
                DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
                       byte, fdc, status);
                show_floppy();
@@ -1199,8 +1176,6 @@ static int output_byte(char byte)
        return -1;
 }
 
-#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
-
 /* gets the response from the fdc */
 static int result(void)
 {
@@ -1208,14 +1183,13 @@ static int result(void)
        int status = 0;
 
        for (i = 0; i < MAX_REPLIES; i++) {
-               if ((status = wait_til_ready()) < 0)
+               status = wait_til_ready();
+               if (status < 0)
                        break;
                status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
                if ((status & ~STATUS_BUSY) == STATUS_READY) {
-#ifdef FLOPPY_SANITY_CHECK
                        resultjiffies = jiffies;
                        resultsize = i;
-#endif
                        return i;
                }
                if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
@@ -1223,10 +1197,9 @@ static int result(void)
                else
                        break;
        }
-       if (!initialising) {
-               DPRINT
-                   ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
-                    fdc, status, i);
+       if (initialized) {
+               DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
+                      fdc, status, i);
                show_floppy();
        }
        FDCS->reset = 1;
@@ -1237,12 +1210,14 @@ static int result(void)
 /* does the fdc need more output? */
 static int need_more_output(void)
 {
-       int status;
+       int status = wait_til_ready();
 
-       if ((status = wait_til_ready()) < 0)
+       if (status < 0)
                return -1;
-       if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
+
+       if (is_ready_state(status))
                return MORE_OUTPUT;
+
        return result();
 }
 
@@ -1264,9 +1239,12 @@ static inline void perpendicular_mode(void)
                default:
                        DPRINT("Invalid data rate for perpendicular mode!\n");
                        cont->done(0);
-                       FDCS->reset = 1;        /* convenient way to return to
-                                                * redo without to much hassle (deep
-                                                * stack et al. */
+                       FDCS->reset = 1;
+                                       /*
+                                        * convenient way to return to
+                                        * redo without too much hassle
+                                        * (deep stack et al.)
+                                        */
                        return;
                }
        } else
@@ -1366,9 +1344,9 @@ static void fdc_specify(void)
 
        /* Convert step rate from microseconds to milliseconds and 4 bits */
        srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
-       if (slow_floppy) {
+       if (slow_floppy)
                srt = srt / 4;
-       }
+
        SUPBOUND(srt, 0xf);
        INFBOUND(srt, 0);
 
@@ -1415,16 +1393,46 @@ static int fdc_dtr(void)
         * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
         */
        FDCS->dtr = raw_cmd->rate & 3;
-       return (fd_wait_for_completion(jiffies + 2UL * HZ / 100,
-                                      (timeout_fn) floppy_ready));
+       return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
+                                     (timeout_fn)floppy_ready);
 }                              /* fdc_dtr */
 
 static void tell_sector(void)
 {
-       printk(": track %d, head %d, sector %d, size %d",
-              R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
+       pr_cont(": track %d, head %d, sector %d, size %d",
+               R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
 }                              /* tell_sector */
 
+static void print_errors(void)
+{
+       DPRINT("");
+       if (ST0 & ST0_ECE) {
+               pr_cont("Recalibrate failed!");
+       } else if (ST2 & ST2_CRC) {
+               pr_cont("data CRC error");
+               tell_sector();
+       } else if (ST1 & ST1_CRC) {
+               pr_cont("CRC error");
+               tell_sector();
+       } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
+                  (ST2 & ST2_MAM)) {
+               if (!probing) {
+                       pr_cont("sector not found");
+                       tell_sector();
+               } else
+                       pr_cont("probe failed...");
+       } else if (ST2 & ST2_WC) {      /* seek error */
+               pr_cont("wrong cylinder");
+       } else if (ST2 & ST2_BC) {      /* cylinder marked as bad */
+               pr_cont("bad cylinder");
+       } else {
+               pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
+                       ST0, ST1, ST2);
+               tell_sector();
+       }
+       pr_cont("\n");
+}
+
 /*
  * OK, this error interpreting routine is called after a
  * DMA read/write has succeeded
@@ -1437,7 +1445,7 @@ static int interpret_errors(void)
        char bad;
 
        if (inr != 7) {
-               DPRINT("-- FDC reply error");
+               DPRINT("-- FDC reply error\n");
                FDCS->reset = 1;
                return 1;
        }
@@ -1450,43 +1458,17 @@ static int interpret_errors(void)
                bad = 1;
                if (ST1 & ST1_WP) {
                        DPRINT("Drive is write protected\n");
-                       CLEARF(FD_DISK_WRITABLE);
+                       clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
                        cont->done(0);
                        bad = 2;
                } else if (ST1 & ST1_ND) {
-                       SETF(FD_NEED_TWADDLE);
+                       set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
                } else if (ST1 & ST1_OR) {
                        if (DP->flags & FTD_MSG)
                                DPRINT("Over/Underrun - retrying\n");
                        bad = 0;
                } else if (*errors >= DP->max_errors.reporting) {
-                       DPRINT("");
-                       if (ST0 & ST0_ECE) {
-                               printk("Recalibrate failed!");
-                       } else if (ST2 & ST2_CRC) {
-                               printk("data CRC error");
-                               tell_sector();
-                       } else if (ST1 & ST1_CRC) {
-                               printk("CRC error");
-                               tell_sector();
-                       } else if ((ST1 & (ST1_MAM | ST1_ND))
-                                  || (ST2 & ST2_MAM)) {
-                               if (!probing) {
-                                       printk("sector not found");
-                                       tell_sector();
-                               } else
-                                       printk("probe failed...");
-                       } else if (ST2 & ST2_WC) {      /* seek error */
-                               printk("wrong cylinder");
-                       } else if (ST2 & ST2_BC) {      /* cylinder marked as bad */
-                               printk("bad cylinder");
-                       } else {
-                               printk
-                                   ("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
-                                    ST0, ST1, ST2);
-                               tell_sector();
-                       }
-                       printk("\n");
+                       print_errors();
                }
                if (ST2 & ST2_WC || ST2 & ST2_BC)
                        /* wrong cylinder => recal */
@@ -1531,9 +1513,9 @@ static void setup_rw_floppy(void)
                 */
                if (time_after(ready_date, jiffies + DP->select_delay)) {
                        ready_date -= DP->select_delay;
-                       function = (timeout_fn) floppy_start;
+                       function = (timeout_fn)floppy_start;
                } else
-                       function = (timeout_fn) setup_rw_floppy;
+                       function = (timeout_fn)setup_rw_floppy;
 
                /* wait until the floppy is spinning fast enough */
                if (fd_wait_for_completion(ready_date, function))
@@ -1551,7 +1533,7 @@ static void setup_rw_floppy(void)
        for (i = 0; i < raw_cmd->cmd_count; i++)
                r |= output_byte(raw_cmd->cmd[i]);
 
-       debugt("rw_command: ");
+       debugt(__func__, "rw_command");
 
        if (r) {
                cont->error();
@@ -1574,7 +1556,7 @@ static int blind_seek;
  */
 static void seek_interrupt(void)
 {
-       debugt("seek interrupt:");
+       debugt(__func__, "");
        if (inr != 2 || (ST0 & 0xF8) != 0x20) {
                DPRINT("seek failed\n");
                DRS->track = NEED_2_RECAL;
@@ -1583,14 +1565,11 @@ static void seek_interrupt(void)
                return;
        }
        if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
-#ifdef DCL_DEBUG
-               if (DP->flags & FD_DEBUG) {
-                       DPRINT
-                           ("clearing NEWCHANGE flag because of effective seek\n");
-                       DPRINT("jiffies=%lu\n", jiffies);
-               }
-#endif
-               CLEARF(FD_DISK_NEWCHANGE);      /* effective seek */
+               debug_dcl(DP->flags,
+                         "clearing NEWCHANGE flag because of effective seek\n");
+               debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
+               clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+                                       /* effective seek */
                DRS->select_date = jiffies;
        }
        DRS->track = ST1;
@@ -1599,26 +1578,23 @@ static void seek_interrupt(void)
 
 static void check_wp(void)
 {
-       if (TESTF(FD_VERIFY)) {
-               /* check write protection */
+       if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
+                                       /* check write protection */
                output_byte(FD_GETSTATUS);
                output_byte(UNIT(current_drive));
                if (result() != 1) {
                        FDCS->reset = 1;
                        return;
                }
-               CLEARF(FD_VERIFY);
-               CLEARF(FD_NEED_TWADDLE);
-#ifdef DCL_DEBUG
-               if (DP->flags & FD_DEBUG) {
-                       DPRINT("checking whether disk is write protected\n");
-                       DPRINT("wp=%x\n", ST3 & 0x40);
-               }
-#endif
+               clear_bit(FD_VERIFY_BIT, &DRS->flags);
+               clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
+               debug_dcl(DP->flags,
+                         "checking whether disk is write protected\n");
+               debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
                if (!(ST3 & 0x40))
-                       SETF(FD_DISK_WRITABLE);
+                       set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
                else
-                       CLEARF(FD_DISK_WRITABLE);
+                       clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
        }
 }
 
@@ -1628,19 +1604,15 @@ static void seek_floppy(void)
 
        blind_seek = 0;
 
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("calling disk change from seek\n");
-       }
-#endif
+       debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
 
-       if (!TESTF(FD_DISK_NEWCHANGE) &&
+       if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
            disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
                /* the media changed flag should be cleared after the seek.
                 * If it isn't, this means that there is really no disk in
                 * the drive.
                 */
-               SETF(FD_DISK_CHANGED);
+               set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
                cont->done(0);
                cont->redo();
                return;
@@ -1648,7 +1620,7 @@ static void seek_floppy(void)
        if (DRS->track <= NEED_1_RECAL) {
                recalibrate_floppy();
                return;
-       } else if (TESTF(FD_DISK_NEWCHANGE) &&
+       } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
                   (raw_cmd->flags & FD_RAW_NEED_DISK) &&
                   (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
                /* we seek to clear the media-changed condition. Does anybody
@@ -1677,19 +1649,22 @@ static void seek_floppy(void)
        do_floppy = seek_interrupt;
        output_byte(FD_SEEK);
        output_byte(UNIT(current_drive));
-       LAST_OUT(track);
-       debugt("seek command:");
+       if (output_byte(track) < 0) {
+               reset_fdc();
+               return;
+       }
+       debugt(__func__, "");
 }
 
 static void recal_interrupt(void)
 {
-       debugt("recal interrupt:");
+       debugt(__func__, "");
        if (inr != 2)
                FDCS->reset = 1;
        else if (ST0 & ST0_ECE) {
                switch (DRS->track) {
                case NEED_1_RECAL:
-                       debugt("recal interrupt need 1 recal:");
+                       debugt(__func__, "need 1 recal");
                        /* after a second recalibrate, we still haven't
                         * reached track 0. Probably no drive. Raise an
                         * error, as failing immediately might upset
@@ -1698,25 +1673,21 @@ static void recal_interrupt(void)
                        cont->redo();
                        return;
                case NEED_2_RECAL:
-                       debugt("recal interrupt need 2 recal:");
+                       debugt(__func__, "need 2 recal");
                        /* If we already did a recalibrate,
                         * and we are not at track 0, this
                         * means we have moved. (The only way
                         * not to move at recalibration is to
                         * be already at track 0.) Clear the
                         * new change flag */
-#ifdef DCL_DEBUG
-                       if (DP->flags & FD_DEBUG) {
-                               DPRINT
-                                   ("clearing NEWCHANGE flag because of second recalibrate\n");
-                       }
-#endif
+                       debug_dcl(DP->flags,
+                                 "clearing NEWCHANGE flag because of second recalibrate\n");
 
-                       CLEARF(FD_DISK_NEWCHANGE);
+                       clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
                        DRS->select_date = jiffies;
                        /* fall through */
                default:
-                       debugt("recal interrupt default:");
+                       debugt(__func__, "default");
                        /* Recalibrate moves the head by at
                         * most 80 steps. If after one
                         * recalibrate we don't have reached
@@ -1738,8 +1709,8 @@ static void print_result(char *message, int inr)
        DPRINT("%s ", message);
        if (inr >= 0)
                for (i = 0; i < inr; i++)
-                       printk("repl[%d]=%x ", i, reply_buffer[i]);
-       printk("\n");
+                       pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
+       pr_cont("\n");
 }
 
 /* interrupt handler. Note that this can be called externally on the Sparc */
@@ -1760,10 +1731,10 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
        do_floppy = NULL;
        if (fdc >= N_FDC || FDCS->address == -1) {
                /* we don't even know which FDC is the culprit */
-               printk("DOR0=%x\n", fdc_state[0].dor);
-               printk("floppy interrupt on bizarre fdc %d\n", fdc);
-               printk("handler=%p\n", handler);
-               is_alive("bizarre fdc");
+               pr_info("DOR0=%x\n", fdc_state[0].dor);
+               pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
+               pr_info("handler=%pf\n", handler);
+               is_alive(__func__, "bizarre fdc");
                return IRQ_NONE;
        }
 
@@ -1777,7 +1748,7 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
         * activity.
         */
 
-       do_print = !handler && print_unex && !initialising;
+       do_print = !handler && print_unex && initialized;
 
        inr = result();
        if (do_print)
@@ -1790,15 +1761,15 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
                        if (do_print)
                                print_result("sensei", inr);
                        max_sensei--;
-               } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
-                        && max_sensei);
+               } while ((ST0 & 0x83) != UNIT(current_drive) &&
+                        inr == 2 && max_sensei);
        }
        if (!handler) {
                FDCS->reset = 1;
                return IRQ_NONE;
        }
        schedule_bh(handler);
-       is_alive("normal interrupt end");
+       is_alive(__func__, "normal interrupt end");
 
        /* FIXME! Was it really for us? */
        return IRQ_HANDLED;
@@ -1806,10 +1777,11 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
 
 static void recalibrate_floppy(void)
 {
-       debugt("recalibrate floppy:");
+       debugt(__func__, "");
        do_floppy = recal_interrupt;
        output_byte(FD_RECALIBRATE);
-       LAST_OUT(UNIT(current_drive));
+       if (output_byte(UNIT(current_drive)) < 0)
+               reset_fdc();
 }
 
 /*
@@ -1817,10 +1789,10 @@ static void recalibrate_floppy(void)
  */
 static void reset_interrupt(void)
 {
-       debugt("reset interrupt:");
+       debugt(__func__, "");
        result();               /* get the status ready for set_fdc */
        if (FDCS->reset) {
-               printk("reset set in interrupt, calling %p\n", cont->error);
+               pr_info("reset set in interrupt, calling %pf\n", cont->error);
                cont->error();  /* a reset just after a reset. BAD! */
        }
        cont->redo();
@@ -1858,53 +1830,49 @@ static void show_floppy(void)
 {
        int i;
 
-       printk("\n");
-       printk("floppy driver state\n");
-       printk("-------------------\n");
-       printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
-              jiffies, interruptjiffies, jiffies - interruptjiffies,
-              lasthandler);
+       pr_info("\n");
+       pr_info("floppy driver state\n");
+       pr_info("-------------------\n");
+       pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
+               jiffies, interruptjiffies, jiffies - interruptjiffies,
+               lasthandler);
 
-#ifdef FLOPPY_SANITY_CHECK
-       printk("timeout_message=%s\n", timeout_message);
-       printk("last output bytes:\n");
+       pr_info("timeout_message=%s\n", timeout_message);
+       pr_info("last output bytes:\n");
        for (i = 0; i < OLOGSIZE; i++)
-               printk("%2x %2x %lu\n",
-                      output_log[(i + output_log_pos) % OLOGSIZE].data,
-                      output_log[(i + output_log_pos) % OLOGSIZE].status,
-                      output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
-       printk("last result at %lu\n", resultjiffies);
-       printk("last redo_fd_request at %lu\n", lastredo);
-       for (i = 0; i < resultsize; i++) {
-               printk("%2x ", reply_buffer[i]);
-       }
-       printk("\n");
-#endif
-
-       printk("status=%x\n", fd_inb(FD_STATUS));
-       printk("fdc_busy=%lu\n", fdc_busy);
+               pr_info("%2x %2x %lu\n",
+                       output_log[(i + output_log_pos) % OLOGSIZE].data,
+                       output_log[(i + output_log_pos) % OLOGSIZE].status,
+                       output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
+       pr_info("last result at %lu\n", resultjiffies);
+       pr_info("last redo_fd_request at %lu\n", lastredo);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
+                      reply_buffer, resultsize, true);
+
+       pr_info("status=%x\n", fd_inb(FD_STATUS));
+       pr_info("fdc_busy=%lu\n", fdc_busy);
        if (do_floppy)
-               printk("do_floppy=%p\n", do_floppy);
+               pr_info("do_floppy=%pf\n", do_floppy);
        if (work_pending(&floppy_work))
-               printk("floppy_work.func=%p\n", floppy_work.func);
+               pr_info("floppy_work.func=%pf\n", floppy_work.func);
        if (timer_pending(&fd_timer))
-               printk("fd_timer.function=%p\n", fd_timer.function);
+               pr_info("fd_timer.function=%pf\n", fd_timer.function);
        if (timer_pending(&fd_timeout)) {
-               printk("timer_function=%p\n", fd_timeout.function);
-               printk("expires=%lu\n", fd_timeout.expires - jiffies);
-               printk("now=%lu\n", jiffies);
-       }
-       printk("cont=%p\n", cont);
-       printk("current_req=%p\n", current_req);
-       printk("command_status=%d\n", command_status);
-       printk("\n");
+               pr_info("timer_function=%pf\n", fd_timeout.function);
+               pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
+               pr_info("now=%lu\n", jiffies);
+       }
+       pr_info("cont=%p\n", cont);
+       pr_info("current_req=%p\n", current_req);
+       pr_info("command_status=%d\n", command_status);
+       pr_info("\n");
 }
 
 static void floppy_shutdown(unsigned long data)
 {
        unsigned long flags;
 
-       if (!initialising)
+       if (initialized)
                show_floppy();
        cancel_activity();
 
@@ -1916,17 +1884,17 @@ static void floppy_shutdown(unsigned long data)
 
        /* avoid dma going to a random drive after shutdown */
 
-       if (!initialising)
+       if (initialized)
                DPRINT("floppy timeout called\n");
        FDCS->reset = 1;
        if (cont) {
                cont->done(0);
                cont->redo();   /* this will recall reset when needed */
        } else {
-               printk("no cont in shutdown!\n");
+               pr_info("no cont in shutdown!\n");
                process_fd_request();
        }
-       is_alive("floppy shutdown");
+       is_alive(__func__, "");
 }
 
 /* start motor, check media-changed condition and write protection */
@@ -1954,27 +1922,26 @@ static int start_motor(void (*function)(void))
        set_dor(fdc, mask, data);
 
        /* wait_for_completion also schedules reset if needed. */
-       return (fd_wait_for_completion(DRS->select_date + DP->select_delay,
-                                      (timeout_fn) function));
+       return fd_wait_for_completion(DRS->select_date + DP->select_delay,
+                                     (timeout_fn)function);
 }
 
 static void floppy_ready(void)
 {
-       CHECK_RESET;
+       if (FDCS->reset) {
+               reset_fdc();
+               return;
+       }
        if (start_motor(floppy_ready))
                return;
        if (fdc_dtr())
                return;
 
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("calling disk change from floppy_ready\n");
-       }
-#endif
+       debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
        if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
            disk_change(current_drive) && !DP->select_delay)
-               twaddle();      /* this clears the dcl on certain drive/controller
-                                * combinations */
+               twaddle();      /* this clears the dcl on certain
+                                * drive/controller combinations */
 
 #ifdef fd_chose_dma_mode
        if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
@@ -1998,15 +1965,11 @@ static void floppy_ready(void)
 
 static void floppy_start(void)
 {
-       reschedule_timeout(current_reqD, "floppy start", 0);
+       reschedule_timeout(current_reqD, "floppy start");
 
        scandrives();
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("setting NEWCHANGE in floppy_start\n");
-       }
-#endif
-       SETF(FD_DISK_NEWCHANGE);
+       debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
+       set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
        floppy_ready();
 }
 
@@ -2026,7 +1989,7 @@ static void floppy_start(void)
 
 static void do_wakeup(void)
 {
-       reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
+       reschedule_timeout(MAXTIMEOUT, "do wakeup");
        cont = NULL;
        command_status += 2;
        wake_up(&command_done);
@@ -2046,7 +2009,7 @@ static struct cont_t intr_cont = {
        .done           = (done_f)empty
 };
 
-static int wait_til_done(void (*handler)(void), int interruptible)
+static int wait_til_done(void (*handler)(void), bool interruptible)
 {
        int ret;
 
@@ -2064,7 +2027,7 @@ static int wait_til_done(void (*handler)(void), int interruptible)
                        if (command_status >= 2 || !NO_SIGNAL)
                                break;
 
-                       is_alive("wait_til_done");
+                       is_alive(__func__, "");
                        schedule();
                }
 
@@ -2180,9 +2143,9 @@ static void format_interrupt(void)
        cont->redo();
 }
 
-#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
-#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1))
+#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
 #define CT(x) ((x) | 0xc0)
+
 static void setup_format_params(int track)
 {
        int n;
@@ -2197,8 +2160,8 @@ static void setup_format_params(int track)
        raw_cmd = &default_raw_cmd;
        raw_cmd->track = track;
 
-       raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
-           FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
+       raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
+                         FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
        raw_cmd->rate = _floppy->rate & 0x43;
        raw_cmd->cmd_count = NR_F;
        COMMAND = FM_MODE(_floppy, FD_FORMAT);
@@ -2257,7 +2220,7 @@ static void redo_format(void)
        buffer_track = -1;
        setup_format_params(format_req.track << STRETCH(_floppy));
        floppy_start();
-       debugt("queue format request");
+       debugt(__func__, "queue format request");
 }
 
 static struct cont_t format_cont = {
@@ -2271,7 +2234,9 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
 {
        int ret;
 
-       LOCK_FDC(drive, 1);
+       if (lock_fdc(drive, true))
+               return -EINTR;
+
        set_floppy(drive);
        if (!_floppy ||
            _floppy->track > DP->tracks ||
@@ -2286,7 +2251,9 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
        format_errors = 0;
        cont = &format_cont;
        errors = &format_errors;
-       IWAIT(redo_format);
+       ret = wait_til_done(redo_format, true);
+       if (ret == -EINTR)
+               return -EINTR;
        process_fd_request();
        return ret;
 }
@@ -2320,12 +2287,14 @@ static void request_done(int uptodate)
        struct request *req = current_req;
        unsigned long flags;
        int block;
+       char msg[sizeof("request done ") + sizeof(int) * 3];
 
        probing = 0;
-       reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
+       snprintf(msg, sizeof(msg), "request done %d", uptodate);
+       reschedule_timeout(MAXTIMEOUT, msg);
 
        if (!req) {
-               printk("floppy.c: no request in request_done\n");
+               pr_info("floppy.c: no request in request_done\n");
                return;
        }
 
@@ -2377,7 +2346,7 @@ static void rw_interrupt(void)
                DRS->first_read_date = jiffies;
 
        nr_sectors = 0;
-       CODE2SIZE;
+       ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
 
        if (ST1 & ST1_EOC)
                eoc = 1;
@@ -2393,20 +2362,18 @@ static void rw_interrupt(void)
                       R_HEAD - HEAD) * SECT_PER_TRACK +
                      R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
 
-#ifdef FLOPPY_SANITY_CHECK
        if (nr_sectors / ssize >
            DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
                DPRINT("long rw: %x instead of %lx\n",
                       nr_sectors, current_count_sectors);
-               printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
-               printk("rh=%d h=%d\n", R_HEAD, HEAD);
-               printk("rt=%d t=%d\n", R_TRACK, TRACK);
-               printk("heads=%d eoc=%d\n", heads, eoc);
-               printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
-                      fsector_t, ssize);
-               printk("in_sector_offset=%d\n", in_sector_offset);
+               pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
+               pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
+               pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
+               pr_info("heads=%d eoc=%d\n", heads, eoc);
+               pr_info("spt=%d st=%d ss=%d\n",
+                       SECT_PER_TRACK, fsector_t, ssize);
+               pr_info("in_sector_offset=%d\n", in_sector_offset);
        }
-#endif
 
        nr_sectors -= in_sector_offset;
        INFBOUND(nr_sectors, 0);
@@ -2511,19 +2478,17 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                                              blk_rq_sectors(current_req));
 
        remaining = current_count_sectors << 9;
-#ifdef FLOPPY_SANITY_CHECK
        if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
                DPRINT("in copy buffer\n");
-               printk("current_count_sectors=%ld\n", current_count_sectors);
-               printk("remaining=%d\n", remaining >> 9);
-               printk("current_req->nr_sectors=%u\n",
-                      blk_rq_sectors(current_req));
-               printk("current_req->current_nr_sectors=%u\n",
-                      blk_rq_cur_sectors(current_req));
-               printk("max_sector=%d\n", max_sector);
-               printk("ssize=%d\n", ssize);
+               pr_info("current_count_sectors=%ld\n", current_count_sectors);
+               pr_info("remaining=%d\n", remaining >> 9);
+               pr_info("current_req->nr_sectors=%u\n",
+                       blk_rq_sectors(current_req));
+               pr_info("current_req->current_nr_sectors=%u\n",
+                       blk_rq_cur_sectors(current_req));
+               pr_info("max_sector=%d\n", max_sector);
+               pr_info("ssize=%d\n", ssize);
        }
-#endif
 
        buffer_max = max(max_sector, buffer_max);
 
@@ -2539,26 +2504,24 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                SUPBOUND(size, remaining);
 
                buffer = page_address(bv->bv_page) + bv->bv_offset;
-#ifdef FLOPPY_SANITY_CHECK
                if (dma_buffer + size >
                    floppy_track_buffer + (max_buffer_sectors << 10) ||
                    dma_buffer < floppy_track_buffer) {
                        DPRINT("buffer overrun in copy buffer %d\n",
-                              (int)((floppy_track_buffer -
-                                     dma_buffer) >> 9));
-                       printk("fsector_t=%d buffer_min=%d\n",
-                              fsector_t, buffer_min);
-                       printk("current_count_sectors=%ld\n",
-                              current_count_sectors);
+                              (int)((floppy_track_buffer - dma_buffer) >> 9));
+                       pr_info("fsector_t=%d buffer_min=%d\n",
+                               fsector_t, buffer_min);
+                       pr_info("current_count_sectors=%ld\n",
+                               current_count_sectors);
                        if (CT(COMMAND) == FD_READ)
-                               printk("read\n");
+                               pr_info("read\n");
                        if (CT(COMMAND) == FD_WRITE)
-                               printk("write\n");
+                               pr_info("write\n");
                        break;
                }
                if (((unsigned long)buffer) % 512)
                        DPRINT("%p buffer not aligned\n", buffer);
-#endif
+
                if (CT(COMMAND) == FD_READ)
                        memcpy(buffer, dma_buffer, size);
                else
@@ -2567,13 +2530,11 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                remaining -= size;
                dma_buffer += size;
        }
-#ifdef FLOPPY_SANITY_CHECK
        if (remaining) {
                if (remaining > 0)
                        max_sector -= remaining >> 9;
                DPRINT("weirdness: remaining %d\n", remaining >> 9);
        }
-#endif
 }
 
 /* work around a bug in pseudo DMA
@@ -2593,15 +2554,14 @@ static void virtualdmabug_workaround(void)
 
                hard_sectors = raw_cmd->length >> (7 + SIZECODE);
                end_sector = SECTOR + hard_sectors - 1;
-#ifdef FLOPPY_SANITY_CHECK
                if (end_sector > SECT_PER_TRACK) {
-                       printk("too many sectors %d > %d\n",
-                              end_sector, SECT_PER_TRACK);
+                       pr_info("too many sectors %d > %d\n",
+                               end_sector, SECT_PER_TRACK);
                        return;
                }
-#endif
-               SECT_PER_TRACK = end_sector;    /* make sure SECT_PER_TRACK points
-                                                * to end of transfer */
+               SECT_PER_TRACK = end_sector;
+                                       /* make sure SECT_PER_TRACK
+                                        * points to end of transfer */
        }
 }
 
@@ -2624,7 +2584,7 @@ static int make_raw_rw_request(void)
        int ssize;
 
        if (max_buffer_sectors == 0) {
-               printk("VFS: Block I/O scheduled on unopened device\n");
+               pr_info("VFS: Block I/O scheduled on unopened device\n");
                return 0;
        }
 
@@ -2641,7 +2601,7 @@ static int make_raw_rw_request(void)
                raw_cmd->flags |= FD_RAW_WRITE;
                COMMAND = FM_MODE(_floppy, FD_WRITE);
        } else {
-               DPRINT("make_raw_rw_request: unknown command\n");
+               DPRINT("%s: unknown command\n", __func__);
                return 0;
        }
 
@@ -2659,7 +2619,8 @@ static int make_raw_rw_request(void)
        HEAD = fsector_t / _floppy->sect;
 
        if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
-            TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
+            test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
+           fsector_t < _floppy->sect)
                max_sector = _floppy->sect;
 
        /* 2M disks have phantom sectors on the first track */
@@ -2685,7 +2646,7 @@ static int make_raw_rw_request(void)
        raw_cmd->track = TRACK << STRETCH(_floppy);
        DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
        GAP = _floppy->gap;
-       CODE2SIZE;
+       ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
        SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
        SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
            FD_SECTBASE(_floppy);
@@ -2730,8 +2691,10 @@ static int make_raw_rw_request(void)
                }
        } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
                if (CT(COMMAND) == FD_WRITE) {
-                       if (fsector_t + blk_rq_sectors(current_req) > ssize &&
-                           fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
+                       unsigned int sectors;
+
+                       sectors = fsector_t + blk_rq_sectors(current_req);
+                       if (sectors > ssize && sectors < ssize + ssize)
                                max_size = ssize + ssize;
                        else
                                max_size = ssize;
@@ -2752,12 +2715,10 @@ static int make_raw_rw_request(void)
                 * on a 64 bit machine!
                 */
                max_size = buffer_chain_size();
-               dma_limit =
-                   (MAX_DMA_ADDRESS -
-                    ((unsigned long)current_req->buffer)) >> 9;
-               if ((unsigned long)max_size > dma_limit) {
+               dma_limit = (MAX_DMA_ADDRESS -
+                            ((unsigned long)current_req->buffer)) >> 9;
+               if ((unsigned long)max_size > dma_limit)
                        max_size = dma_limit;
-               }
                /* 64 kb boundaries */
                if (CROSS_64KB(current_req->buffer, max_size << 9))
                        max_size = (K_64 -
@@ -2773,16 +2734,16 @@ static int make_raw_rw_request(void)
                 */
                if (!direct ||
                    (indirect * 2 > direct * 3 &&
-                    *errors < DP->max_errors.read_track && ((!probing
-                      || (DP->read_track & (1 << DRS->probed_format)))))) {
+                    *errors < DP->max_errors.read_track &&
+                    ((!probing ||
+                      (DP->read_track & (1 << DRS->probed_format)))))) {
                        max_size = blk_rq_sectors(current_req);
                } else {
                        raw_cmd->kernel_data = current_req->buffer;
                        raw_cmd->length = current_count_sectors << 9;
                        if (raw_cmd->length == 0) {
-                               DPRINT
-                                   ("zero dma transfer attempted from make_raw_request\n");
-                               DPRINT("indirect=%d direct=%d fsector_t=%d",
+                               DPRINT("%s: zero dma transfer attempted\n", __func__);
+                               DPRINT("indirect=%d direct=%d fsector_t=%d\n",
                                       indirect, direct, fsector_t);
                                return 0;
                        }
@@ -2802,25 +2763,22 @@ static int make_raw_rw_request(void)
            ((CT(COMMAND) == FD_READ ||
              (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
             max_sector > 2 * max_buffer_sectors + buffer_min &&
-            max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
-           /* not enough space */
-           ) {
+            max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
+               /* not enough space */
                buffer_track = -1;
                buffer_drive = current_drive;
                buffer_max = buffer_min = aligned_sector_t;
        }
        raw_cmd->kernel_data = floppy_track_buffer +
-           ((aligned_sector_t - buffer_min) << 9);
+               ((aligned_sector_t - buffer_min) << 9);
 
        if (CT(COMMAND) == FD_WRITE) {
                /* copy write buffer to track buffer.
                 * if we get here, we know that the write
                 * is either aligned or the data already in the buffer
                 * (buffer will be overwritten) */
-#ifdef FLOPPY_SANITY_CHECK
                if (in_sector_offset && buffer_track == -1)
                        DPRINT("internal error offset !=0 on write\n");
-#endif
                buffer_track = raw_cmd->track;
                buffer_drive = current_drive;
                copy_buffer(ssize, max_sector,
@@ -2834,7 +2792,6 @@ static int make_raw_rw_request(void)
        raw_cmd->length = in_sector_offset + current_count_sectors;
        raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
        raw_cmd->length <<= 9;
-#ifdef FLOPPY_SANITY_CHECK
        if ((raw_cmd->length < current_count_sectors << 9) ||
            (raw_cmd->kernel_data != current_req->buffer &&
             CT(COMMAND) == FD_WRITE &&
@@ -2845,19 +2802,19 @@ static int make_raw_rw_request(void)
                DPRINT("fractionary current count b=%lx s=%lx\n",
                       raw_cmd->length, current_count_sectors);
                if (raw_cmd->kernel_data != current_req->buffer)
-                       printk("addr=%d, length=%ld\n",
-                              (int)((raw_cmd->kernel_data -
-                                     floppy_track_buffer) >> 9),
-                              current_count_sectors);
-               printk("st=%d ast=%d mse=%d msi=%d\n",
-                      fsector_t, aligned_sector_t, max_sector, max_size);
-               printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
-               printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
-                      COMMAND, SECTOR, HEAD, TRACK);
-               printk("buffer drive=%d\n", buffer_drive);
-               printk("buffer track=%d\n", buffer_track);
-               printk("buffer_min=%d\n", buffer_min);
-               printk("buffer_max=%d\n", buffer_max);
+                       pr_info("addr=%d, length=%ld\n",
+                               (int)((raw_cmd->kernel_data -
+                                      floppy_track_buffer) >> 9),
+                               current_count_sectors);
+               pr_info("st=%d ast=%d mse=%d msi=%d\n",
+                       fsector_t, aligned_sector_t, max_sector, max_size);
+               pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
+               pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
+                       COMMAND, SECTOR, HEAD, TRACK);
+               pr_info("buffer drive=%d\n", buffer_drive);
+               pr_info("buffer track=%d\n", buffer_track);
+               pr_info("buffer_min=%d\n", buffer_min);
+               pr_info("buffer_max=%d\n", buffer_max);
                return 0;
        }
 
@@ -2868,14 +2825,14 @@ static int make_raw_rw_request(void)
                    raw_cmd->kernel_data + raw_cmd->length >
                    floppy_track_buffer + (max_buffer_sectors << 10)) {
                        DPRINT("buffer overrun in schedule dma\n");
-                       printk("fsector_t=%d buffer_min=%d current_count=%ld\n",
-                              fsector_t, buffer_min, raw_cmd->length >> 9);
-                       printk("current_count_sectors=%ld\n",
-                              current_count_sectors);
+                       pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
+                               fsector_t, buffer_min, raw_cmd->length >> 9);
+                       pr_info("current_count_sectors=%ld\n",
+                               current_count_sectors);
                        if (CT(COMMAND) == FD_READ)
-                               printk("read\n");
+                               pr_info("read\n");
                        if (CT(COMMAND) == FD_WRITE)
-                               printk("write\n");
+                               pr_info("write\n");
                        return 0;
                }
        } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
@@ -2884,14 +2841,13 @@ static int make_raw_rw_request(void)
                return 0;
        } else if (raw_cmd->length < current_count_sectors << 9) {
                DPRINT("more sectors than bytes\n");
-               printk("bytes=%ld\n", raw_cmd->length >> 9);
-               printk("sectors=%ld\n", current_count_sectors);
+               pr_info("bytes=%ld\n", raw_cmd->length >> 9);
+               pr_info("sectors=%ld\n", current_count_sectors);
        }
        if (raw_cmd->length == 0) {
                DPRINT("zero dma transfer attempted from make_raw_request\n");
                return 0;
        }
-#endif
 
        virtualdmabug_workaround();
        return 2;
@@ -2899,7 +2855,6 @@ static int make_raw_rw_request(void)
 
 static void redo_fd_request(void)
 {
-#define REPEAT {request_done(0); continue; }
        int drive;
        int tmp;
 
@@ -2907,63 +2862,63 @@ static void redo_fd_request(void)
        if (current_drive < N_DRIVE)
                floppy_off(current_drive);
 
-       for (;;) {
-               if (!current_req) {
-                       struct request *req;
-
-                       spin_lock_irq(floppy_queue->queue_lock);
-                       req = blk_fetch_request(floppy_queue);
-                       spin_unlock_irq(floppy_queue->queue_lock);
-                       if (!req) {
-                               do_floppy = NULL;
-                               unlock_fdc();
-                               return;
-                       }
-                       current_req = req;
-               }
-               drive = (long)current_req->rq_disk->private_data;
-               set_fdc(drive);
-               reschedule_timeout(current_reqD, "redo fd request", 0);
+do_request:
+       if (!current_req) {
+               struct request *req;
 
-               set_floppy(drive);
-               raw_cmd = &default_raw_cmd;
-               raw_cmd->flags = 0;
-               if (start_motor(redo_fd_request))
+               spin_lock_irq(floppy_queue->queue_lock);
+               req = blk_fetch_request(floppy_queue);
+               spin_unlock_irq(floppy_queue->queue_lock);
+               if (!req) {
+                       do_floppy = NULL;
+                       unlock_fdc();
                        return;
-               disk_change(current_drive);
-               if (test_bit(current_drive, &fake_change) ||
-                   TESTF(FD_DISK_CHANGED)) {
-                       DPRINT("disk absent or changed during operation\n");
-                       REPEAT;
-               }
-               if (!_floppy) { /* Autodetection */
-                       if (!probing) {
-                               DRS->probed_format = 0;
-                               if (next_valid_format()) {
-                                       DPRINT("no autodetectable formats\n");
-                                       _floppy = NULL;
-                                       REPEAT;
-                               }
-                       }
-                       probing = 1;
-                       _floppy =
-                           floppy_type + DP->autodetect[DRS->probed_format];
-               } else
-                       probing = 0;
-               errors = &(current_req->errors);
-               tmp = make_raw_rw_request();
-               if (tmp < 2) {
-                       request_done(tmp);
-                       continue;
                }
+               current_req = req;
+       }
+       drive = (long)current_req->rq_disk->private_data;
+       set_fdc(drive);
+       reschedule_timeout(current_reqD, "redo fd request");
 
-               if (TESTF(FD_NEED_TWADDLE))
-                       twaddle();
-               schedule_bh(floppy_start);
-               debugt("queue fd request");
+       set_floppy(drive);
+       raw_cmd = &default_raw_cmd;
+       raw_cmd->flags = 0;
+       if (start_motor(redo_fd_request))
                return;
+
+       disk_change(current_drive);
+       if (test_bit(current_drive, &fake_change) ||
+           test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
+               DPRINT("disk absent or changed during operation\n");
+               request_done(0);
+               goto do_request;
+       }
+       if (!_floppy) { /* Autodetection */
+               if (!probing) {
+                       DRS->probed_format = 0;
+                       if (next_valid_format()) {
+                               DPRINT("no autodetectable formats\n");
+                               _floppy = NULL;
+                               request_done(0);
+                               goto do_request;
+                       }
+               }
+               probing = 1;
+               _floppy = floppy_type + DP->autodetect[DRS->probed_format];
+       } else
+               probing = 0;
+       errors = &(current_req->errors);
+       tmp = make_raw_rw_request();
+       if (tmp < 2) {
+               request_done(tmp);
+               goto do_request;
        }
-#undef REPEAT
+
+       if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
+               twaddle();
+       schedule_bh(floppy_start);
+       debugt(__func__, "queue fd request");
+       return;
 }
 
 static struct cont_t rw_cont = {
@@ -2979,30 +2934,30 @@ static void process_fd_request(void)
        schedule_bh(redo_fd_request);
 }
 
-static void do_fd_request(struct request_queue * q)
+static void do_fd_request(struct request_queue *q)
 {
        if (max_buffer_sectors == 0) {
-               printk("VFS: do_fd_request called on non-open device\n");
+               pr_info("VFS: %s called on non-open device\n", __func__);
                return;
        }
 
        if (usage_count == 0) {
-               printk("warning: usage count=0, current_req=%p exiting\n",
-                      current_req);
-               printk("sect=%ld type=%x flags=%x\n",
-                      (long)blk_rq_pos(current_req), current_req->cmd_type,
-                      current_req->cmd_flags);
+               pr_info("warning: usage count=0, current_req=%p exiting\n",
+                       current_req);
+               pr_info("sect=%ld type=%x flags=%x\n",
+                       (long)blk_rq_pos(current_req), current_req->cmd_type,
+                       current_req->cmd_flags);
                return;
        }
        if (test_bit(0, &fdc_busy)) {
                /* fdc busy, this new request will be treated when the
                   current one is done */
-               is_alive("do fd request, old request running");
+               is_alive(__func__, "old request running");
                return;
        }
-       lock_fdc(MAXTIMEOUT, 0);
+       lock_fdc(MAXTIMEOUT, false);
        process_fd_request();
-       is_alive("do fd request");
+       is_alive(__func__, "");
 }
 
 static struct cont_t poll_cont = {
@@ -3012,24 +2967,18 @@ static struct cont_t poll_cont = {
        .done           = generic_done
 };
 
-static int poll_drive(int interruptible, int flag)
+static int poll_drive(bool interruptible, int flag)
 {
-       int ret;
-
        /* no auto-sense, just clear dcl */
        raw_cmd = &default_raw_cmd;
        raw_cmd->flags = flag;
        raw_cmd->track = 0;
        raw_cmd->cmd_count = 0;
        cont = &poll_cont;
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("setting NEWCHANGE in poll_drive\n");
-       }
-#endif
-       SETF(FD_DISK_NEWCHANGE);
-       WAIT(floppy_ready);
-       return ret;
+       debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
+       set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+
+       return wait_til_done(floppy_ready, interruptible);
 }
 
 /*
@@ -3039,7 +2988,7 @@ static int poll_drive(int interruptible, int flag)
 
 static void reset_intr(void)
 {
-       printk("weird, reset interrupt called\n");
+       pr_info("weird, reset interrupt called\n");
 }
 
 static struct cont_t reset_cont = {
@@ -3049,20 +2998,23 @@ static struct cont_t reset_cont = {
        .done           = generic_done
 };
 
-static int user_reset_fdc(int drive, int arg, int interruptible)
+static int user_reset_fdc(int drive, int arg, bool interruptible)
 {
        int ret;
 
-       ret = 0;
-       LOCK_FDC(drive, interruptible);
+       if (lock_fdc(drive, interruptible))
+               return -EINTR;
+
        if (arg == FD_RESET_ALWAYS)
                FDCS->reset = 1;
        if (FDCS->reset) {
                cont = &reset_cont;
-               WAIT(reset_fdc);
+               ret = wait_til_done(reset_fdc, interruptible);
+               if (ret == -EINTR)
+                       return -EINTR;
        }
        process_fd_request();
-       return ret;
+       return 0;
 }
 
 /*
@@ -3075,17 +3027,12 @@ static inline int fd_copyout(void __user *param, const void *address,
        return copy_to_user(param, address, size) ? -EFAULT : 0;
 }
 
-static inline int fd_copyin(void __user *param, void *address, unsigned long size)
+static inline int fd_copyin(void __user *param, void *address,
+                           unsigned long size)
 {
        return copy_from_user(address, param, size) ? -EFAULT : 0;
 }
 
-#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) ? -EFAULT : 0)
-#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) ? -EFAULT : 0)
-
-#define COPYOUT(x) ECALL(_COPYOUT(x))
-#define COPYIN(x) ECALL(_COPYIN(x))
-
 static inline const char *drive_name(int type, int drive)
 {
        struct floppy_struct *floppy;
@@ -3156,23 +3103,29 @@ static struct cont_t raw_cmd_cont = {
        .done           = raw_cmd_done
 };
 
-static inline int raw_cmd_copyout(int cmd, char __user *param,
+static inline int raw_cmd_copyout(int cmd, void __user *param,
                                  struct floppy_raw_cmd *ptr)
 {
        int ret;
 
        while (ptr) {
-               COPYOUT(*ptr);
+               ret = copy_to_user(param, ptr, sizeof(*ptr));
+               if (ret)
+                       return -EFAULT;
                param += sizeof(struct floppy_raw_cmd);
                if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
-                       if (ptr->length >= 0
-                           && ptr->length <= ptr->buffer_length)
-                               ECALL(fd_copyout
-                                     (ptr->data, ptr->kernel_data,
-                                      ptr->buffer_length - ptr->length));
+                       if (ptr->length >= 0 &&
+                           ptr->length <= ptr->buffer_length) {
+                               long length = ptr->buffer_length - ptr->length;
+                               ret = fd_copyout(ptr->data, ptr->kernel_data,
+                                                length);
+                               if (ret)
+                                       return ret;
+                       }
                }
                ptr = ptr->next;
        }
+
        return 0;
 }
 
@@ -3195,7 +3148,7 @@ static void raw_cmd_free(struct floppy_raw_cmd **ptr)
        }
 }
 
-static inline int raw_cmd_copyin(int cmd, char __user *param,
+static inline int raw_cmd_copyin(int cmd, void __user *param,
                                 struct floppy_raw_cmd **rcmd)
 {
        struct floppy_raw_cmd *ptr;
@@ -3203,17 +3156,19 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
        int i;
 
        *rcmd = NULL;
-       while (1) {
-               ptr = (struct floppy_raw_cmd *)
-                   kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
-               if (!ptr)
-                       return -ENOMEM;
-               *rcmd = ptr;
-               COPYIN(*ptr);
-               ptr->next = NULL;
-               ptr->buffer_length = 0;
-               param += sizeof(struct floppy_raw_cmd);
-               if (ptr->cmd_count > 33)
+
+loop:
+       ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
+       if (!ptr)
+               return -ENOMEM;
+       *rcmd = ptr;
+       ret = copy_from_user(ptr, param, sizeof(*ptr));
+       if (ret)
+               return -EFAULT;
+       ptr->next = NULL;
+       ptr->buffer_length = 0;
+       param += sizeof(struct floppy_raw_cmd);
+       if (ptr->cmd_count > 33)
                        /* the command may now also take up the space
                         * initially intended for the reply & the
                         * reply count. Needed for long 82078 commands
@@ -3222,31 +3177,35 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
                         * 16 bytes for a structure, you'll one day
                         * discover that you really need 17...
                         */
+               return -EINVAL;
+
+       for (i = 0; i < 16; i++)
+               ptr->reply[i] = 0;
+       ptr->resultcode = 0;
+       ptr->kernel_data = NULL;
+
+       if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
+               if (ptr->length <= 0)
                        return -EINVAL;
+               ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
+               fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
+               if (!ptr->kernel_data)
+                       return -ENOMEM;
+               ptr->buffer_length = ptr->length;
+       }
+       if (ptr->flags & FD_RAW_WRITE) {
+               ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
+               if (ret)
+                       return ret;
+       }
 
-               for (i = 0; i < 16; i++)
-                       ptr->reply[i] = 0;
-               ptr->resultcode = 0;
-               ptr->kernel_data = NULL;
-
-               if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
-                       if (ptr->length <= 0)
-                               return -EINVAL;
-                       ptr->kernel_data =
-                           (char *)fd_dma_mem_alloc(ptr->length);
-                       fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
-                       if (!ptr->kernel_data)
-                               return -ENOMEM;
-                       ptr->buffer_length = ptr->length;
-               }
-               if (ptr->flags & FD_RAW_WRITE)
-                       ECALL(fd_copyin(ptr->data, ptr->kernel_data,
-                                       ptr->length));
+       if (ptr->flags & FD_RAW_MORE) {
                rcmd = &(ptr->next);
-               if (!(ptr->flags & FD_RAW_MORE))
-                       return 0;
                ptr->rate &= 0x43;
+               goto loop;
        }
+
+       return 0;
 }
 
 static int raw_cmd_ioctl(int cmd, void __user *param)
@@ -3283,12 +3242,8 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
 
        raw_cmd = my_raw_cmd;
        cont = &raw_cmd_cont;
-       ret = wait_til_done(floppy_start, 1);
-#ifdef DCL_DEBUG
-       if (DP->flags & FD_DEBUG) {
-               DPRINT("calling disk change from raw_cmd ioctl\n");
-       }
-#endif
+       ret = wait_til_done(floppy_start, true);
+       debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
 
        if (ret != -EINTR && FDCS->reset)
                ret = -EIO;
@@ -3327,7 +3282,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                mutex_lock(&open_lock);
-               if (lock_fdc(drive, 1)) {
+               if (lock_fdc(drive, true)) {
                        mutex_unlock(&open_lock);
                        return -EINTR;
                }
@@ -3346,11 +3301,15 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                mutex_unlock(&open_lock);
        } else {
                int oldStretch;
-               LOCK_FDC(drive, 1);
-               if (cmd != FDDEFPRM)
+
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               if (cmd != FDDEFPRM) {
                        /* notice a disk change immediately, else
                         * we lose our settings immediately*/
-                       CALL(poll_drive(1, FD_RAW_NEED_DISK));
+                       if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+                               return -EINTR;
+               }
                oldStretch = g->stretch;
                user_params[drive] = *g;
                if (buffer_drive == drive)
@@ -3415,7 +3374,7 @@ static inline int normalize_ioctl(int *cmd, int *size)
                        *size = _IOC_SIZE(*cmd);
                        *cmd = ioctl_table[i];
                        if (*size > _IOC_SIZE(*cmd)) {
-                               printk("ioctl not yet supported\n");
+                               pr_info("ioctl not yet supported\n");
                                return -EFAULT;
                        }
                        return 0;
@@ -3429,8 +3388,10 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
        if (type)
                *g = &floppy_type[type];
        else {
-               LOCK_FDC(drive, 0);
-               CALL(poll_drive(0, 0));
+               if (lock_fdc(drive, false))
+                       return -EINTR;
+               if (poll_drive(false, 0) == -EINTR)
+                       return -EINTR;
                process_fd_request();
                *g = current_type[drive];
        }
@@ -3459,10 +3420,6 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                    unsigned long param)
 {
-#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
-#define OUT(c,x) case c: outparam = (const char *) (x); break
-#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
-
        int drive = (long)bdev->bd_disk->private_data;
        int type = ITYPE(UDRS->fd_device);
        int i;
@@ -3474,26 +3431,28 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                struct floppy_max_errors max_errors;
                struct floppy_drive_params dp;
        } inparam;              /* parameters coming from user space */
-       const char *outparam;   /* parameters passed back to user space */
+       const void *outparam;   /* parameters passed back to user space */
 
        /* convert compatibility eject ioctls into floppy eject ioctl.
         * We do this in order to provide a means to eject floppy disks before
         * installing the new fdutils package */
        if (cmd == CDROMEJECT ||        /* CD-ROM eject */
-           cmd == 0x6470 /* SunOS floppy eject */ ) {
+           cmd == 0x6470) {            /* SunOS floppy eject */
                DPRINT("obsolete eject ioctl\n");
                DPRINT("please use floppycontrol --eject\n");
                cmd = FDEJECT;
        }
 
-       /* convert the old style command into a new style command */
-       if ((cmd & 0xff00) == 0x0200) {
-               ECALL(normalize_ioctl(&cmd, &size));
-       } else
+       if (!((cmd & 0xff00) == 0x0200))
                return -EINVAL;
 
+       /* convert the old style command into a new style command */
+       ret = normalize_ioctl(&cmd, &size);
+       if (ret)
+               return ret;
+
        /* permission checks */
-       if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
+       if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
            ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
                return -EPERM;
 
@@ -3501,129 +3460,142 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                return -EINVAL;
 
        /* copyin */
-       CLEARSTRUCT(&inparam);
-       if (_IOC_DIR(cmd) & _IOC_WRITE)
-           ECALL(fd_copyin((void __user *)param, &inparam, size))
-
-               switch (cmd) {
-               case FDEJECT:
-                       if (UDRS->fd_ref != 1)
-                               /* somebody else has this drive open */
-                               return -EBUSY;
-                       LOCK_FDC(drive, 1);
-
-                       /* do the actual eject. Fails on
-                        * non-Sparc architectures */
-                       ret = fd_eject(UNIT(drive));
-
-                       USETF(FD_DISK_CHANGED);
-                       USETF(FD_VERIFY);
-                       process_fd_request();
+       memset(&inparam, 0, sizeof(inparam));
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               ret = fd_copyin((void __user *)param, &inparam, size);
+               if (ret)
                        return ret;
-               case FDCLRPRM:
-                       LOCK_FDC(drive, 1);
-                       current_type[drive] = NULL;
-                       floppy_sizes[drive] = MAX_DISK_SIZE << 1;
-                       UDRS->keep_data = 0;
-                       return invalidate_drive(bdev);
-               case FDSETPRM:
-               case FDDEFPRM:
-                       return set_geometry(cmd, &inparam.g,
-                                           drive, type, bdev);
-               case FDGETPRM:
-                       ECALL(get_floppy_geometry(drive, type,
-                                                 (struct floppy_struct **)
-                                                 &outparam));
-                       break;
-
-               case FDMSGON:
-                       UDP->flags |= FTD_MSG;
-                       return 0;
-               case FDMSGOFF:
-                       UDP->flags &= ~FTD_MSG;
-                       return 0;
-
-               case FDFMTBEG:
-                       LOCK_FDC(drive, 1);
-                       CALL(poll_drive(1, FD_RAW_NEED_DISK));
-                       ret = UDRS->flags;
-                       process_fd_request();
-                       if (ret & FD_VERIFY)
-                               return -ENODEV;
-                       if (!(ret & FD_DISK_WRITABLE))
-                               return -EROFS;
-                       return 0;
-               case FDFMTTRK:
-                       if (UDRS->fd_ref != 1)
-                               return -EBUSY;
-                       return do_format(drive, &inparam.f);
-               case FDFMTEND:
-               case FDFLUSH:
-                       LOCK_FDC(drive, 1);
-                       return invalidate_drive(bdev);
-
-               case FDSETEMSGTRESH:
-                       UDP->max_errors.reporting =
-                           (unsigned short)(param & 0x0f);
-                       return 0;
-                       OUT(FDGETMAXERRS, &UDP->max_errors);
-                       IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
-
-               case FDGETDRVTYP:
-                       outparam = drive_name(type, drive);
-                       SUPBOUND(size, strlen(outparam) + 1);
-                       break;
-
-                       IN(FDSETDRVPRM, UDP, dp);
-                       OUT(FDGETDRVPRM, UDP);
-
-               case FDPOLLDRVSTAT:
-                       LOCK_FDC(drive, 1);
-                       CALL(poll_drive(1, FD_RAW_NEED_DISK));
-                       process_fd_request();
-                       /* fall through */
-                       OUT(FDGETDRVSTAT, UDRS);
-
-               case FDRESET:
-                       return user_reset_fdc(drive, (int)param, 1);
-
-                       OUT(FDGETFDCSTAT, UFDCS);
+       }
 
-               case FDWERRORCLR:
-                       CLEARSTRUCT(UDRWE);
-                       return 0;
-                       OUT(FDWERRORGET, UDRWE);
-
-               case FDRAWCMD:
-                       if (type)
-                               return -EINVAL;
-                       LOCK_FDC(drive, 1);
-                       set_floppy(drive);
-                       CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
-                       process_fd_request();
-                       return i;
+       switch (cmd) {
+       case FDEJECT:
+               if (UDRS->fd_ref != 1)
+                       /* somebody else has this drive open */
+                       return -EBUSY;
+               if (lock_fdc(drive, true))
+                       return -EINTR;
 
-               case FDTWADDLE:
-                       LOCK_FDC(drive, 1);
-                       twaddle();
-                       process_fd_request();
-                       return 0;
+               /* do the actual eject. Fails on
+                * non-Sparc architectures */
+               ret = fd_eject(UNIT(drive));
 
-               default:
+               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+               set_bit(FD_VERIFY_BIT, &UDRS->flags);
+               process_fd_request();
+               return ret;
+       case FDCLRPRM:
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               current_type[drive] = NULL;
+               floppy_sizes[drive] = MAX_DISK_SIZE << 1;
+               UDRS->keep_data = 0;
+               return invalidate_drive(bdev);
+       case FDSETPRM:
+       case FDDEFPRM:
+               return set_geometry(cmd, &inparam.g, drive, type, bdev);
+       case FDGETPRM:
+               ret = get_floppy_geometry(drive, type,
+                                         (struct floppy_struct **)&outparam);
+               if (ret)
+                       return ret;
+               break;
+       case FDMSGON:
+               UDP->flags |= FTD_MSG;
+               return 0;
+       case FDMSGOFF:
+               UDP->flags &= ~FTD_MSG;
+               return 0;
+       case FDFMTBEG:
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+                       return -EINTR;
+               ret = UDRS->flags;
+               process_fd_request();
+               if (ret & FD_VERIFY)
+                       return -ENODEV;
+               if (!(ret & FD_DISK_WRITABLE))
+                       return -EROFS;
+               return 0;
+       case FDFMTTRK:
+               if (UDRS->fd_ref != 1)
+                       return -EBUSY;
+               return do_format(drive, &inparam.f);
+       case FDFMTEND:
+       case FDFLUSH:
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               return invalidate_drive(bdev);
+       case FDSETEMSGTRESH:
+               UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
+               return 0;
+       case FDGETMAXERRS:
+               outparam = &UDP->max_errors;
+               break;
+       case FDSETMAXERRS:
+               UDP->max_errors = inparam.max_errors;
+               break;
+       case FDGETDRVTYP:
+               outparam = drive_name(type, drive);
+               SUPBOUND(size, strlen((const char *)outparam) + 1);
+               break;
+       case FDSETDRVPRM:
+               *UDP = inparam.dp;
+               break;
+       case FDGETDRVPRM:
+               outparam = UDP;
+               break;
+       case FDPOLLDRVSTAT:
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+                       return -EINTR;
+               process_fd_request();
+               /* fall through */
+       case FDGETDRVSTAT:
+               outparam = UDRS;
+               break;
+       case FDRESET:
+               return user_reset_fdc(drive, (int)param, true);
+       case FDGETFDCSTAT:
+               outparam = UFDCS;
+               break;
+       case FDWERRORCLR:
+               memset(UDRWE, 0, sizeof(*UDRWE));
+               return 0;
+       case FDWERRORGET:
+               outparam = UDRWE;
+               break;
+       case FDRAWCMD:
+               if (type)
                        return -EINVAL;
-               }
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               set_floppy(drive);
+               i = raw_cmd_ioctl(cmd, (void __user *)param);
+               if (i == -EINTR)
+                       return -EINTR;
+               process_fd_request();
+               return i;
+       case FDTWADDLE:
+               if (lock_fdc(drive, true))
+                       return -EINTR;
+               twaddle();
+               process_fd_request();
+               return 0;
+       default:
+               return -EINVAL;
+       }
 
        if (_IOC_DIR(cmd) & _IOC_READ)
                return fd_copyout((void __user *)param, outparam, size);
-       else
-               return 0;
-#undef OUT
-#undef IN
+
+       return 0;
 }
 
 static void __init config_types(void)
 {
-       int first = 1;
+       bool has_drive = false;
        int drive;
 
        /* read drive info out of physical CMOS */
@@ -3655,17 +3627,22 @@ static void __init config_types(void)
                        name = temparea;
                }
                if (name) {
-                       const char *prepend = ",";
-                       if (first) {
-                               prepend = KERN_INFO "Floppy drive(s):";
-                               first = 0;
+                       const char *prepend;
+                       if (!has_drive) {
+                               prepend = "";
+                               has_drive = true;
+                               pr_info("Floppy drive(s):");
+                       } else {
+                               prepend = ",";
                        }
-                       printk("%s fd%d is %s", prepend, drive, name);
+
+                       pr_cont("%s fd%d is %s", prepend, drive, name);
                }
                *UDP = *params;
        }
-       if (!first)
-               printk("\n");
+
+       if (has_drive)
+               pr_cont("\n");
 }
 
 static int floppy_release(struct gendisk *disk, fmode_t mode)
@@ -3705,8 +3682,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                goto out2;
 
        if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
-               USETF(FD_DISK_CHANGED);
-               USETF(FD_VERIFY);
+               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+               set_bit(FD_VERIFY_BIT, &UDRS->flags);
        }
 
        if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
@@ -3735,9 +3712,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                        INFBOUND(try, 16);
                        tmp = (char *)fd_dma_mem_alloc(1024 * try);
                }
-               if (!tmp && !floppy_track_buffer) {
+               if (!tmp && !floppy_track_buffer)
                        fallback_on_nodma_alloc(&tmp, 2048 * try);
-               }
                if (!tmp && !floppy_track_buffer) {
                        DPRINT("Unable to allocate DMA memory\n");
                        goto out;
@@ -3767,11 +3743,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                if (mode & (FMODE_READ|FMODE_WRITE)) {
                        UDRS->last_checked = 0;
                        check_disk_change(bdev);
-                       if (UTESTF(FD_DISK_CHANGED))
+                       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
                                goto out;
                }
                res = -EROFS;
-               if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
+               if ((mode & FMODE_WRITE) &&
+                   !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
                        goto out;
        }
        mutex_unlock(&open_lock);
@@ -3795,17 +3772,18 @@ static int check_floppy_change(struct gendisk *disk)
 {
        int drive = (long)disk->private_data;
 
-       if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
+       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+           test_bit(FD_VERIFY_BIT, &UDRS->flags))
                return 1;
 
        if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
-               lock_fdc(drive, 0);
-               poll_drive(0, 0);
+               lock_fdc(drive, false);
+               poll_drive(false, 0);
                process_fd_request();
        }
 
-       if (UTESTF(FD_DISK_CHANGED) ||
-           UTESTF(FD_VERIFY) ||
+       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+           test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
            test_bit(drive, &fake_change) ||
            (!ITYPE(UDRS->fd_device) && !current_type[drive]))
                return 1;
@@ -3818,8 +3796,7 @@ static int check_floppy_change(struct gendisk *disk)
  * a disk in the drive, and whether that disk is writable.
  */
 
-static void floppy_rb0_complete(struct bio *bio,
-                              int err)
+static void floppy_rb0_complete(struct bio *bio, int err)
 {
        complete((struct completion *)bio->bi_private);
 }
@@ -3877,14 +3854,16 @@ static int floppy_revalidate(struct gendisk *disk)
        int cf;
        int res = 0;
 
-       if (UTESTF(FD_DISK_CHANGED) ||
-           UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
+       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+           test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
+           test_bit(drive, &fake_change) || NO_GEOM) {
                if (usage_count == 0) {
-                       printk("VFS: revalidate called on non-open device.\n");
+                       pr_info("VFS: revalidate called on non-open device.\n");
                        return -EFAULT;
                }
-               lock_fdc(drive, 0);
-               cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
+               lock_fdc(drive, false);
+               cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+                     test_bit(FD_VERIFY_BIT, &UDRS->flags));
                if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
                        process_fd_request();   /*already done by another thread */
                        return 0;
@@ -3894,7 +3873,7 @@ static int floppy_revalidate(struct gendisk *disk)
                if (buffer_drive == drive)
                        buffer_track = -1;
                clear_bit(drive, &fake_change);
-               UCLEARF(FD_DISK_CHANGED);
+               clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
                if (cf)
                        UDRS->generation++;
                if (NO_GEOM) {
@@ -3902,7 +3881,7 @@ static int floppy_revalidate(struct gendisk *disk)
                        res = __floppy_read_block_0(opened_bdev[drive]);
                } else {
                        if (cf)
-                               poll_drive(0, FD_RAW_NEED_DISK);
+                               poll_drive(false, FD_RAW_NEED_DISK);
                        process_fd_request();
                }
        }
@@ -3934,21 +3913,21 @@ static char __init get_fdc_version(void)
        output_byte(FD_DUMPREGS);       /* 82072 and better know DUMPREGS */
        if (FDCS->reset)
                return FDC_NONE;
-       if ((r = result()) <= 0x00)
+       r = result();
+       if (r <= 0x00)
                return FDC_NONE;        /* No FDC present ??? */
        if ((r == 1) && (reply_buffer[0] == 0x80)) {
-               printk(KERN_INFO "FDC %d is an 8272A\n", fdc);
+               pr_info("FDC %d is an 8272A\n", fdc);
                return FDC_8272A;       /* 8272a/765 don't know DUMPREGS */
        }
        if (r != 10) {
-               printk
-                   ("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
-                    fdc, r);
+               pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
+                       fdc, r);
                return FDC_UNKNOWN;
        }
 
        if (!fdc_configure()) {
-               printk(KERN_INFO "FDC %d is an 82072\n", fdc);
+               pr_info("FDC %d is an 82072\n", fdc);
                return FDC_82072;       /* 82072 doesn't know CONFIGURE */
        }
 
@@ -3956,52 +3935,50 @@ static char __init get_fdc_version(void)
        if (need_more_output() == MORE_OUTPUT) {
                output_byte(0);
        } else {
-               printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
+               pr_info("FDC %d is an 82072A\n", fdc);
                return FDC_82072A;      /* 82072A as found on Sparcs. */
        }
 
        output_byte(FD_UNLOCK);
        r = result();
        if ((r == 1) && (reply_buffer[0] == 0x80)) {
-               printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
-               return FDC_82077_ORIG;  /* Pre-1991 82077, doesn't know 
+               pr_info("FDC %d is a pre-1991 82077\n", fdc);
+               return FDC_82077_ORIG;  /* Pre-1991 82077, doesn't know
                                         * LOCK/UNLOCK */
        }
        if ((r != 1) || (reply_buffer[0] != 0x00)) {
-               printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
-                      fdc, r);
+               pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
+                       fdc, r);
                return FDC_UNKNOWN;
        }
        output_byte(FD_PARTID);
        r = result();
        if (r != 1) {
-               printk("FDC %d init: PARTID: unexpected return of %d bytes.\n",
-                      fdc, r);
+               pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
+                       fdc, r);
                return FDC_UNKNOWN;
        }
        if (reply_buffer[0] == 0x80) {
-               printk(KERN_INFO "FDC %d is a post-1991 82077\n", fdc);
+               pr_info("FDC %d is a post-1991 82077\n", fdc);
                return FDC_82077;       /* Revised 82077AA passes all the tests */
        }
        switch (reply_buffer[0] >> 5) {
        case 0x0:
                /* Either a 82078-1 or a 82078SL running at 5Volt */
-               printk(KERN_INFO "FDC %d is an 82078.\n", fdc);
+               pr_info("FDC %d is an 82078.\n", fdc);
                return FDC_82078;
        case 0x1:
-               printk(KERN_INFO "FDC %d is a 44pin 82078\n", fdc);
+               pr_info("FDC %d is a 44pin 82078\n", fdc);
                return FDC_82078;
        case 0x2:
-               printk(KERN_INFO "FDC %d is a S82078B\n", fdc);
+               pr_info("FDC %d is a S82078B\n", fdc);
                return FDC_S82078B;
        case 0x3:
-               printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n",
-                      fdc);
+               pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
                return FDC_87306;
        default:
-               printk(KERN_INFO
-                      "FDC %d init: 82078 variant with unknown PARTID=%d.\n",
-                      fdc, reply_buffer[0] >> 5);
+               pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
+                       fdc, reply_buffer[0] >> 5);
                return FDC_82078_UNKN;
        }
 }                              /* get_fdc_version */
@@ -4113,9 +4090,9 @@ static int __init floppy_setup(char *str)
                                else
                                        param = config_params[i].def_param;
                                if (config_params[i].fn)
-                                       config_params[i].
-                                           fn(ints, param,
-                                              config_params[i].param2);
+                                       config_params[i].fn(ints, param,
+                                                           config_params[i].
+                                                           param2);
                                if (config_params[i].var) {
                                        DPRINT("%s=%d\n", str, param);
                                        *config_params[i].var = param;
@@ -4129,8 +4106,8 @@ static int __init floppy_setup(char *str)
 
                DPRINT("allowed options are:");
                for (i = 0; i < ARRAY_SIZE(config_params); i++)
-                       printk(" %s", config_params[i].name);
-               printk("\n");
+                       pr_cont(" %s", config_params[i].name);
+               pr_cont("\n");
        } else
                DPRINT("botched floppy option\n");
        DPRINT("Read Documentation/blockdev/floppy.txt\n");
@@ -4148,7 +4125,8 @@ static ssize_t floppy_cmos_show(struct device *dev,
        drive = p->id;
        return sprintf(buf, "%X\n", UDP->cmos);
 }
-DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
+
+DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
 
 static void floppy_device_release(struct device *dev)
 {
@@ -4160,7 +4138,7 @@ static int floppy_resume(struct device *dev)
 
        for (fdc = 0; fdc < N_FDC; fdc++)
                if (FDCS->address != -1)
-                       user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+                       user_reset_fdc(-1, FD_RESET_ALWAYS, false);
 
        return 0;
 }
@@ -4172,8 +4150,8 @@ static const struct dev_pm_ops floppy_pm_ops = {
 
 static struct platform_driver floppy_driver = {
        .driver = {
-               .name = "floppy",
-               .pm = &floppy_pm_ops,
+                  .name = "floppy",
+                  .pm = &floppy_pm_ops,
        },
 };
 
@@ -4245,16 +4223,16 @@ static int __init floppy_init(void)
                else
                        floppy_sizes[i] = MAX_DISK_SIZE << 1;
 
-       reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
+       reschedule_timeout(MAXTIMEOUT, "floppy init");
        config_types();
 
        for (i = 0; i < N_FDC; i++) {
                fdc = i;
-               CLEARSTRUCT(FDCS);
+               memset(FDCS, 0, sizeof(*FDCS));
                FDCS->dtr = -1;
                FDCS->dor = 0x4;
 #if defined(__sparc__) || defined(__mc68000__)
-               /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
+       /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
 #ifdef __mc68000__
                if (MACH_IS_SUN3X)
 #endif
@@ -4283,11 +4261,11 @@ static int __init floppy_init(void)
 
        /* initialise drive state */
        for (drive = 0; drive < N_DRIVE; drive++) {
-               CLEARSTRUCT(UDRS);
-               CLEARSTRUCT(UDRWE);
-               USETF(FD_DISK_NEWCHANGE);
-               USETF(FD_DISK_CHANGED);
-               USETF(FD_VERIFY);
+               memset(UDRS, 0, sizeof(*UDRS));
+               memset(UDRWE, 0, sizeof(*UDRWE));
+               set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
+               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+               set_bit(FD_VERIFY_BIT, &UDRS->flags);
                UDRS->fd_device = -1;
                floppy_track_buffer = NULL;
                max_buffer_sectors = 0;
@@ -4307,7 +4285,7 @@ static int __init floppy_init(void)
                if (FDCS->address == -1)
                        continue;
                FDCS->rawcmd = 2;
-               if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
+               if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
                        floppy_release_regions(fdc);
                        FDCS->address = -1;
@@ -4330,12 +4308,12 @@ static int __init floppy_init(void)
                 * properly, so force a reset for the standard FDC clones,
                 * to avoid interrupt garbage.
                 */
-               user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+               user_reset_fdc(-1, FD_RESET_ALWAYS, false);
        }
        fdc = 0;
        del_timer(&fd_timeout);
        current_drive = 0;
-       initialising = 0;
+       initialized = true;
        if (have_no_fdc) {
                DPRINT("no floppy controllers found\n");
                err = have_no_fdc;
@@ -4356,7 +4334,8 @@ static int __init floppy_init(void)
                if (err)
                        goto out_flush_work;
 
-               err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+               err = device_create_file(&floppy_device[drive].dev,
+                                        &dev_attr_cmos);
                if (err)
                        goto out_unreg_platform_dev;
 
@@ -4420,8 +4399,10 @@ static int floppy_request_regions(int fdc)
        const struct io_region *p;
 
        for (p = io_regions; p < ARRAY_END(io_regions); p++) {
-               if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
-                       DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
+               if (!request_region(FDCS->address + p->offset,
+                                   p->size, "floppy")) {
+                       DPRINT("Floppy io-port 0x%04lx in use\n",
+                              FDCS->address + p->offset);
                        floppy_release_allocated_regions(fdc, p);
                        return -EBUSY;
                }
@@ -4512,10 +4493,8 @@ cleanup:
 static void floppy_release_irq_and_dma(void)
 {
        int old_fdc;
-#ifdef FLOPPY_SANITY_CHECK
 #ifndef __sparc__
        int drive;
-#endif
 #endif
        long tmpsize;
        unsigned long tmpaddr;
@@ -4547,20 +4526,18 @@ static void floppy_release_irq_and_dma(void)
                buffer_min = buffer_max = -1;
                fd_dma_mem_free(tmpaddr, tmpsize);
        }
-#ifdef FLOPPY_SANITY_CHECK
 #ifndef __sparc__
        for (drive = 0; drive < N_FDC * 4; drive++)
                if (timer_pending(motor_off_timer + drive))
-                       printk("motor off timer %d still active\n", drive);
+                       pr_info("motor off timer %d still active\n", drive);
 #endif
 
        if (timer_pending(&fd_timeout))
-               printk("floppy timer still active:%s\n", timeout_message);
+               pr_info("floppy timer still active:%s\n", timeout_message);
        if (timer_pending(&fd_timer))
-               printk("auxiliary floppy timer still active\n");
+               pr_info("auxiliary floppy timer still active\n");
        if (work_pending(&floppy_work))
-               printk("work still pending\n");
-#endif
+               pr_info("work still pending\n");
        old_fdc = fdc;
        for (fdc = 0; fdc < N_FDC; fdc++)
                if (FDCS->address != -1)
@@ -4577,7 +4554,9 @@ static void __init parse_floppy_cfg_string(char *cfg)
        char *ptr;
 
        while (*cfg) {
-               for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++) ;
+               ptr = cfg;
+               while (*cfg && *cfg != ' ' && *cfg != '\t')
+                       cfg++;
                if (*cfg) {
                        *cfg = '\0';
                        cfg++;
@@ -4625,6 +4604,7 @@ static void __exit floppy_module_exit(void)
        /* eject disk, if any */
        fd_eject(0);
 }
+
 module_exit(floppy_module_exit);
 
 module_param(floppy, charp, 0);
@@ -4636,9 +4616,10 @@ MODULE_LICENSE("GPL");
 
 /* This doesn't actually get used other than for module information */
 static const struct pnp_device_id floppy_pnpids[] = {
-       { "PNP0700", 0 },
-       { }
+       {"PNP0700", 0},
+       {}
 };
+
 MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
 
 #else
index a808b15..eb2091a 100644 (file)
@@ -476,7 +476,9 @@ static void class_osdblk_release(struct class *cls)
        kfree(cls);
 }
 
-static ssize_t class_osdblk_list(struct class *c, char *data)
+static ssize_t class_osdblk_list(struct class *c,
+                               struct class_attribute *attr,
+                               char *data)
 {
        int n = 0;
        struct list_head *tmp;
@@ -500,7 +502,9 @@ static ssize_t class_osdblk_list(struct class *c, char *data)
        return n;
 }
 
-static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count)
+static ssize_t class_osdblk_add(struct class *c,
+                               struct class_attribute *attr,
+                               const char *buf, size_t count)
 {
        struct osdblk_device *osdev;
        ssize_t rc;
@@ -592,7 +596,9 @@ err_out_mod:
        return rc;
 }
 
-static ssize_t class_osdblk_remove(struct class *c, const char *buf,
+static ssize_t class_osdblk_remove(struct class *c,
+                                       struct class_attribute *attr,
+                                       const char *buf,
                                        size_t count)
 {
        struct osdblk_device *osdev = NULL;
index b72935b..39c8514 100644 (file)
@@ -284,7 +284,7 @@ static ssize_t kobj_pkt_store(struct kobject *kobj,
        return len;
 }
 
-static struct sysfs_ops kobj_pkt_ops = {
+static const struct sysfs_ops kobj_pkt_ops = {
        .show = kobj_pkt_show,
        .store = kobj_pkt_store
 };
@@ -337,7 +337,9 @@ static void class_pktcdvd_release(struct class *cls)
 {
        kfree(cls);
 }
-static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
+static ssize_t class_pktcdvd_show_map(struct class *c,
+                                       struct class_attribute *attr,
+                                       char *data)
 {
        int n = 0;
        int idx;
@@ -356,7 +358,9 @@ static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
        return n;
 }
 
-static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
+static ssize_t class_pktcdvd_store_add(struct class *c,
+                                       struct class_attribute *attr,
+                                       const char *buf,
                                        size_t count)
 {
        unsigned int major, minor;
@@ -376,7 +380,9 @@ static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
        return -EINVAL;
 }
 
-static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf,
+static ssize_t class_pktcdvd_store_remove(struct class *c,
+                                         struct class_attribute *attr,
+                                         const char *buf,
                                        size_t count)
 {
        unsigned int major, minor;
index 21681a8..37b0542 100644 (file)
@@ -139,6 +139,8 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
  *
  * This function allocates a new struct iucv_tty_buffer element and, optionally,
  * allocates an internal data buffer with the specified size @size.
+ * The internal data buffer is always allocated with GFP_DMA which is
+ * required for receiving and sending data with IUCV.
  * Note: The total message size arises from the internal buffer size and the
  *      members of the iucv_tty_msg structure.
  * The function returns NULL if memory allocation has failed.
@@ -154,7 +156,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
 
        if (size > 0) {
                bufp->msg.length = MSG_SIZE(size);
-               bufp->mbuf = kmalloc(bufp->msg.length, flags);
+               bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA);
                if (!bufp->mbuf) {
                        mempool_free(bufp, hvc_iucv_mempool);
                        return NULL;
@@ -237,7 +239,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
        if (!rb->mbuf) { /* message not yet received ... */
                /* allocate mem to store msg data; if no memory is available
                 * then leave the buffer on the list and re-try later */
-               rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC);
+               rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA);
                if (!rb->mbuf)
                        return -ENOMEM;
 
index 176f175..4462b11 100644 (file)
@@ -295,6 +295,9 @@ struct smi_info {
 static int force_kipmid[SI_MAX_PARMS];
 static int num_force_kipmid;
 
+static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
+static int num_max_busy_us;
+
 static int unload_when_empty = 1;
 
 static int try_smi_init(struct smi_info *smi);
@@ -925,23 +928,77 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
        }
 }
 
+/*
+ * Use -1 in the nsec value of the busy waiting timespec to tell that
+ * we are spinning in kipmid looking for something and not delaying
+ * between checks
+ */
+static inline void ipmi_si_set_not_busy(struct timespec *ts)
+{
+       ts->tv_nsec = -1;
+}
+static inline int ipmi_si_is_busy(struct timespec *ts)
+{
+       return ts->tv_nsec != -1;
+}
+
+static int ipmi_thread_busy_wait(enum si_sm_result smi_result,
+                                const struct smi_info *smi_info,
+                                struct timespec *busy_until)
+{
+       unsigned int max_busy_us = 0;
+
+       if (smi_info->intf_num < num_max_busy_us)
+               max_busy_us = kipmid_max_busy_us[smi_info->intf_num];
+       if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
+               ipmi_si_set_not_busy(busy_until);
+       else if (!ipmi_si_is_busy(busy_until)) {
+               getnstimeofday(busy_until);
+               timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
+       } else {
+               struct timespec now;
+               getnstimeofday(&now);
+               if (unlikely(timespec_compare(&now, busy_until) > 0)) {
+                       ipmi_si_set_not_busy(busy_until);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+
+/*
+ * A busy-waiting loop for speeding up IPMI operation.
+ *
+ * Lousy hardware makes this hard.  This is only enabled for systems
+ * that are not BT and do not have interrupts.  It starts spinning
+ * when an operation is complete or until max_busy tells it to stop
+ * (if that is enabled).  See the paragraph on kimid_max_busy_us in
+ * Documentation/IPMI.txt for details.
+ */
 static int ipmi_thread(void *data)
 {
        struct smi_info *smi_info = data;
        unsigned long flags;
        enum si_sm_result smi_result;
+       struct timespec busy_until;
 
+       ipmi_si_set_not_busy(&busy_until);
        set_user_nice(current, 19);
        while (!kthread_should_stop()) {
+               int busy_wait;
+
                spin_lock_irqsave(&(smi_info->si_lock), flags);
                smi_result = smi_event_handler(smi_info, 0);
                spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+               busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
+                                                 &busy_until);
                if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
                        ; /* do nothing */
-               else if (smi_result == SI_SM_CALL_WITH_DELAY)
+               else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
                        schedule();
                else
-                       schedule_timeout_interruptible(1);
+                       schedule_timeout_interruptible(0);
        }
        return 0;
 }
@@ -1144,7 +1201,7 @@ static int           regsizes[SI_MAX_PARMS];
 static unsigned int num_regsizes;
 static int           regshifts[SI_MAX_PARMS];
 static unsigned int num_regshifts;
-static int slave_addrs[SI_MAX_PARMS];
+static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */
 static unsigned int num_slave_addrs;
 
 #define IPMI_IO_ADDR_SPACE  0
@@ -1212,6 +1269,11 @@ module_param(unload_when_empty, int, 0);
 MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
                 " specified or found, default is 1.  Setting to 0"
                 " is useful for hot add of devices using hotmod.");
+module_param_array(kipmid_max_busy_us, uint, &num_max_busy_us, 0644);
+MODULE_PARM_DESC(kipmid_max_busy_us,
+                "Max time (in microseconds) to busy-wait for IPMI data before"
+                " sleeping. 0 (default) means to wait forever. Set to 100-500"
+                " if kipmid is using up a lot of CPU time.");
 
 
 static void std_irq_cleanup(struct smi_info *info)
@@ -1607,7 +1669,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                regsize = 1;
                regshift = 0;
                irq = 0;
-               ipmb = 0x20;
+               ipmb = 0; /* Choose the default if not specified */
 
                next = strchr(curr, ':');
                if (next) {
@@ -1799,6 +1861,7 @@ static __devinit void hardcode_find_bmc(void)
                info->irq = irqs[i];
                if (info->irq)
                        info->irq_setup = std_irq_setup;
+               info->slave_addr = slave_addrs[i];
 
                try_smi_init(info);
        }
index 48788db..1f3215a 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
- *  Added devfs support. 
+ *  Added devfs support.
  *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
  *  Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
  */
@@ -44,36 +44,6 @@ static inline unsigned long size_inside_page(unsigned long start,
        return min(sz, size);
 }
 
-/*
- * Architectures vary in how they handle caching for addresses
- * outside of main memory.
- *
- */
-static inline int uncached_access(struct file *file, unsigned long addr)
-{
-#if defined(CONFIG_IA64)
-       /*
-        * On ia64, we ignore O_DSYNC because we cannot tolerate memory attribute aliases.
-        */
-       return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_MIPS)
-       {
-               extern int __uncached_access(struct file *file,
-                                            unsigned long addr);
-
-               return __uncached_access(file, addr);
-       }
-#else
-       /*
-        * Accessing memory above the top the kernel knows about or through a file pointer
-        * that was marked O_DSYNC will be done non-cached.
-        */
-       if (file->f_flags & O_DSYNC)
-               return 1;
-       return addr >= __pa(high_memory);
-#endif
-}
-
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t count)
 {
@@ -115,15 +85,15 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 }
 #endif
 
-void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)
 {
 }
 
 /*
- * This funcion reads the *physical* memory. The f_pos points directly to the 
- * memory location. 
+ * This funcion reads the *physical* memory. The f_pos points directly to the
+ * memory location.
  */
-static ssize_t read_mem(struct file * file, char __user * buf,
+static ssize_t read_mem(struct file *file, char __user *buf,
                        size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -140,10 +110,10 @@ static ssize_t read_mem(struct file * file, char __user * buf,
                if (sz > 0) {
                        if (clear_user(buf, sz))
                                return -EFAULT;
-                       buf += sz; 
-                       p += sz; 
-                       count -= sz; 
-                       read += sz; 
+                       buf += sz;
+                       p += sz;
+                       count -= sz;
+                       read += sz;
                }
        }
 #endif
@@ -157,9 +127,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,
                        return -EPERM;
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_mem_ptr(p);
                if (!ptr)
@@ -180,7 +150,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
        return read;
 }
 
-static ssize_t write_mem(struct file * file, const char __user * buf, 
+static ssize_t write_mem(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -212,9 +182,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
                        return -EPERM;
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_mem_ptr(p);
                if (!ptr) {
@@ -242,13 +212,46 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
        return written;
 }
 
-int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file,
+int __weak phys_mem_access_prot_allowed(struct file *file,
        unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
 {
        return 1;
 }
 
 #ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+
+/*
+ * Architectures vary in how they handle caching for addresses
+ * outside of main memory.
+ *
+ */
+static int uncached_access(struct file *file, unsigned long addr)
+{
+#if defined(CONFIG_IA64)
+       /*
+        * On ia64, we ignore O_DSYNC because we cannot tolerate memory
+        * attribute aliases.
+        */
+       return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
+#elif defined(CONFIG_MIPS)
+       {
+               extern int __uncached_access(struct file *file,
+                                            unsigned long addr);
+
+               return __uncached_access(file, addr);
+       }
+#else
+       /*
+        * Accessing memory above the top the kernel knows about or through a
+        * file pointer
+        * that was marked O_DSYNC will be done non-cached.
+        */
+       if (file->f_flags & O_DSYNC)
+               return 1;
+       return addr >= __pa(high_memory);
+#endif
+}
+
 static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
                                     unsigned long size, pgprot_t vma_prot)
 {
@@ -294,7 +297,7 @@ static const struct vm_operations_struct mmap_mem_ops = {
 #endif
 };
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
        size_t size = vma->vm_end - vma->vm_start;
 
@@ -329,7 +332,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 }
 
 #ifdef CONFIG_DEVKMEM
-static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
 {
        unsigned long pfn;
 
@@ -337,9 +340,9 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
        pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
 
        /*
-        * RED-PEN: on some architectures there is more mapped memory
-        * than available in mem_map which pfn_valid checks
-        * for. Perhaps should add a new macro here.
+        * RED-PEN: on some architectures there is more mapped memory than
+        * available in mem_map which pfn_valid checks for. Perhaps should add a
+        * new macro here.
         *
         * RED-PEN: vmalloc is not supported right now.
         */
@@ -389,7 +392,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf,
 /*
  * This function reads the *virtual* memory as seen by the kernel.
  */
-static ssize_t read_kmem(struct file *file, char __user *buf, 
+static ssize_t read_kmem(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -400,8 +403,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
        read = 0;
        if (p < (unsigned long) high_memory) {
                low_count = count;
-               if (count > (unsigned long) high_memory - p)
-                       low_count = (unsigned long) high_memory - p;
+               if (count > (unsigned long)high_memory - p)
+                       low_count = (unsigned long)high_memory - p;
 
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
                /* we don't have page 0 mapped on sparc and m68k.. */
@@ -465,9 +468,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
 }
 
 
-static inline ssize_t
-do_write_kmem(unsigned long p, const char __user *buf,
-             size_t count, loff_t *ppos)
+static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
+                               size_t count, loff_t *ppos)
 {
        ssize_t written, sz;
        unsigned long copied;
@@ -491,9 +493,9 @@ do_write_kmem(unsigned long p, const char __user *buf,
                sz = size_inside_page(p, count);
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_kmem_ptr((char *)p);
 
@@ -514,11 +516,10 @@ do_write_kmem(unsigned long p, const char __user *buf,
        return written;
 }
 
-
 /*
  * This function writes to the *virtual* memory as seen by the kernel.
  */
-static ssize_t write_kmem(struct file * file, const char __user * buf, 
+static ssize_t write_kmem(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -570,17 +571,17 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
 #endif
 
 #ifdef CONFIG_DEVPORT
-static ssize_t read_port(struct file * file, char __user * buf,
+static ssize_t read_port(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long i = *ppos;
        char __user *tmp = buf;
 
        if (!access_ok(VERIFY_WRITE, buf, count))
-               return -EFAULT; 
+               return -EFAULT;
        while (count-- > 0 && i < 65536) {
-               if (__put_user(inb(i),tmp) < 0) 
-                       return -EFAULT;  
+               if (__put_user(inb(i), tmp) < 0)
+                       return -EFAULT;
                i++;
                tmp++;
        }
@@ -588,22 +589,22 @@ static ssize_t read_port(struct file * file, char __user * buf,
        return tmp-buf;
 }
 
-static ssize_t write_port(struct file * file, const char __user * buf,
+static ssize_t write_port(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        unsigned long i = *ppos;
        const char __user * tmp = buf;
 
-       if (!access_ok(VERIFY_READ,buf,count))
+       if (!access_ok(VERIFY_READ, buf, count))
                return -EFAULT;
        while (count-- > 0 && i < 65536) {
                char c;
                if (__get_user(c, tmp)) {
                        if (tmp > buf)
                                break;
-                       return -EFAULT; 
+                       return -EFAULT;
                }
-               outb(c,i);
+               outb(c, i);
                i++;
                tmp++;
        }
@@ -612,13 +613,13 @@ static ssize_t write_port(struct file * file, const char __user * buf,
 }
 #endif
 
-static ssize_t read_null(struct file * file, char __user * buf,
+static ssize_t read_null(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        return 0;
 }
 
-static ssize_t write_null(struct file * file, const char __user * buf,
+static ssize_t write_null(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        return count;
@@ -630,13 +631,13 @@ static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
        return sd->len;
 }
 
-static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,
                                 loff_t *ppos, size_t len, unsigned int flags)
 {
        return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
 }
 
-static ssize_t read_zero(struct file * file, char __user * buf, 
+static ssize_t read_zero(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        size_t written;
@@ -667,7 +668,7 @@ static ssize_t read_zero(struct file * file, char __user * buf,
        return written ? written : -EFAULT;
 }
 
-static int mmap_zero(struct file * file, struct vm_area_struct * vma)
+static int mmap_zero(struct file *file, struct vm_area_struct *vma)
 {
 #ifndef CONFIG_MMU
        return -ENOSYS;
@@ -677,7 +678,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma)
        return 0;
 }
 
-static ssize_t write_full(struct file * file, const char __user * buf,
+static ssize_t write_full(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        return -ENOSPC;
@@ -688,8 +689,7 @@ static ssize_t write_full(struct file * file, const char __user * buf,
  * can fopen() both devices with "a" now.  This was previously impossible.
  * -- SRB.
  */
-
-static loff_t null_lseek(struct file * file, loff_t offset, int orig)
+static loff_t null_lseek(struct file *file, loff_t offset, int orig)
 {
        return file->f_pos = 0;
 }
@@ -702,24 +702,31 @@ static loff_t null_lseek(struct file * file, loff_t offset, int orig)
  * also note that seeking relative to the "end of file" isn't supported:
  * it has no meaning, so it returns -EINVAL.
  */
-static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
+static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
        mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
        switch (orig) {
-               case 0:
-                       file->f_pos = offset;
-                       ret = file->f_pos;
-                       force_successful_syscall_return();
+       case SEEK_CUR:
+               offset += file->f_pos;
+               if ((unsigned long long)offset <
+                   (unsigned long long)file->f_pos) {
+                       ret = -EOVERFLOW;
                        break;
-               case 1:
-                       file->f_pos += offset;
-                       ret = file->f_pos;
-                       force_successful_syscall_return();
+               }
+       case SEEK_SET:
+               /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
+               if ((unsigned long long)offset >= ~0xFFFULL) {
+                       ret = -EOVERFLOW;
                        break;
-               default:
-                       ret = -EINVAL;
+               }
+               file->f_pos = offset;
+               ret = file->f_pos;
+               force_successful_syscall_return();
+               break;
+       default:
+               ret = -EINVAL;
        }
        mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
        return ret;
@@ -803,7 +810,7 @@ static const struct file_operations oldmem_fops = {
 };
 #endif
 
-static ssize_t kmsg_write(struct file * file, const char __user * buf,
+static ssize_t kmsg_write(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        char *tmp;
@@ -825,7 +832,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
 }
 
 static const struct file_operations kmsg_fops = {
-       .write =        kmsg_write,
+       .write = kmsg_write,
 };
 
 static const struct memdev {
@@ -876,7 +883,7 @@ static int memory_open(struct inode *inode, struct file *filp)
 }
 
 static const struct file_operations memory_fops = {
-       .open           = memory_open,
+       .open = memory_open,
 };
 
 static char *mem_devnode(struct device *dev, mode_t *mode)
@@ -897,7 +904,7 @@ static int __init chr_dev_init(void)
        if (err)
                return err;
 
-       if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
+       if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
        mem_class = class_create(THIS_MODULE, "mem");
index 918711a..04fd0d8 100644 (file)
@@ -546,7 +546,7 @@ static void mmtimer_tasklet(unsigned long data)
 {
        int nodeid = data;
        struct mmtimer_node *mn = &timers[nodeid];
-       struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list);
+       struct mmtimer *x;
        struct k_itimer *t;
        unsigned long flags;
 
index 2e50f4d..bdae832 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/audit.h>
 #include <linux/file.h>
 #include <linux/uaccess.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 
@@ -2091,3 +2092,19 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .receive_buf     = n_tty_receive_buf,
        .write_wakeup    = n_tty_write_wakeup
 };
+
+/**
+ *     n_tty_inherit_ops       -       inherit N_TTY methods
+ *     @ops: struct tty_ldisc_ops where to save N_TTY methods
+ *
+ *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
+ *     methods.
+ */
+
+void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
+{
+       *ops = tty_ldisc_N_TTY;
+       ops->owner = NULL;
+       ops->refcount = ops->flags = 0;
+}
+EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
index ac16fbe..283a15b 100644 (file)
@@ -148,7 +148,6 @@ void tty_audit_fork(struct signal_struct *sig)
        spin_lock_irq(&current->sighand->siglock);
        sig->audit_tty = current->signal->audit_tty;
        spin_unlock_irq(&current->sighand->siglock);
-       sig->tty_audit_buf = NULL;
 }
 
 /**
index 67bc2ec..2d5d575 100644 (file)
@@ -766,7 +766,7 @@ static void cpufreq_sysfs_release(struct kobject *kobj)
        complete(&policy->kobj_unregister);
 }
 
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
        .show   = show,
        .store  = store,
 };
index 97b0038..8719b36 100644 (file)
@@ -22,6 +22,7 @@ static int __init cpuidle_sysfs_setup(char *unused)
 __setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup);
 
 static ssize_t show_available_governors(struct sysdev_class *class,
+                                       struct sysdev_class_attribute *attr,
                                        char *buf)
 {
        ssize_t i = 0;
@@ -41,6 +42,7 @@ out:
 }
 
 static ssize_t show_current_driver(struct sysdev_class *class,
+                                  struct sysdev_class_attribute *attr,
                                   char *buf)
 {
        ssize_t ret;
@@ -56,6 +58,7 @@ static ssize_t show_current_driver(struct sysdev_class *class,
 }
 
 static ssize_t show_current_governor(struct sysdev_class *class,
+                                    struct sysdev_class_attribute *attr,
                                     char *buf)
 {
        ssize_t ret;
@@ -71,6 +74,7 @@ static ssize_t show_current_governor(struct sysdev_class *class,
 }
 
 static ssize_t store_current_governor(struct sysdev_class *class,
+                                     struct sysdev_class_attribute *attr,
                                      const char *buf, size_t count)
 {
        char gov_name[CPUIDLE_NAME_LEN];
@@ -191,7 +195,7 @@ static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
        return ret;
 }
 
-static struct sysfs_ops cpuidle_sysfs_ops = {
+static const struct sysfs_ops cpuidle_sysfs_ops = {
        .show = cpuidle_show,
        .store = cpuidle_store,
 };
@@ -277,7 +281,7 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
        return ret;
 }
 
-static struct sysfs_ops cpuidle_state_sysfs_ops = {
+static const struct sysfs_ops cpuidle_state_sysfs_ops = {
        .show = cpuidle_state_show,
 };
 
index af14c9a..0099340 100644 (file)
@@ -1138,7 +1138,7 @@ ioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
        return entry->show(&chan->common, page);
 }
 
-struct sysfs_ops ioat_sysfs_ops = {
+const struct sysfs_ops ioat_sysfs_ops = {
        .show   = ioat_attr_show,
 };
 
index 4f747a2..86b97ac 100644 (file)
@@ -346,7 +346,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
                           unsigned long *phys_complete);
 void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
 void ioat_kobject_del(struct ioatdma_device *device);
-extern struct sysfs_ops ioat_sysfs_ops;
+extern const struct sysfs_ops ioat_sysfs_ops;
 extern struct ioat_sysfs_entry ioat_version_attr;
 extern struct ioat_sysfs_entry ioat_cap_attr;
 #endif /* IOATDMA_H */
index d205d49..243e9aa 100644 (file)
@@ -75,6 +75,14 @@ static struct edac_pci_ctl_info *e752x_pci;
 #define E752X_NR_CSROWS                8       /* number of csrows */
 
 /* E752X register addresses - device 0 function 0 */
+#define E752X_MCHSCRB          0x52    /* Memory Scrub register (16b) */
+                                       /*
+                                        * 6:5     Scrub Completion Count
+                                        * 3:2     Scrub Rate (i3100 only)
+                                        *      01=fast 10=normal
+                                        * 1:0     Scrub Mode enable
+                                        *      00=off 10=on
+                                        */
 #define E752X_DRB              0x60    /* DRAM row boundary register (8b) */
 #define E752X_DRA              0x70    /* DRAM row attribute register (8b) */
                                        /*
@@ -240,6 +248,41 @@ static const struct e752x_dev_info e752x_devs[] = {
                .ctl_name = "3100"},
 };
 
+/* Valid scrub rates for the e752x/3100 hardware memory scrubber. We
+ * map the scrubbing bandwidth to a hardware register value. The 'set'
+ * operation finds the 'matching or higher value'.  Note that scrubbing
+ * on the e752x can only be enabled/disabled.  The 3100 supports
+ * a normal and fast mode.
+ */
+
+#define SDRATE_EOT 0xFFFFFFFF
+
+struct scrubrate {
+       u32 bandwidth;  /* bandwidth consumed by scrubbing in bytes/sec */
+       u16 scrubval;   /* register value for scrub rate */
+};
+
+/* Rate below assumes same performance as i3100 using PC3200 DDR2 in
+ * normal mode.  e752x bridges don't support choosing normal or fast mode,
+ * so the scrubbing bandwidth value isn't all that important - scrubbing is
+ * either on or off.
+ */
+static const struct scrubrate scrubrates_e752x[] = {
+       {0,             0x00},  /* Scrubbing Off */
+       {500000,        0x02},  /* Scrubbing On */
+       {SDRATE_EOT,    0x00}   /* End of Table */
+};
+
+/* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s
+ * Normal mode: 125 (32000 / 256) times slower than fast mode.
+ */
+static const struct scrubrate scrubrates_i3100[] = {
+       {0,             0x00},  /* Scrubbing Off */
+       {500000,        0x0a},  /* Normal mode - 32k clocks */
+       {62500000,      0x06},  /* Fast mode - 256 clocks */
+       {SDRATE_EOT,    0x00}   /* End of Table */
+};
+
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
                                unsigned long page)
 {
@@ -915,6 +958,68 @@ static void e752x_check(struct mem_ctl_info *mci)
        e752x_process_error_info(mci, &info, 1);
 }
 
+/* Program byte/sec bandwidth scrub rate to hardware */
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
+{
+       const struct scrubrate *scrubrates;
+       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct pci_dev *pdev = pvt->dev_d0f0;
+       int i;
+
+       if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
+               scrubrates = scrubrates_i3100;
+       else
+               scrubrates = scrubrates_e752x;
+
+       /* Translate the desired scrub rate to a e752x/3100 register value.
+        * Search for the bandwidth that is equal or greater than the
+        * desired rate and program the cooresponding register value.
+        */
+       for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
+               if (scrubrates[i].bandwidth >= *new_bw)
+                       break;
+
+       if (scrubrates[i].bandwidth == SDRATE_EOT)
+               return -1;
+
+       pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval);
+
+       return 0;
+}
+
+/* Convert current scrub rate value into byte/sec bandwidth */
+static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+{
+       const struct scrubrate *scrubrates;
+       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct pci_dev *pdev = pvt->dev_d0f0;
+       u16 scrubval;
+       int i;
+
+       if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
+               scrubrates = scrubrates_i3100;
+       else
+               scrubrates = scrubrates_e752x;
+
+       /* Find the bandwidth matching the memory scrubber configuration */
+       pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval);
+       scrubval = scrubval & 0x0f;
+
+       for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
+               if (scrubrates[i].scrubval == scrubval)
+                       break;
+
+       if (scrubrates[i].bandwidth == SDRATE_EOT) {
+               e752x_printk(KERN_WARNING,
+                       "Invalid sdram scrub control value: 0x%x\n", scrubval);
+               return -1;
+       }
+
+       *bw = scrubrates[i].bandwidth;
+
+       return 0;
+}
+
 /* Return 1 if dual channel mode is active.  Else return 0. */
 static inline int dual_channel_active(u16 ddrcsr)
 {
@@ -1073,10 +1178,7 @@ fail:
 
 /* Setup system bus parity mask register.
  * Sysbus parity supported on:
- *   e7320/e7520/e7525 + Xeon
- *   i3100 + Xeon/Celeron
- * Sysbus parity not supported on:
- *   i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo
+ * e7320/e7520/e7525 + Xeon
  */
 static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
 {
@@ -1087,10 +1189,7 @@ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
        /* Allow module parameter override, else see if CPU supports parity */
        if (sysbus_parity != -1) {
                enable = sysbus_parity;
-       } else if (cpu_id[0] &&
-                  ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) ||
-                   (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) ||
-                   (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) {
+       } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) {
                e752x_printk(KERN_INFO, "System Bus Parity not "
                             "supported by CPU, disabling\n");
                enable = 0;
@@ -1187,6 +1286,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        mci->dev_name = pci_name(pdev);
        mci->edac_check = e752x_check;
        mci->ctl_page_to_phys = ctl_page_to_phys;
+       mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
+       mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
 
        /* set the map type.  1 = normal, 0 = reversed
         * Must be set before e752x_init_csrows in case csrow mapping
index 5376457..5fdedbc 100644 (file)
@@ -137,7 +137,7 @@ static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
 }
 
 /* edac_dev file operations for an 'ctl_info' */
-static struct sysfs_ops device_ctl_info_ops = {
+static const struct sysfs_ops device_ctl_info_ops = {
        .show = edac_dev_ctl_info_show,
        .store = edac_dev_ctl_info_store
 };
@@ -373,7 +373,7 @@ static ssize_t edac_dev_instance_store(struct kobject *kobj,
 }
 
 /* edac_dev file operations for an 'instance' */
-static struct sysfs_ops device_instance_ops = {
+static const struct sysfs_ops device_instance_ops = {
        .show = edac_dev_instance_show,
        .store = edac_dev_instance_store
 };
@@ -476,7 +476,7 @@ static ssize_t edac_dev_block_store(struct kobject *kobj,
 }
 
 /* edac_dev file operations for a 'block' */
-static struct sysfs_ops device_block_ops = {
+static const struct sysfs_ops device_block_ops = {
        .show = edac_dev_block_show,
        .store = edac_dev_block_store
 };
index e1d4ce0..88840e9 100644 (file)
@@ -245,7 +245,7 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
        return -EIO;
 }
 
-static struct sysfs_ops csrowfs_ops = {
+static const struct sysfs_ops csrowfs_ops = {
        .show = csrowdev_show,
        .store = csrowdev_store
 };
@@ -575,7 +575,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
 }
 
 /* Intermediate show/store table */
-static struct sysfs_ops mci_ops = {
+static const struct sysfs_ops mci_ops = {
        .show = mcidev_show,
        .store = mcidev_store
 };
index fb60a87..bef94e3 100644 (file)
@@ -121,7 +121,7 @@ static ssize_t edac_pci_instance_store(struct kobject *kobj,
 }
 
 /* fs_ops table */
-static struct sysfs_ops pci_instance_ops = {
+static const struct sysfs_ops pci_instance_ops = {
        .show = edac_pci_instance_show,
        .store = edac_pci_instance_store
 };
@@ -261,7 +261,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj,
        return -EIO;
 }
 
-static struct sysfs_ops edac_pci_sysfs_ops = {
+static const struct sysfs_ops edac_pci_sysfs_ops = {
        .show = edac_pci_dev_show,
        .store = edac_pci_dev_store
 };
index ecd5928..94cac0a 100644 (file)
@@ -239,16 +239,15 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
        /* we only need the error registers */
        r.start += 0xe00;
 
-       if (!devm_request_mem_region(&op->dev, r.start,
-                                       r.end - r.start + 1, pdata->name)) {
+       if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
+                                       pdata->name)) {
                printk(KERN_ERR "%s: Error while requesting mem region\n",
                       __func__);
                res = -EBUSY;
                goto err;
        }
 
-       pdata->pci_vbase = devm_ioremap(&op->dev, r.start,
-                                       r.end - r.start + 1);
+       pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
        if (!pdata->pci_vbase) {
                printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
                res = -ENOMEM;
@@ -668,15 +667,125 @@ static struct of_platform_driver mpc85xx_l2_err_driver = {
 
 /**************************** MC Err device ***************************/
 
+/*
+ * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the
+ * MPC8572 User's Manual.  Each line represents a syndrome bit column as a
+ * 64-bit value, but split into an upper and lower 32-bit chunk.  The labels
+ * below correspond to Freescale's manuals.
+ */
+static unsigned int ecc_table[16] = {
+       /* MSB           LSB */
+       /* [0:31]    [32:63] */
+       0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */
+       0x00ff00ff, 0x00fff0ff,
+       0x0f0f0f0f, 0x0f0fff00,
+       0x11113333, 0x7777000f,
+       0x22224444, 0x8888222f,
+       0x44448888, 0xffff4441,
+       0x8888ffff, 0x11118882,
+       0xffff1111, 0x22221114, /* Syndrome bit 0 */
+};
+
+/*
+ * Calculate the correct ECC value for a 64-bit value specified by high:low
+ */
+static u8 calculate_ecc(u32 high, u32 low)
+{
+       u32 mask_low;
+       u32 mask_high;
+       int bit_cnt;
+       u8 ecc = 0;
+       int i;
+       int j;
+
+       for (i = 0; i < 8; i++) {
+               mask_high = ecc_table[i * 2];
+               mask_low = ecc_table[i * 2 + 1];
+               bit_cnt = 0;
+
+               for (j = 0; j < 32; j++) {
+                       if ((mask_high >> j) & 1)
+                               bit_cnt ^= (high >> j) & 1;
+                       if ((mask_low >> j) & 1)
+                               bit_cnt ^= (low >> j) & 1;
+               }
+
+               ecc |= bit_cnt << i;
+       }
+
+       return ecc;
+}
+
+/*
+ * Create the syndrome code which is generated if the data line specified by
+ * 'bit' failed.  Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641
+ * User's Manual and 9-61 in the MPC8572 User's Manual.
+ */
+static u8 syndrome_from_bit(unsigned int bit) {
+       int i;
+       u8 syndrome = 0;
+
+       /*
+        * Cycle through the upper or lower 32-bit portion of each value in
+        * ecc_table depending on if 'bit' is in the upper or lower half of
+        * 64-bit data.
+        */
+       for (i = bit < 32; i < 16; i += 2)
+               syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2);
+
+       return syndrome;
+}
+
+/*
+ * Decode data and ecc syndrome to determine what went wrong
+ * Note: This can only decode single-bit errors
+ */
+static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc,
+                      int *bad_data_bit, int *bad_ecc_bit)
+{
+       int i;
+       u8 syndrome;
+
+       *bad_data_bit = -1;
+       *bad_ecc_bit = -1;
+
+       /*
+        * Calculate the ECC of the captured data and XOR it with the captured
+        * ECC to find an ECC syndrome value we can search for
+        */
+       syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc;
+
+       /* Check if a data line is stuck... */
+       for (i = 0; i < 64; i++) {
+               if (syndrome == syndrome_from_bit(i)) {
+                       *bad_data_bit = i;
+                       return;
+               }
+       }
+
+       /* If data is correct, check ECC bits for errors... */
+       for (i = 0; i < 8; i++) {
+               if ((syndrome >> i) & 0x1) {
+                       *bad_ecc_bit = i;
+                       return;
+               }
+       }
+}
+
 static void mpc85xx_mc_check(struct mem_ctl_info *mci)
 {
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        struct csrow_info *csrow;
+       u32 bus_width;
        u32 err_detect;
        u32 syndrome;
        u32 err_addr;
        u32 pfn;
        int row_index;
+       u32 cap_high;
+       u32 cap_low;
+       int bad_data_bit;
+       int bad_ecc_bit;
 
        err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
        if (!err_detect)
@@ -692,6 +801,15 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
        }
 
        syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC);
+
+       /* Mask off appropriate bits of syndrome based on bus width */
+       bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) &
+                       DSC_DBW_MASK) ? 32 : 64;
+       if (bus_width == 64)
+               syndrome &= 0xff;
+       else
+               syndrome &= 0xffff;
+
        err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS);
        pfn = err_addr >> PAGE_SHIFT;
 
@@ -701,14 +819,35 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
                        break;
        }
 
-       mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data High: %#8.8x\n",
-                         in_be32(pdata->mc_vbase +
-                                 MPC85XX_MC_CAPTURE_DATA_HI));
-       mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data Low: %#8.8x\n",
-                         in_be32(pdata->mc_vbase +
-                                 MPC85XX_MC_CAPTURE_DATA_LO));
-       mpc85xx_mc_printk(mci, KERN_ERR, "syndrome: %#8.8x\n", syndrome);
-       mpc85xx_mc_printk(mci, KERN_ERR, "err addr: %#8.8x\n", err_addr);
+       cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI);
+       cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO);
+
+       /*
+        * Analyze single-bit errors on 64-bit wide buses
+        * TODO: Add support for 32-bit wide buses
+        */
+       if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) {
+               sbe_ecc_decode(cap_high, cap_low, syndrome,
+                               &bad_data_bit, &bad_ecc_bit);
+
+               if (bad_data_bit != -1)
+                       mpc85xx_mc_printk(mci, KERN_ERR,
+                               "Faulty Data bit: %d\n", bad_data_bit);
+               if (bad_ecc_bit != -1)
+                       mpc85xx_mc_printk(mci, KERN_ERR,
+                               "Faulty ECC bit: %d\n", bad_ecc_bit);
+
+               mpc85xx_mc_printk(mci, KERN_ERR,
+                       "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
+                       cap_high ^ (1 << (bad_data_bit - 32)),
+                       cap_low ^ (1 << bad_data_bit),
+                       syndrome ^ (1 << bad_ecc_bit));
+       }
+
+       mpc85xx_mc_printk(mci, KERN_ERR,
+                       "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
+                       cap_high, cap_low, syndrome);
+       mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8x\n", err_addr);
        mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn);
 
        /* we are out of range */
index 52432ee..cb24df8 100644 (file)
@@ -48,6 +48,9 @@
 #define DSC_MEM_EN     0x80000000
 #define DSC_ECC_EN     0x20000000
 #define DSC_RD_EN      0x10000000
+#define DSC_DBW_MASK   0x00180000
+#define DSC_DBW_32     0x00080000
+#define DSC_DBW_64     0x00000000
 
 #define DSC_SDTYPE_MASK                0x07000000
 
index 014cabd..5db0518 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
-#include <linux/semaphore.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/workqueue.h>
@@ -828,9 +827,9 @@ static int update_unit(struct device *dev, void *data)
        struct fw_driver *driver = (struct fw_driver *)dev->driver;
 
        if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
-               down(&dev->sem);
+               device_lock(dev);
                driver->update(unit);
-               up(&dev->sem);
+               device_unlock(dev);
        }
 
        return 0;
index 9e4f59d..110e24e 100644 (file)
@@ -122,7 +122,7 @@ edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
        return ret;
 }
 
-static struct sysfs_ops edd_attr_ops = {
+static const struct sysfs_ops edd_attr_ops = {
        .show = edd_attr_show,
 };
 
index f4f709d..082f06e 100644 (file)
@@ -362,7 +362,7 @@ static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops efivar_attr_ops = {
+static const struct sysfs_ops efivar_attr_ops = {
        .show = efivar_attr_show,
        .store = efivar_attr_store,
 };
index a3600e3..ed2801c 100644 (file)
@@ -519,7 +519,7 @@ static ssize_t ibft_show_attribute(struct kobject *kobj,
        return ret;
 }
 
-static struct sysfs_ops ibft_attr_ops = {
+static const struct sysfs_ops ibft_attr_ops = {
        .show = ibft_show_attribute,
 };
 
index 20f6457..d59f7ca 100644 (file)
@@ -74,7 +74,7 @@ static struct attribute *def_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops memmap_attr_ops = {
+static const struct sysfs_ops memmap_attr_ops = {
        .show = memmap_attr_show,
 };
 
index 9006fdb..6d1b866 100644 (file)
@@ -623,7 +623,9 @@ static const struct attribute_group gpiochip_attr_group = {
  * /sys/class/gpio/unexport ... write-only
  *     integer N ... number of GPIO to unexport
  */
-static ssize_t export_store(struct class *class, const char *buf, size_t len)
+static ssize_t export_store(struct class *class,
+                               struct class_attribute *attr,
+                               const char *buf, size_t len)
 {
        long    gpio;
        int     status;
@@ -653,7 +655,9 @@ done:
        return status ? : len;
 }
 
-static ssize_t unexport_store(struct class *class, const char *buf, size_t len)
+static ssize_t unexport_store(struct class *class,
+                               struct class_attribute *attr,
+                               const char *buf, size_t len)
 {
        long    gpio;
        int     status;
index 7e42b7e..014ce24 100644 (file)
@@ -70,19 +70,17 @@ static int drm_class_resume(struct device *dev)
        return 0;
 }
 
-/* Display the version of drm_core. This doesn't work right in current design */
-static ssize_t version_show(struct class *dev, char *buf)
-{
-       return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR,
-                      CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
-}
-
 static char *drm_devnode(struct device *dev, mode_t *mode)
 {
        return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
 }
 
-static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
+static CLASS_ATTR_STRING(version, S_IRUGO,
+               CORE_NAME " "
+               __stringify(CORE_MAJOR) "."
+               __stringify(CORE_MINOR) "."
+               __stringify(CORE_PATCHLEVEL) " "
+               CORE_DATE);
 
 /**
  * drm_sysfs_create - create a struct drm_sysfs_class structure
@@ -109,7 +107,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
        class->suspend = drm_class_suspend;
        class->resume = drm_class_resume;
 
-       err = class_create_file(class, &class_attr_version);
+       err = class_create_file(class, &class_attr_version.attr);
        if (err)
                goto err_out_class;
 
@@ -132,7 +130,7 @@ void drm_sysfs_destroy(void)
 {
        if ((drm_class == NULL) || (IS_ERR(drm_class)))
                return;
-       class_remove_file(drm_class, &class_attr_version);
+       class_remove_file(drm_class, &class_attr_version.attr);
        class_destroy(drm_class);
 }
 
index c7320ce..89c38c4 100644 (file)
@@ -128,7 +128,7 @@ static struct attribute *ttm_bo_global_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops ttm_bo_global_ops = {
+static const struct sysfs_ops ttm_bo_global_ops = {
        .show = &ttm_bo_global_show
 };
 
index f5245c0..eb143e0 100644 (file)
@@ -152,7 +152,7 @@ static struct attribute *ttm_mem_zone_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops ttm_mem_zone_ops = {
+static const struct sysfs_ops ttm_mem_zone_ops = {
        .show = &ttm_mem_zone_show,
        .store = &ttm_mem_zone_store
 };
index 913abd7..c7c2375 100644 (file)
@@ -850,7 +850,7 @@ static const struct i2c_algorithm omap_i2c_algo = {
        .functionality  = omap_i2c_func,
 };
 
-static int __init
+static int __devinit
 omap_i2c_probe(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev;
index 5122b5a..1835021 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
-#include <linux/semaphore.h>
 #include <asm/atomic.h>
 
 #include "csr.h"
@@ -1397,9 +1396,9 @@ static int update_pdrv(struct device *dev, void *data)
                        pdrv = container_of(drv, struct hpsb_protocol_driver,
                                            driver);
                        if (pdrv->update) {
-                               down(&ud->device.sem);
+                               device_lock(&ud->device);
                                error = pdrv->update(ud);
-                               up(&ud->device.sem);
+                               device_unlock(&ud->device);
                        }
                        if (error)
                                device_release_driver(&ud->device);
index 5130fc5..764787e 100644 (file)
@@ -3597,7 +3597,7 @@ static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
                       atomic_long_read(&group->counter[cm_attr->index]));
 }
 
-static struct sysfs_ops cm_counter_ops = {
+static const struct sysfs_ops cm_counter_ops = {
        .show = cm_show_counter
 };
 
index 158a214..1558bb7 100644 (file)
@@ -79,7 +79,7 @@ static ssize_t port_attr_show(struct kobject *kobj,
        return port_attr->show(p, port_attr, buf);
 }
 
-static struct sysfs_ops port_sysfs_ops = {
+static const struct sysfs_ops port_sysfs_ops = {
        .show = port_attr_show
 };
 
index 1b09b73..017d6e2 100644 (file)
@@ -1336,11 +1336,8 @@ static void ib_ucm_remove_one(struct ib_device *device)
        device_unregister(&ucm_dev->dev);
 }
 
-static ssize_t show_abi_version(struct class *class, char *buf)
-{
-       return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION);
-}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+                        __stringify(IB_USER_CM_ABI_VERSION));
 
 static int __init ib_ucm_init(void)
 {
@@ -1353,7 +1350,7 @@ static int __init ib_ucm_init(void)
                goto error1;
        }
 
-       ret = class_create_file(&cm_class, &class_attr_abi_version);
+       ret = class_create_file(&cm_class, &class_attr_abi_version.attr);
        if (ret) {
                printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
                goto error2;
@@ -1367,7 +1364,7 @@ static int __init ib_ucm_init(void)
        return 0;
 
 error3:
-       class_remove_file(&cm_class, &class_attr_abi_version);
+       class_remove_file(&cm_class, &class_attr_abi_version.attr);
 error2:
        unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
 error1:
@@ -1377,7 +1374,7 @@ error1:
 static void __exit ib_ucm_cleanup(void)
 {
        ib_unregister_client(&ucm_client);
-       class_remove_file(&cm_class, &class_attr_abi_version);
+       class_remove_file(&cm_class, &class_attr_abi_version.attr);
        unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
        if (overflow_maj)
                unregister_chrdev_region(overflow_maj, IB_UCM_MAX_DEVICES);
index 02d360c..04b585e 100644 (file)
@@ -965,11 +965,8 @@ static ssize_t show_port(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
 
-static ssize_t show_abi_version(struct class *class, char *buf)
-{
-       return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION);
-}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+                        __stringify(IB_USER_MAD_ABI_VERSION));
 
 static dev_t overflow_maj;
 static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
@@ -1194,7 +1191,7 @@ static int __init ib_umad_init(void)
                goto out_chrdev;
        }
 
-       ret = class_create_file(umad_class, &class_attr_abi_version);
+       ret = class_create_file(umad_class, &class_attr_abi_version.attr);
        if (ret) {
                printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n");
                goto out_class;
index 4fa2e65..d805cf3 100644 (file)
@@ -691,11 +691,8 @@ static ssize_t show_dev_abi_version(struct device *device,
 }
 static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL);
 
-static ssize_t show_abi_version(struct class *class, char *buf)
-{
-       return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION);
-}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+                        __stringify(IB_USER_VERBS_ABI_VERSION));
 
 static dev_t overflow_maj;
 static DECLARE_BITMAP(overflow_map, IB_UVERBS_MAX_DEVICES);
@@ -841,7 +838,7 @@ static int __init ib_uverbs_init(void)
                goto out_chrdev;
        }
 
-       ret = class_create_file(uverbs_class, &class_attr_abi_version);
+       ret = class_create_file(uverbs_class, &class_attr_abi_version.attr);
        if (ret) {
                printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
                goto out_class;
index 437f55c..419795f 100644 (file)
@@ -321,6 +321,7 @@ int wf_register_sensor(struct wf_sensor *new_sr)
        kref_init(&new_sr->ref);
        list_add(&new_sr->link, &wf_sensors);
 
+       sysfs_attr_init(&new_sr->attr.attr);
        new_sr->attr.attr.name = new_sr->name;
        new_sr->attr.attr.mode = 0444;
        new_sr->attr.show = wf_show_sensor;
index 6c68b9e..43137b4 100644 (file)
@@ -173,6 +173,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
 
        fct->fan_type = pwm_fan;
        fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
+       sysfs_attr_init(&fct->ctrl.attr.attr);
 
        /* We use the name & location here the same way we do for SMU sensors,
         * see the comment in windfarm_smu_sensors.c. The locations are a bit
index f91b409..84d2b91 100644 (file)
@@ -75,7 +75,7 @@ static struct attribute *dm_attrs[] = {
        NULL,
 };
 
-static struct sysfs_ops dm_sysfs_ops = {
+static const struct sysfs_ops dm_sysfs_ops = {
        .show   = dm_attr_show,
 };
 
index a20a71e..fdc1890 100644 (file)
@@ -2642,7 +2642,7 @@ static void rdev_free(struct kobject *ko)
        mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
        kfree(rdev);
 }
-static struct sysfs_ops rdev_sysfs_ops = {
+static const struct sysfs_ops rdev_sysfs_ops = {
        .show           = rdev_attr_show,
        .store          = rdev_attr_store,
 };
@@ -4059,7 +4059,7 @@ static void md_free(struct kobject *ko)
        kfree(mddev);
 }
 
-static struct sysfs_ops md_sysfs_ops = {
+static const struct sysfs_ops md_sysfs_ops = {
        .show   = md_attr_show,
        .store  = md_attr_store,
 };
index 7400eac..142c327 100644 (file)
@@ -1735,7 +1735,7 @@ static struct v4l2_int_device omap24xxcam = {
  *
  */
 
-static int __init omap24xxcam_probe(struct platform_device *pdev)
+static int __devinit omap24xxcam_probe(struct platform_device *pdev)
 {
        struct omap24xxcam_device *cam;
        struct resource *mem;
index 04c2726..779aa8e 100644 (file)
@@ -497,12 +497,7 @@ static struct pci_driver phantom_pci_driver = {
        .resume = phantom_resume
 };
 
-static ssize_t phantom_show_version(struct class *cls, char *buf)
-{
-       return sprintf(buf, PHANTOM_VERSION "\n");
-}
-
-static CLASS_ATTR(version, 0444, phantom_show_version, NULL);
+static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION);
 
 static int __init phantom_init(void)
 {
@@ -515,7 +510,7 @@ static int __init phantom_init(void)
                printk(KERN_ERR "phantom: can't register phantom class\n");
                goto err;
        }
-       retval = class_create_file(phantom_class, &class_attr_version);
+       retval = class_create_file(phantom_class, &class_attr_version.attr);
        if (retval) {
                printk(KERN_ERR "phantom: can't create sysfs version file\n");
                goto err_class;
@@ -541,7 +536,7 @@ static int __init phantom_init(void)
 err_unchr:
        unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
 err_attr:
-       class_remove_file(phantom_class, &class_attr_version);
+       class_remove_file(phantom_class, &class_attr_version.attr);
 err_class:
        class_destroy(phantom_class);
 err:
@@ -554,7 +549,7 @@ static void __exit phantom_exit(void)
 
        unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
 
-       class_remove_file(phantom_class, &class_attr_version);
+       class_remove_file(phantom_class, &class_attr_version.attr);
        class_destroy(phantom_class);
 
        pr_debug("phantom: module successfully removed\n");
index 02a77b8..7a8b906 100644 (file)
@@ -516,8 +516,7 @@ struct gru_blade_state {
 
 /* Scan all active GRUs in a GRU bitmap */
 #define for_each_gru_in_bitmap(gid, map)                               \
-       for ((gid) = find_first_bit((map), GRU_MAX_GRUS); (gid) < GRU_MAX_GRUS;\
-               (gid)++, (gid) = find_next_bit((map), GRU_MAX_GRUS, (gid)))
+       for_each_set_bit((gid), (map), GRU_MAX_GRUS)
 
 /* Scan all active GRUs on a specific blade */
 #define for_each_gru_on_blade(gru, nid, i)                             \
@@ -536,23 +535,17 @@ struct gru_blade_state {
 
 /* Scan each CBR whose bit is set in a TFM (or copy of) */
 #define for_each_cbr_in_tfm(i, map)                                    \
-       for ((i) = find_first_bit(map, GRU_NUM_CBE);                    \
-                       (i) < GRU_NUM_CBE;                              \
-                       (i)++, (i) = find_next_bit(map, GRU_NUM_CBE, i))
+       for_each_set_bit((i), (map), GRU_NUM_CBE)
 
 /* Scan each CBR in a CBR bitmap. Note: multiple CBRs in an allocation unit */
 #define for_each_cbr_in_allocation_map(i, map, k)                      \
-       for ((k) = find_first_bit(map, GRU_CBR_AU); (k) < GRU_CBR_AU;   \
-                       (k) = find_next_bit(map, GRU_CBR_AU, (k) + 1))  \
+       for_each_set_bit((k), (map), GRU_CBR_AU)                        \
                for ((i) = (k)*GRU_CBR_AU_SIZE;                         \
                                (i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++)
 
 /* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */
 #define for_each_dsr_in_allocation_map(i, map, k)                      \
-       for ((k) = find_first_bit((const unsigned long *)map, GRU_DSR_AU);\
-                       (k) < GRU_DSR_AU;                               \
-                       (k) = find_next_bit((const unsigned long *)map, \
-                                         GRU_DSR_AU, (k) + 1))         \
+       for_each_set_bit((k), (const unsigned long *)(map), GRU_DSR_AU) \
                for ((i) = (k) * GRU_DSR_AU_CL;                         \
                                (i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++)
 
index f4b97d3..3168ebd 100644 (file)
@@ -1089,6 +1089,7 @@ void mmc_rescan(struct work_struct *work)
        mmc_claim_host(host);
 
        mmc_power_up(host);
+       sdio_reset(host);
        mmc_go_idle(host);
 
        mmc_send_if_cond(host, host->ocr_avail);
index 4eb7825..dea36d9 100644 (file)
@@ -67,13 +67,13 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
        return err;
 }
 
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
-       unsigned addr, u8 in, u8out)
+static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
+       unsigned addr, u8 in, u8 *out)
 {
        struct mmc_command cmd;
        int err;
 
-       BUG_ON(!card);
+       BUG_ON(!host);
        BUG_ON(fn > 7);
 
        /* sanity check */
@@ -90,11 +90,11 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        cmd.arg |= in;
        cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
 
-       err = mmc_wait_for_cmd(card->host, &cmd, 0);
+       err = mmc_wait_for_cmd(host, &cmd, 0);
        if (err)
                return err;
 
-       if (mmc_host_is_spi(card->host)) {
+       if (mmc_host_is_spi(host)) {
                /* host driver already reported errors */
        } else {
                if (cmd.resp[0] & R5_ERROR)
@@ -106,7 +106,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        }
 
        if (out) {
-               if (mmc_host_is_spi(card->host))
+               if (mmc_host_is_spi(host))
                        *out = (cmd.resp[0] >> 8) & 0xFF;
                else
                        *out = cmd.resp[0] & 0xFF;
@@ -115,6 +115,13 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        return 0;
 }
 
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+       unsigned addr, u8 in, u8 *out)
+{
+       BUG_ON(!card);
+       return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
+}
+
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
@@ -182,3 +189,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        return 0;
 }
 
+int sdio_reset(struct mmc_host *host)
+{
+       int ret;
+       u8 abort;
+
+       /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
+
+       ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+       if (ret)
+               abort = 0x08;
+       else
+               abort |= 0x08;
+
+       ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+       return ret;
+}
+
index e2e74b0..12a4d3a 100644 (file)
@@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, u8 in, u8* out);
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+int sdio_reset(struct mmc_host *host);
 
 #endif
 
index 60a2b69..faa7b76 100644 (file)
@@ -708,7 +708,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 65535;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-       mmc->max_seg_size = mmc->max_seg_size;
+       mmc->max_seg_size = mmc->max_req_size;
 
        host = mmc_priv(mmc);
        host->base = ioremap(r->start, resource_size(r));
index bc45ef9..fad40aa 100644 (file)
@@ -89,7 +89,8 @@ DEFINE_MUTEX(ubi_devices_mutex);
 static DEFINE_SPINLOCK(ubi_devices_lock);
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
-static ssize_t ubi_version_show(struct class *class, char *buf)
+static ssize_t ubi_version_show(struct class *class, struct class_attribute *attr,
+                               char *buf)
 {
        return sprintf(buf, "%d\n", UBI_VERSION);
 }
index 5acd557..b8bec08 100644 (file)
@@ -51,7 +51,9 @@
  * "show" function for the bond_masters attribute.
  * The class parameter is ignored.
  */
-static ssize_t bonding_show_bonds(struct class *cls, char *buf)
+static ssize_t bonding_show_bonds(struct class *cls,
+                                 struct class_attribute *attr,
+                                 char *buf)
 {
        struct net *net = current->nsproxy->net_ns;
        struct bond_net *bn = net_generic(net, bond_net_id);
@@ -98,6 +100,7 @@ static struct net_device *bond_get_by_name(struct net *net, const char *ifname)
  */
 
 static ssize_t bonding_store_bonds(struct class *cls,
+                                  struct class_attribute *attr,
                                   const char *buffer, size_t count)
 {
        struct net *net = current->nsproxy->net_ns;
index f2b9379..0bc777b 100644 (file)
@@ -1577,7 +1577,7 @@ static struct attribute * veth_pool_attrs[] = {
        NULL,
 };
 
-static struct sysfs_ops veth_pool_ops = {
+static const struct sysfs_ops veth_pool_ops = {
        .show   = veth_pool_show,
        .store  = veth_pool_store,
 };
index 966de5d..e6e972d 100644 (file)
@@ -384,7 +384,7 @@ static struct attribute *veth_cnx_default_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops veth_cnx_sysfs_ops = {
+static const struct sysfs_ops veth_cnx_sysfs_ops = {
                .show = veth_cnx_attribute_show
 };
 
@@ -441,7 +441,7 @@ static struct attribute *veth_port_default_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops veth_port_sysfs_ops = {
+static const struct sysfs_ops veth_port_sysfs_ops = {
        .show = veth_port_attribute_show
 };
 
index 0bc5d47..1062b8f 100644 (file)
@@ -481,7 +481,7 @@ pdcspath_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static struct sysfs_ops pdcspath_attr_ops = {
+static const struct sysfs_ops pdcspath_attr_ops = {
        .show = pdcspath_attr_show,
        .store = pdcspath_attr_store,
 };
index 712250f..26301cb 100644 (file)
@@ -288,9 +288,9 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
                        next = dev->bus_list.next;
 
                /* Run device routines with the device locked */
-               down(&dev->dev.sem);
+               device_lock(&dev->dev);
                retval = cb(dev, userdata);
-               up(&dev->dev.sem);
+               device_unlock(&dev->dev);
                if (retval)
                        break;
        }
index 6151389..0a894ef 100644 (file)
@@ -73,7 +73,7 @@ static void legacy_release(struct kobject *kobj)
 }
 
 static struct kobj_type legacy_ktype = {
-       .sysfs_ops = &(struct sysfs_ops){
+       .sysfs_ops = &(const struct sysfs_ops){
                .store = legacy_store, .show = legacy_show
        },
        .release = &legacy_release,
index 807224e..de29645 100644 (file)
@@ -642,6 +642,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        if (!b->legacy_io)
                goto kzalloc_err;
 
+       sysfs_bin_attr_init(b->legacy_io);
        b->legacy_io->attr.name = "legacy_io";
        b->legacy_io->size = 0xffff;
        b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
@@ -654,6 +655,7 @@ void pci_create_legacy_files(struct pci_bus *b)
                goto legacy_io_err;
 
        /* Allocated above after the legacy_io struct */
+       sysfs_bin_attr_init(b->legacy_mem);
        b->legacy_mem = b->legacy_io + 1;
        b->legacy_mem->attr.name = "legacy_mem";
        b->legacy_mem->size = 1024*1024;
@@ -800,6 +802,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
        if (res_attr) {
                char *res_attr_name = (char *)(res_attr + 1);
 
+               sysfs_bin_attr_init(res_attr);
                if (write_combine) {
                        pdev->res_attr_wc[num] = res_attr;
                        sprintf(res_attr_name, "resource%d_wc", num);
@@ -972,6 +975,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
                if (!attr)
                        return -ENOMEM;
 
+               sysfs_bin_attr_init(attr);
                attr->size = dev->vpd->len;
                attr->attr.name = "vpd";
                attr->attr.mode = S_IRUSR | S_IWUSR;
@@ -1038,6 +1042,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
                        retval = -ENOMEM;
                        goto err_resource_files;
                }
+               sysfs_bin_attr_init(attr);
                attr->size = rom_size;
                attr->attr.name = "rom";
                attr->attr.mode = S_IRUSR;
index 77b493b..cb1dd5f 100644 (file)
@@ -1583,8 +1583,10 @@ void pci_pm_init(struct pci_dev *dev)
        int pm;
        u16 pmc;
 
+       pm_runtime_forbid(&dev->dev);
        device_enable_async_suspend(&dev->dev);
        dev->wakeup_prepared = false;
+
        dev->pm_cap = 0;
 
        /* find PCI PM capability in list */
@@ -2296,35 +2298,6 @@ void pci_msi_off(struct pci_dev *dev)
        }
 }
 
-#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
-/*
- * These can be overridden by arch-specific implementations
- */
-int
-pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       if (!pci_dma_supported(dev, mask))
-               return -EIO;
-
-       dev->dma_mask = mask;
-       dev_dbg(&dev->dev, "using %dbit DMA mask\n", fls64(mask));
-
-       return 0;
-}
-    
-int
-pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       if (!pci_dma_supported(dev, mask))
-               return -EIO;
-
-       dev->dev.coherent_dma_mask = mask;
-       dev_dbg(&dev->dev, "using %dbit consistent DMA mask\n", fls64(mask));
-
-       return 0;
-}
-#endif
-
 #ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE
 int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
 {
@@ -2486,7 +2459,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
        if (!probe) {
                pci_block_user_cfg_access(dev);
                /* block PM suspend, driver probe, etc. */
-               down(&dev->dev.sem);
+               device_lock(&dev->dev);
        }
 
        rc = pci_dev_specific_reset(dev, probe);
@@ -2508,7 +2481,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
        rc = pci_parent_bus_reset(dev, probe);
 done:
        if (!probe) {
-               up(&dev->dev.sem);
+               device_unlock(&dev->dev);
                pci_unblock_user_cfg_access(dev);
        }
 
@@ -3066,8 +3039,6 @@ EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_try_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
 EXPORT_SYMBOL_GPL(pci_intx);
-EXPORT_SYMBOL(pci_set_dma_mask);
-EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_find_parent_resource);
 EXPORT_SYMBOL(pci_select_bars);
index 49c9e6c..f75a44d 100644 (file)
@@ -29,7 +29,7 @@ static ssize_t pci_slot_attr_store(struct kobject *kobj,
        return attribute->store ? attribute->store(slot, buf, len) : -EIO;
 }
 
-static struct sysfs_ops pci_slot_sysfs_ops = {
+static const struct sysfs_ops pci_slot_sysfs_ops = {
        .show = pci_slot_attr_show,
        .store = pci_slot_attr_store,
 };
index 0f98be4..ad93ebd 100644 (file)
@@ -971,9 +971,9 @@ static int runtime_suspend(struct device *dev)
 {
        int rc;
 
-       down(&dev->sem);
+       device_lock(dev);
        rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
-       up(&dev->sem);
+       device_unlock(dev);
        return rc;
 }
 
@@ -981,9 +981,9 @@ static int runtime_resume(struct device *dev)
 {
        int rc;
 
-       down(&dev->sem);
+       device_lock(dev);
        rc = pcmcia_dev_resume(dev);
-       up(&dev->sem);
+       device_unlock(dev);
        return rc;
 }
 
index cd2ee6f..e631dbe 100644 (file)
@@ -150,6 +150,7 @@ config MSI_LAPTOP
        tristate "MSI Laptop Extras"
        depends on ACPI
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on RFKILL
        ---help---
          This is a driver for laptops built by MSI (MICRO-STAR
          INTERNATIONAL):
index 3aa57da..7ccf33c 100644 (file)
@@ -57,7 +57,7 @@ enum hp_wmi_radio {
        HPWMI_WWAN = 2,
 };
 
-static int __init hp_wmi_bios_setup(struct platform_device *device);
+static int __devinit hp_wmi_bios_setup(struct platform_device *device);
 static int __exit hp_wmi_bios_remove(struct platform_device *device);
 static int hp_wmi_resume_handler(struct device *device);
 
@@ -447,7 +447,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_tablet);
 }
 
-static int __init hp_wmi_bios_setup(struct platform_device *device)
+static int __devinit hp_wmi_bios_setup(struct platform_device *device)
 {
        int err;
        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
index 759763d..c2b05da 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
+#include <linux/rfkill.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
 #define MSI_EC_COMMAND_WIRELESS 0x10
 #define MSI_EC_COMMAND_LCD_LEVEL 0x11
 
+#define MSI_STANDARD_EC_COMMAND_ADDRESS        0x2e
+#define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
+#define MSI_STANDARD_EC_WEBCAM_MASK    (1 << 1)
+#define MSI_STANDARD_EC_WLAN_MASK      (1 << 3)
+#define MSI_STANDARD_EC_3G_MASK                (1 << 4)
+
+/* For set SCM load flag to disable BIOS fn key */
+#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS       0x2d
+#define MSI_STANDARD_EC_SCM_LOAD_MASK          (1 << 0)
+
+static int msi_laptop_resume(struct platform_device *device);
+
+#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
+
 static int force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -74,6 +89,23 @@ static int auto_brightness;
 module_param(auto_brightness, int, 0);
 MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
 
+static bool old_ec_model;
+static int wlan_s, bluetooth_s, threeg_s;
+static int threeg_exists;
+
+/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
+ * those netbook will load the SCM (windows app) to disable the original
+ * Wlan/Bluetooth control by BIOS when user press fn key, then control
+ * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
+ * cann't on/off 3G module on those 3G netbook.
+ * On Linux, msi-laptop driver will do the same thing to disable the
+ * original BIOS control, then might need use HAL or other userland
+ * application to do the software control that simulate with SCM.
+ * e.g. MSI N034 netbook
+ */
+static bool load_scm_model;
+static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
+
 /* Hardware access */
 
 static int set_lcd_level(int level)
@@ -130,6 +162,35 @@ static int set_auto_brightness(int enable)
        return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
 }
 
+static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
+{
+       int status;
+       u8 wdata = 0, rdata;
+       int result;
+
+       if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
+               return -EINVAL;
+
+       /* read current device state */
+       result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+       if (result < 0)
+               return -EINVAL;
+
+       if (!!(rdata & mask) != status) {
+               /* reverse device bit */
+               if (rdata & mask)
+                       wdata = rdata & ~mask;
+               else
+                       wdata = rdata | mask;
+
+               result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
+               if (result < 0)
+                       return -EINVAL;
+       }
+
+       return count;
+}
+
 static int get_wireless_state(int *wlan, int *bluetooth)
 {
        u8 wdata = 0, rdata;
@@ -148,6 +209,38 @@ static int get_wireless_state(int *wlan, int *bluetooth)
        return 0;
 }
 
+static int get_wireless_state_ec_standard(void)
+{
+       u8 rdata;
+       int result;
+
+       result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+       if (result < 0)
+               return -1;
+
+       wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
+
+       bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+       threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+       return 0;
+}
+
+static int get_threeg_exists(void)
+{
+       u8 rdata;
+       int result;
+
+       result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
+       if (result < 0)
+               return -1;
+
+       threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+       return 0;
+}
+
 /* Backlight device stuff */
 
 static int bl_get_brightness(struct backlight_device *b)
@@ -176,26 +269,71 @@ static ssize_t show_wlan(struct device *dev,
 
        int ret, enabled;
 
-       ret = get_wireless_state(&enabled, NULL);
+       if (old_ec_model) {
+               ret = get_wireless_state(&enabled, NULL);
+       } else {
+               ret = get_wireless_state_ec_standard();
+               enabled = wlan_s;
+       }
        if (ret < 0)
                return ret;
 
        return sprintf(buf, "%i\n", enabled);
 }
 
+static ssize_t store_wlan(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
+}
+
 static ssize_t show_bluetooth(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
 
        int ret, enabled;
 
-       ret = get_wireless_state(NULL, &enabled);
+       if (old_ec_model) {
+               ret = get_wireless_state(NULL, &enabled);
+       } else {
+               ret = get_wireless_state_ec_standard();
+               enabled = bluetooth_s;
+       }
        if (ret < 0)
                return ret;
 
        return sprintf(buf, "%i\n", enabled);
 }
 
+static ssize_t store_bluetooth(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
+}
+
+static ssize_t show_threeg(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+
+       int ret;
+
+       /* old msi ec not support 3G */
+       if (old_ec_model)
+               return -1;
+
+       ret = get_wireless_state_ec_standard();
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", threeg_s);
+}
+
+static ssize_t store_threeg(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
+}
+
 static ssize_t show_lcd_level(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -258,6 +396,7 @@ static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
 static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
 
 static struct attribute *msipf_attributes[] = {
        &dev_attr_lcd_level.attr,
@@ -275,7 +414,8 @@ static struct platform_driver msipf_driver = {
        .driver = {
                .name = "msi-laptop-pf",
                .owner = THIS_MODULE,
-       }
+       },
+       .resume = msi_laptop_resume,
 };
 
 static struct platform_device *msipf_device;
@@ -332,6 +472,192 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
        { }
 };
 
+static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
+       {
+               .ident = "MSI N034",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                               "MICRO-STAR INTERNATIONAL CO., LTD"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
+                       DMI_MATCH(DMI_CHASSIS_VENDOR,
+                       "MICRO-STAR INTERNATIONAL CO., LTD")
+               },
+               .callback = dmi_check_cb
+       },
+       { }
+};
+
+static int rfkill_bluetooth_set(void *data, bool blocked)
+{
+       /* Do something with blocked...*/
+       /*
+        * blocked == false is on
+        * blocked == true is off
+        */
+       if (blocked)
+               set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+       else
+               set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+       return 0;
+}
+
+static int rfkill_wlan_set(void *data, bool blocked)
+{
+       if (blocked)
+               set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
+       else
+               set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
+
+       return 0;
+}
+
+static int rfkill_threeg_set(void *data, bool blocked)
+{
+       if (blocked)
+               set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
+       else
+               set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
+
+       return 0;
+}
+
+static struct rfkill_ops rfkill_bluetooth_ops = {
+       .set_block = rfkill_bluetooth_set
+};
+
+static struct rfkill_ops rfkill_wlan_ops = {
+       .set_block = rfkill_wlan_set
+};
+
+static struct rfkill_ops rfkill_threeg_ops = {
+       .set_block = rfkill_threeg_set
+};
+
+static void rfkill_cleanup(void)
+{
+       if (rfk_bluetooth) {
+               rfkill_unregister(rfk_bluetooth);
+               rfkill_destroy(rfk_bluetooth);
+       }
+
+       if (rfk_threeg) {
+               rfkill_unregister(rfk_threeg);
+               rfkill_destroy(rfk_threeg);
+       }
+
+       if (rfk_wlan) {
+               rfkill_unregister(rfk_wlan);
+               rfkill_destroy(rfk_wlan);
+       }
+}
+
+static int rfkill_init(struct platform_device *sdev)
+{
+       /* add rfkill */
+       int retval;
+
+       rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
+                               RFKILL_TYPE_BLUETOOTH,
+                               &rfkill_bluetooth_ops, NULL);
+       if (!rfk_bluetooth) {
+               retval = -ENOMEM;
+               goto err_bluetooth;
+       }
+       retval = rfkill_register(rfk_bluetooth);
+       if (retval)
+               goto err_bluetooth;
+
+       rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
+                               &rfkill_wlan_ops, NULL);
+       if (!rfk_wlan) {
+               retval = -ENOMEM;
+               goto err_wlan;
+       }
+       retval = rfkill_register(rfk_wlan);
+       if (retval)
+               goto err_wlan;
+
+       if (threeg_exists) {
+               rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
+                               RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
+               if (!rfk_threeg) {
+                       retval = -ENOMEM;
+                       goto err_threeg;
+               }
+               retval = rfkill_register(rfk_threeg);
+               if (retval)
+                       goto err_threeg;
+       }
+
+       return 0;
+
+err_threeg:
+       rfkill_destroy(rfk_threeg);
+       if (rfk_wlan)
+               rfkill_unregister(rfk_wlan);
+err_wlan:
+       rfkill_destroy(rfk_wlan);
+       if (rfk_bluetooth)
+               rfkill_unregister(rfk_bluetooth);
+err_bluetooth:
+       rfkill_destroy(rfk_bluetooth);
+
+       return retval;
+}
+
+static int msi_laptop_resume(struct platform_device *device)
+{
+       u8 data;
+       int result;
+
+       if (!load_scm_model)
+               return 0;
+
+       /* set load SCM to disable hardware control by fn key */
+       result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+       if (result < 0)
+               return result;
+
+       result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+               data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+       if (result < 0)
+               return result;
+
+       return 0;
+}
+
+static int load_scm_model_init(struct platform_device *sdev)
+{
+       u8 data;
+       int result;
+
+       /* allow userland write sysfs file  */
+       dev_attr_bluetooth.store = store_bluetooth;
+       dev_attr_wlan.store = store_wlan;
+       dev_attr_threeg.store = store_threeg;
+       dev_attr_bluetooth.attr.mode |= S_IWUSR;
+       dev_attr_wlan.attr.mode |= S_IWUSR;
+       dev_attr_threeg.attr.mode |= S_IWUSR;
+
+       /* disable hardware control by fn key */
+       result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+       if (result < 0)
+               return result;
+
+       result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+               data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+       if (result < 0)
+               return result;
+
+       /* initial rfkill */
+       result = rfkill_init(sdev);
+       if (result < 0)
+               return result;
+
+       return 0;
+}
+
 static int __init msi_init(void)
 {
        int ret;
@@ -339,8 +665,14 @@ static int __init msi_init(void)
        if (acpi_disabled)
                return -ENODEV;
 
-       if (!force && !dmi_check_system(msi_dmi_table))
-               return -ENODEV;
+       if (force || dmi_check_system(msi_dmi_table))
+               old_ec_model = 1;
+
+       if (!old_ec_model)
+               get_threeg_exists();
+
+       if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
+               load_scm_model = 1;
 
        if (auto_brightness < 0 || auto_brightness > 2)
                return -EINVAL;
@@ -374,10 +706,23 @@ static int __init msi_init(void)
        if (ret)
                goto fail_platform_device1;
 
+       if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
+               ret = -EINVAL;
+               goto fail_platform_device1;
+       }
+
        ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
        if (ret)
                goto fail_platform_device2;
 
+       if (!old_ec_model) {
+               if (threeg_exists)
+                       ret = device_create_file(&msipf_device->dev,
+                                               &dev_attr_threeg);
+               if (ret)
+                       goto fail_platform_device2;
+       }
+
        /* Disable automatic brightness control by default because
         * this module was probably loaded to do brightness control in
         * software. */
@@ -412,10 +757,14 @@ static void __exit msi_cleanup(void)
 {
 
        sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+       if (!old_ec_model && threeg_exists)
+               device_remove_file(&msipf_device->dev, &dev_attr_threeg);
        platform_device_unregister(msipf_device);
        platform_driver_unregister(&msipf_driver);
        backlight_device_unregister(msibl_device);
 
+       rfkill_cleanup();
+
        /* Enable automatic brightness control again */
        if (auto_brightness != 2)
                set_auto_brightness(1);
@@ -435,3 +784,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARIN
 MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
 MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
 MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
index cc2eb8e..1afe4e0 100644 (file)
@@ -30,4 +30,6 @@ config PPS_DEBUG
          messages to the system log.  Select this if you are having a
          problem with PPS support and want to see more of what is going on.
 
+source drivers/pps/clients/Kconfig
+
 endmenu
index 19ea582..98960dd 100644 (file)
@@ -4,5 +4,6 @@
 
 pps_core-y                     := pps.o kapi.o sysfs.o
 obj-$(CONFIG_PPS)              := pps_core.o
+obj-y                          += clients/
 
 ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
new file mode 100644 (file)
index 0000000..4e801bd
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# PPS clients configuration
+#
+
+if PPS
+
+comment "PPS clients support"
+
+config PPS_CLIENT_KTIMER
+       tristate "Kernel timer client (Testing client, use for debug)"
+       help
+         If you say yes here you get support for a PPS debugging client
+         which uses a kernel timer to generate the PPS signal.
+
+         This driver can also be built as a module.  If so, the module
+         will be called pps-ktimer.
+
+config PPS_CLIENT_LDISC
+       tristate "PPS line discipline"
+       depends on PPS
+       help
+         If you say yes here you get support for a PPS source connected
+         with the CD (Carrier Detect) pin of your serial port.
+
+endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
new file mode 100644 (file)
index 0000000..812c9b1
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for PPS clients.
+#
+
+obj-$(CONFIG_PPS_CLIENT_KTIMER)        += pps-ktimer.o
+obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
+
+ifeq ($(CONFIG_PPS_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
new file mode 100644 (file)
index 0000000..e7ef5b8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * pps-ktimer.c -- kernel timer test client
+ *
+ *
+ * Copyright (C) 2005-2006   Rodolfo Giometti <giometti@linux.it>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/pps_kernel.h>
+
+/*
+ * Global variables
+ */
+
+static int source;
+static struct timer_list ktimer;
+
+/*
+ * The kernel timer
+ */
+
+static void pps_ktimer_event(unsigned long ptr)
+{
+       struct timespec __ts;
+       struct pps_ktime ts;
+
+       /* First of all we get the time stamp... */
+       getnstimeofday(&__ts);
+
+       pr_info("PPS event at %lu\n", jiffies);
+
+       /* ... and translate it to PPS time data struct */
+       ts.sec = __ts.tv_sec;
+       ts.nsec = __ts.tv_nsec;
+
+       pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
+
+       mod_timer(&ktimer, jiffies + HZ);
+}
+
+/*
+ * The echo function
+ */
+
+static void pps_ktimer_echo(int source, int event, void *data)
+{
+       pr_info("echo %s %s for source %d\n",
+               event & PPS_CAPTUREASSERT ? "assert" : "",
+               event & PPS_CAPTURECLEAR ? "clear" : "",
+               source);
+}
+
+/*
+ * The PPS info struct
+ */
+
+static struct pps_source_info pps_ktimer_info = {
+       .name           = "ktimer",
+       .path           = "",
+       .mode           = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
+                         PPS_ECHOASSERT |
+                         PPS_CANWAIT | PPS_TSFMT_TSPEC,
+       .echo           = pps_ktimer_echo,
+       .owner          = THIS_MODULE,
+};
+
+/*
+ * Module staff
+ */
+
+static void __exit pps_ktimer_exit(void)
+{
+       del_timer_sync(&ktimer);
+       pps_unregister_source(source);
+
+       pr_info("ktimer PPS source unregistered\n");
+}
+
+static int __init pps_ktimer_init(void)
+{
+       int ret;
+
+       ret = pps_register_source(&pps_ktimer_info,
+                               PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
+       if (ret < 0) {
+               printk(KERN_ERR "cannot register ktimer source\n");
+               return ret;
+       }
+       source = ret;
+
+       setup_timer(&ktimer, pps_ktimer_event, 0);
+       mod_timer(&ktimer, jiffies + HZ);
+
+       pr_info("ktimer PPS source registered at %d\n", source);
+
+       return  0;
+}
+
+module_init(pps_ktimer_init);
+module_exit(pps_ktimer_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("dummy PPS source by using a kernel timer (just for debug)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
new file mode 100644 (file)
index 0000000..8e1932d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * pps-ldisc.c -- PPS line discipline
+ *
+ *
+ * Copyright (C) 2008  Rodolfo Giometti <giometti@linux.it>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You 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/serial_core.h>
+#include <linux/tty.h>
+#include <linux/pps_kernel.h>
+
+#define PPS_TTY_MAGIC          0x0001
+
+static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
+                               struct timespec *ts)
+{
+       int id = (long)tty->disc_data;
+       struct timespec __ts;
+       struct pps_ktime pps_ts;
+
+       /* First of all we get the time stamp... */
+       getnstimeofday(&__ts);
+
+       /* Does caller give us a timestamp? */
+       if (ts) {       /* Yes. Let's use it! */
+               pps_ts.sec = ts->tv_sec;
+               pps_ts.nsec = ts->tv_nsec;
+       } else {        /* No. Do it ourself! */
+               pps_ts.sec = __ts.tv_sec;
+               pps_ts.nsec = __ts.tv_nsec;
+       }
+
+       /* Now do the PPS event report */
+       pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
+                       NULL);
+
+       pr_debug("PPS %s at %lu on source #%d\n",
+                       status ? "assert" : "clear", jiffies, id);
+}
+
+static int (*alias_n_tty_open)(struct tty_struct *tty);
+
+static int pps_tty_open(struct tty_struct *tty)
+{
+       struct pps_source_info info;
+       struct tty_driver *drv = tty->driver;
+       int index = tty->index + drv->name_base;
+       int ret;
+
+       info.owner = THIS_MODULE;
+       info.dev = NULL;
+       snprintf(info.name, PPS_MAX_NAME_LEN, "%s%d", drv->driver_name, index);
+       snprintf(info.path, PPS_MAX_NAME_LEN, "/dev/%s%d", drv->name, index);
+       info.mode = PPS_CAPTUREBOTH | \
+                       PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
+                       PPS_CANWAIT | PPS_TSFMT_TSPEC;
+
+       ret = pps_register_source(&info, PPS_CAPTUREBOTH | \
+                               PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
+       if (ret < 0) {
+               pr_err("cannot register PPS source \"%s\"\n", info.path);
+               return ret;
+       }
+       tty->disc_data = (void *)(long)ret;
+
+       /* Should open N_TTY ldisc too */
+       ret = alias_n_tty_open(tty);
+       if (ret < 0)
+               pps_unregister_source((long)tty->disc_data);
+
+       pr_info("PPS source #%d \"%s\" added\n", ret, info.path);
+
+       return 0;
+}
+
+static void (*alias_n_tty_close)(struct tty_struct *tty);
+
+static void pps_tty_close(struct tty_struct *tty)
+{
+       int id = (long)tty->disc_data;
+
+       pps_unregister_source(id);
+       alias_n_tty_close(tty);
+
+       pr_info("PPS source #%d removed\n", id);
+}
+
+static struct tty_ldisc_ops pps_ldisc_ops;
+
+/*
+ * Module stuff
+ */
+
+static int __init pps_tty_init(void)
+{
+       int err;
+
+       /* Inherit the N_TTY's ops */
+       n_tty_inherit_ops(&pps_ldisc_ops);
+
+       /* Save N_TTY's open()/close() methods */
+       alias_n_tty_open = pps_ldisc_ops.open;
+       alias_n_tty_close = pps_ldisc_ops.close;
+
+       /* Init PPS_TTY data */
+       pps_ldisc_ops.owner = THIS_MODULE;
+       pps_ldisc_ops.magic = PPS_TTY_MAGIC;
+       pps_ldisc_ops.name = "pps_tty";
+       pps_ldisc_ops.dcd_change = pps_tty_dcd_change;
+       pps_ldisc_ops.open = pps_tty_open;
+       pps_ldisc_ops.close = pps_tty_close;
+
+       err = tty_register_ldisc(N_PPS, &pps_ldisc_ops);
+       if (err)
+               pr_err("can't register PPS line discipline\n");
+       else
+               pr_info("PPS line discipline registered\n");
+
+       return err;
+}
+
+static void __exit pps_tty_cleanup(void)
+{
+       int err;
+
+       err = tty_unregister_ldisc(N_PPS);
+       if (err)
+               pr_err("can't unregister PPS line discipline\n");
+       else
+               pr_info("PPS line discipline removed\n");
+}
+
+module_init(pps_tty_init);
+module_exit(pps_tty_cleanup);
+
+MODULE_ALIAS_LDISC(N_PPS);
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("PPS TTY device driver");
+MODULE_LICENSE("GPL");
index 33c0e98..bc90b09 100644 (file)
  * the best guess is to add 0.5s.
  */
 
+int rtc_hctosys_ret = -ENODEV;
+
 static int __init rtc_hctosys(void)
 {
-       int err;
+       int err = -ENODEV;
        struct rtc_time tm;
+       struct timespec tv = {
+               .tv_nsec = NSEC_PER_SEC >> 1,
+       };
        struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
 
        if (rtc == NULL) {
-               printk("%s: unable to open rtc device (%s)\n",
+               pr_err("%s: unable to open rtc device (%s)\n",
                        __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
-               return -ENODEV;
+               goto err_open;
        }
 
        err = rtc_read_time(rtc, &tm);
-       if (err == 0) {
-               err = rtc_valid_tm(&tm);
-               if (err == 0) {
-                       struct timespec tv;
+       if (err) {
+               dev_err(rtc->dev.parent,
+                       "hctosys: unable to read the hardware clock\n");
+               goto err_read;
 
-                       tv.tv_nsec = NSEC_PER_SEC >> 1;
+       }
 
-                       rtc_tm_to_time(&tm, &tv.tv_sec);
+       err = rtc_valid_tm(&tm);
+       if (err) {
+               dev_err(rtc->dev.parent,
+                       "hctosys: invalid date/time\n");
+               goto err_invalid;
+       }
 
-                       do_settimeofday(&tv);
+       rtc_tm_to_time(&tm, &tv.tv_sec);
 
-                       dev_info(rtc->dev.parent,
-                               "setting system clock to "
-                               "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
-                               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-                               tm.tm_hour, tm.tm_min, tm.tm_sec,
-                               (unsigned int) tv.tv_sec);
-               }
-               else
-                       dev_err(rtc->dev.parent,
-                               "hctosys: invalid date/time\n");
-       }
-       else
-               dev_err(rtc->dev.parent,
-                       "hctosys: unable to read the hardware clock\n");
+       do_settimeofday(&tv);
 
+       dev_info(rtc->dev.parent,
+               "setting system clock to "
+               "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+               tm.tm_hour, tm.tm_min, tm.tm_sec,
+               (unsigned int) tv.tv_sec);
+
+err_invalid:
+err_read:
        rtc_class_close(rtc);
 
-       return 0;
+err_open:
+       rtc_hctosys_ret = err;
+
+       return err;
 }
 
 late_initcall(rtc_hctosys);
index 7dd23a6..380083c 100644 (file)
@@ -107,8 +107,9 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
-       if (strcmp(dev_name(&to_rtc_device(dev)->dev),
-                  CONFIG_RTC_HCTOSYS_DEVICE) == 0)
+       if (rtc_hctosys_ret == 0 &&
+                       strcmp(dev_name(&to_rtc_device(dev)->dev),
+                               CONFIG_RTC_HCTOSYS_DEVICE) == 0)
                return sprintf(buf, "1\n");
        else
 #endif
index 4951aa8..bbea90b 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/ebcdic.h>
 #include <asm/idals.h>
 #include <asm/itcw.h>
+#include <asm/diag.h>
 
 /* This is ugly... */
 #define PRINTK_HEADER "dasd:"
@@ -2212,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
                goto out;
        }
 
+       if ((mode & FMODE_WRITE) &&
+           (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) ||
+            (base->features & DASD_FEATURE_READONLY))) {
+               rc = -EROFS;
+               goto out;
+       }
+
        return 0;
 
 out:
@@ -2289,6 +2297,34 @@ dasd_exit(void)
  * SECTION: common functions for ccw_driver use
  */
 
+/*
+ * Is the device read-only?
+ * Note that this function does not report the setting of the
+ * readonly device attribute, but how it is configured in z/VM.
+ */
+int dasd_device_is_ro(struct dasd_device *device)
+{
+       struct ccw_dev_id dev_id;
+       struct diag210 diag_data;
+       int rc;
+
+       if (!MACHINE_IS_VM)
+               return 0;
+       ccw_device_get_id(device->cdev, &dev_id);
+       memset(&diag_data, 0, sizeof(diag_data));
+       diag_data.vrdcdvno = dev_id.devno;
+       diag_data.vrdclen = sizeof(diag_data);
+       rc = diag210(&diag_data);
+       if (rc == 0 || rc == 2) {
+               return diag_data.vrdcvfla & 0x80;
+       } else {
+               DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d",
+                         dev_id.devno, rc);
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(dasd_device_is_ro);
+
 static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
 {
        struct ccw_device *cdev = data;
index 44796ba..51224f7 100644 (file)
@@ -1045,6 +1045,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 
                erp->retries = 5;
 
+       } else if (sense[1] & SNS1_WRITE_INHIBITED) {
+               dev_err(&device->cdev->dev, "An I/O request was rejected"
+                       " because writing is inhibited\n");
+               erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
        } else {
                /* fatal error -  set status to FAILED
                   internal error 09 - Command Reject */
index d49766f..8e23919 100644 (file)
@@ -742,6 +742,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
              const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
+       struct dasd_device *device;
        int val;
        char *endp;
 
@@ -758,12 +759,14 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
                devmap->features |= DASD_FEATURE_READONLY;
        else
                devmap->features &= ~DASD_FEATURE_READONLY;
-       if (devmap->device)
-               devmap->device->features = devmap->features;
-       if (devmap->device && devmap->device->block
-           && devmap->device->block->gdp)
-               set_disk_ro(devmap->device->block->gdp, val);
+       device = devmap->device;
+       if (device) {
+               device->features = devmap->features;
+               val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+       }
        spin_unlock(&dasd_devmap_lock);
+       if (device && device->block && device->block->gdp)
+               set_disk_ro(device->block->gdp, val);
        return count;
 }
 
index 6e14863..687f323 100644 (file)
@@ -145,12 +145,10 @@ dasd_diag_erp(struct dasd_device *device)
        mdsk_term_io(device);
        rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
        if (rc == 4) {
-               if (!(device->features & DASD_FEATURE_READONLY)) {
+               if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))
                        pr_warning("%s: The access mode of a DIAG device "
                                   "changed to read-only\n",
                                   dev_name(&device->cdev->dev));
-                       device->features |= DASD_FEATURE_READONLY;
-               }
                rc = 0;
        }
        if (rc)
@@ -449,7 +447,7 @@ dasd_diag_check_device(struct dasd_device *device)
                rc = -EIO;
        } else {
                if (rc == 4)
-                       device->features |= DASD_FEATURE_READONLY;
+                       set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
                pr_info("%s: New DASD with %ld byte/block, total size %ld "
                        "KB%s\n", dev_name(&device->cdev->dev),
                        (unsigned long) block->bp_block,
index 1cca21a..01f4e7a 100644 (file)
@@ -1089,6 +1089,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        struct dasd_eckd_private *private;
        struct dasd_block *block;
        int is_known, rc;
+       int readonly;
 
        if (!ccw_device_is_pathgroup(device->cdev)) {
                dev_warn(&device->cdev->dev,
@@ -1182,15 +1183,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        else
                private->real_cyl = private->rdc_data.no_cyl;
 
+       readonly = dasd_device_is_ro(device);
+       if (readonly)
+               set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+
        dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
-                "with %d cylinders, %d heads, %d sectors\n",
+                "with %d cylinders, %d heads, %d sectors%s\n",
                 private->rdc_data.dev_type,
                 private->rdc_data.dev_model,
                 private->rdc_data.cu_type,
                 private->rdc_data.cu_model.model,
                 private->real_cyl,
                 private->rdc_data.trk_per_cyl,
-                private->rdc_data.sec_per_trk);
+                private->rdc_data.sec_per_trk,
+                readonly ? ", read-only device" : "");
        return 0;
 
 out_err3:
@@ -2839,8 +2845,13 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
        char *psf_data, *rssd_result;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
+       char psf0, psf1;
        int rc;
 
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EACCES;
+       psf0 = psf1 = 0;
+
        /* Copy parms from caller */
        rc = -EFAULT;
        if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
@@ -2869,12 +2880,8 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
                           (void __user *)(unsigned long) usrparm.psf_data,
                           usrparm.psf_data_len))
                goto out_free;
-
-       /* sanity check on syscall header */
-       if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
-               rc = -EINVAL;
-               goto out_free;
-       }
+       psf0 = psf_data[0];
+       psf1 = psf_data[1];
 
        /* setup CCWs for PSF + RSSD */
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device);
@@ -2925,7 +2932,9 @@ out_free:
        kfree(rssd_result);
        kfree(psf_data);
 out:
-       DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
+       DBF_DEV_EVENT(DBF_WARNING, device,
+                     "Symmetrix ioctl (0x%02x 0x%02x): rc=%d",
+                     (int) psf0, (int) psf1, rc);
        return rc;
 }
 
index 0f15244..37282b9 100644 (file)
@@ -124,6 +124,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
        struct dasd_fba_private *private;
        struct ccw_device *cdev = device->cdev;
        int rc;
+       int readonly;
 
        private = (struct dasd_fba_private *) device->private;
        if (!private) {
@@ -162,16 +163,21 @@ dasd_fba_check_characteristics(struct dasd_device *device)
                return rc;
        }
 
+       readonly = dasd_device_is_ro(device);
+       if (readonly)
+               set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+
        dev_info(&device->cdev->dev,
                 "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB "
-                "and %d B/blk\n",
+                "and %d B/blk%s\n",
                 cdev->id.dev_type,
                 cdev->id.dev_model,
                 cdev->id.cu_type,
                 cdev->id.cu_model,
                 ((private->rdc_data.blk_bdsa *
                   (private->rdc_data.blk_size >> 9)) >> 11),
-                private->rdc_data.blk_size);
+                private->rdc_data.blk_size,
+                readonly ? ", read-only device" : "");
        return 0;
 }
 
index 94f92a1..30a1ca3 100644 (file)
@@ -70,7 +70,8 @@ int dasd_gendisk_alloc(struct dasd_block *block)
        }
        len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
 
-       if (block->base->features & DASD_FEATURE_READONLY)
+       if (base->features & DASD_FEATURE_READONLY ||
+           test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
                set_disk_ro(gdp, 1);
        gdp->private_data = block;
        gdp->queue = block->request_queue;
index ed73ce5..a91d4a9 100644 (file)
@@ -436,6 +436,10 @@ struct dasd_block {
 #define DASD_FLAG_OFFLINE      3       /* device is in offline processing */
 #define DASD_FLAG_EER_SNSS     4       /* A SNSS is required */
 #define DASD_FLAG_EER_IN_USE   5       /* A SNSS request is running */
+#define DASD_FLAG_DEVICE_RO    6       /* The device itself is read-only. Don't
+                                        * confuse this with the user specified
+                                        * read-only feature.
+                                        */
 
 void dasd_put_device_wake(struct dasd_device *);
 
@@ -609,6 +613,9 @@ char *dasd_get_sense(struct irb *);
 void dasd_device_set_stop_bits(struct dasd_device *, int);
 void dasd_device_remove_stop_bits(struct dasd_device *, int);
 
+int dasd_device_is_ro(struct dasd_device *);
+
+
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
index 7039d9c..3479f81 100644 (file)
@@ -199,7 +199,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
        if (!argp)
                return -EINVAL;
 
-       if (block->base->features & DASD_FEATURE_READONLY)
+       if (block->base->features & DASD_FEATURE_READONLY ||
+           test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
                return -EROFS;
        if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
                return -EFAULT;
@@ -349,7 +350,8 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
                return -EINVAL;
        if (get_user(intval, (int __user *)argp))
                return -EFAULT;
-
+       if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
+               return -EROFS;
        set_disk_ro(bdev->bd_disk, intval);
        return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
 }
index c6abb75..6d229f3 100644 (file)
@@ -764,7 +764,7 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
 static void io_subchannel_register(struct ccw_device *cdev)
 {
        struct subchannel *sch;
-       int ret;
+       int ret, adjust_init_count = 1;
        unsigned long flags;
 
        sch = to_subchannel(cdev->dev.parent);
@@ -793,6 +793,7 @@ static void io_subchannel_register(struct ccw_device *cdev)
                                              cdev->private->dev_id.ssid,
                                              cdev->private->dev_id.devno);
                }
+               adjust_init_count = 0;
                goto out;
        }
        /*
@@ -818,7 +819,7 @@ out:
        cdev->private->flags.recog_done = 1;
        wake_up(&cdev->private->wait_q);
 out_err:
-       if (atomic_dec_and_test(&ccw_device_init_count))
+       if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count))
                wake_up(&ccw_device_init_wq);
 }
 
index c94eb2a..6ce83f5 100644 (file)
@@ -33,7 +33,6 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data,
        DBF_HEX(&init_data->input_handler, sizeof(void *));
        DBF_HEX(&init_data->output_handler, sizeof(void *));
        DBF_HEX(&init_data->int_parm, sizeof(long));
-       DBF_HEX(&init_data->flags, sizeof(long));
        DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
        DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
        DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
index 232ef04..4f8f743 100644 (file)
@@ -588,10 +588,11 @@ static void qdio_kick_handler(struct qdio_q *q)
        if (q->is_input_q) {
                qperf_inc(q, inbound_handler);
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count);
-       } else
+       } else {
                qperf_inc(q, outbound_handler);
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
                              start, count);
+       }
 
        q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
                   q->irq_ptr->int_parm);
index cb909a5..977bb4d 100644 (file)
@@ -43,6 +43,16 @@ config SMSGIUCV
          Select this option if you want to be able to receive SMSG messages
          from other VM guest systems.
 
+config SMSGIUCV_EVENT
+       tristate "Deliver IUCV special messages as uevents (VM only)"
+       depends on SMSGIUCV
+       help
+         Select this option to deliver CP special messages (SMSGs) as
+         uevents.  The driver handles only those special messages that
+         start with "APP".
+
+         To compile as a module, choose M. The module name is "smsgiucv_app".
+
 config CLAW
        tristate "CLAW device support"
        depends on CCW && NETDEVICES
index 6cab5a6..4dfe8c1 100644 (file)
@@ -6,6 +6,7 @@ ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o
 obj-$(CONFIG_CTCM) += ctcm.o fsm.o
 obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
 obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
+obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o
 obj-$(CONFIG_LCS) += lcs.o
 obj-$(CONFIG_CLAW) += claw.o
 qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o
index fa8a519..7d25bdd 100644 (file)
@@ -3805,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
        init_data.input_handler          = card->discipline.input_handler;
        init_data.output_handler         = card->discipline.output_handler;
        init_data.int_parm               = (unsigned long) card;
-       init_data.flags                  = QDIO_INBOUND_0COPY_SBALS |
-                                          QDIO_OUTBOUND_0COPY_SBALS |
-                                          QDIO_USE_OUTBOUND_PCIS;
        init_data.input_sbal_addr_array  = (void **) in_sbal_ptrs;
        init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
 
index 67f2485..ecef1ed 100644 (file)
@@ -31,9 +31,9 @@
 
 struct smsg_callback {
        struct list_head list;
-       char *prefix;
+       const char *prefix;
        int len;
-       void (*callback)(char *from, char *str);
+       void (*callback)(const char *from, char *str);
 };
 
 MODULE_AUTHOR
@@ -100,8 +100,8 @@ static void smsg_message_pending(struct iucv_path *path,
        kfree(buffer);
 }
 
-int smsg_register_callback(char *prefix,
-                          void (*callback)(char *from, char *str))
+int smsg_register_callback(const char *prefix,
+                          void (*callback)(const char *from, char *str))
 {
        struct smsg_callback *cb;
 
@@ -117,8 +117,9 @@ int smsg_register_callback(char *prefix,
        return 0;
 }
 
-void smsg_unregister_callback(char *prefix,
-                             void (*callback)(char *from, char *str))
+void smsg_unregister_callback(const char *prefix,
+                             void (*callback)(const char *from,
+                                              char *str))
 {
        struct smsg_callback *cb, *tmp;
 
@@ -176,7 +177,7 @@ static const struct dev_pm_ops smsg_pm_ops = {
 
 static struct device_driver smsg_driver = {
        .owner = THIS_MODULE,
-       .name = "SMSGIUCV",
+       .name = SMSGIUCV_DRV_NAME,
        .bus  = &iucv_bus,
        .pm = &smsg_pm_ops,
 };
index 67f5d4f..149a115 100644 (file)
@@ -5,6 +5,10 @@
  * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
-int  smsg_register_callback(char *, void (*)(char *, char *));
-void smsg_unregister_callback(char *, void (*)(char *, char *));
+#define SMSGIUCV_DRV_NAME     "SMSGIUCV"
+
+int  smsg_register_callback(const char *,
+                           void (*)(const char *, char *));
+void smsg_unregister_callback(const char *,
+                             void (*)(const char *, char *));
 
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c
new file mode 100644 (file)
index 0000000..91579dc
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Deliver z/VM CP special messages (SMSG) as uevents.
+ *
+ * The driver registers for z/VM CP special messages with the
+ * "APP" prefix. Incoming messages are delivered to user space
+ * as uevents.
+ *
+ * Copyright IBM Corp. 2010
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *
+ */
+#define KMSG_COMPONENT         "smsgiucv_app"
+#define pr_fmt(fmt)            KMSG_COMPONENT ": " fmt
+
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <net/iucv/iucv.h>
+#include "smsgiucv.h"
+
+/* prefix used for SMSG registration */
+#define SMSG_PREFIX            "APP"
+
+/* SMSG related uevent environment variables */
+#define ENV_SENDER_STR         "SMSG_SENDER="
+#define ENV_SENDER_LEN         (strlen(ENV_SENDER_STR) + 8 + 1)
+#define ENV_PREFIX_STR         "SMSG_ID="
+#define ENV_PREFIX_LEN         (strlen(ENV_PREFIX_STR) + \
+                                strlen(SMSG_PREFIX) + 1)
+#define ENV_TEXT_STR           "SMSG_TEXT="
+#define ENV_TEXT_LEN(msg)      (strlen(ENV_TEXT_STR) + strlen((msg)) + 1)
+
+/* z/VM user ID which is permitted to send SMSGs
+ * If the value is undefined or empty (""), special messages are
+ * accepted from any z/VM user ID. */
+static char *sender;
+module_param(sender, charp, 0400);
+MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted");
+
+/* SMSG device representation */
+static struct device *smsg_app_dev;
+
+/* list element for queuing received messages for delivery */
+struct smsg_app_event {
+       struct list_head list;
+       char *buf;
+       char *envp[4];
+};
+
+/* queue for outgoing uevents */
+static LIST_HEAD(smsg_event_queue);
+static DEFINE_SPINLOCK(smsg_event_queue_lock);
+
+static void smsg_app_event_free(struct smsg_app_event *ev)
+{
+       kfree(ev->buf);
+       kfree(ev);
+}
+
+static struct smsg_app_event *smsg_app_event_alloc(const char *from,
+                                                  const char *msg)
+{
+       struct smsg_app_event *ev;
+
+       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev)
+               return NULL;
+
+       ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN +
+                         ENV_TEXT_LEN(msg), GFP_ATOMIC);
+       if (!ev->buf) {
+               kfree(ev);
+               return NULL;
+       }
+
+       /* setting up environment pointers into buf */
+       ev->envp[0] = ev->buf;
+       ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN;
+       ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN;
+       ev->envp[3] = NULL;
+
+       /* setting up environment: sender, prefix name, and message text */
+       snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from);
+       snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX);
+       snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg);
+
+       return ev;
+}
+
+static void smsg_event_work_fn(struct work_struct *work)
+{
+       LIST_HEAD(event_queue);
+       struct smsg_app_event *p, *n;
+       struct device *dev;
+
+       dev = get_device(smsg_app_dev);
+       if (!dev)
+               return;
+
+       spin_lock_bh(&smsg_event_queue_lock);
+       list_splice_init(&smsg_event_queue, &event_queue);
+       spin_unlock_bh(&smsg_event_queue_lock);
+
+       list_for_each_entry_safe(p, n, &event_queue, list) {
+               list_del(&p->list);
+               kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp);
+               smsg_app_event_free(p);
+       }
+
+       put_device(dev);
+}
+static DECLARE_WORK(smsg_event_work, smsg_event_work_fn);
+
+static void smsg_app_callback(const char *from, char *msg)
+{
+       struct smsg_app_event *se;
+
+       /* check if the originating z/VM user ID matches
+        * the configured sender. */
+       if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0)
+               return;
+
+       /* get start of message text (skip prefix and leading blanks) */
+       msg += strlen(SMSG_PREFIX);
+       while (*msg && isspace(*msg))
+               msg++;
+       if (*msg == '\0')
+               return;
+
+       /* allocate event list element and its environment */
+       se = smsg_app_event_alloc(from, msg);
+       if (!se)
+               return;
+
+       /* queue event and schedule work function */
+       spin_lock(&smsg_event_queue_lock);
+       list_add_tail(&se->list, &smsg_event_queue);
+       spin_unlock(&smsg_event_queue_lock);
+
+       schedule_work(&smsg_event_work);
+       return;
+}
+
+static int __init smsgiucv_app_init(void)
+{
+       struct device_driver *smsgiucv_drv;
+       int rc;
+
+       if (!MACHINE_IS_VM)
+               return -ENODEV;
+
+       smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL);
+       if (!smsg_app_dev)
+               return -ENOMEM;
+
+       smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
+       if (!smsgiucv_drv) {
+               kfree(smsg_app_dev);
+               return -ENODEV;
+       }
+
+       rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
+       if (rc) {
+               kfree(smsg_app_dev);
+               goto fail_put_driver;
+       }
+       smsg_app_dev->bus = &iucv_bus;
+       smsg_app_dev->parent = iucv_root;
+       smsg_app_dev->release = (void (*)(struct device *)) kfree;
+       smsg_app_dev->driver = smsgiucv_drv;
+       rc = device_register(smsg_app_dev);
+       if (rc) {
+               put_device(smsg_app_dev);
+               goto fail_put_driver;
+       }
+
+       /* register with the smsgiucv device driver */
+       rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
+       if (rc) {
+               device_unregister(smsg_app_dev);
+               goto fail_put_driver;
+       }
+
+       rc = 0;
+fail_put_driver:
+       put_driver(smsgiucv_drv);
+       return rc;
+}
+module_init(smsgiucv_app_init);
+
+static void __exit smsgiucv_app_exit(void)
+{
+       /* unregister callback */
+       smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback);
+
+       /* cancel pending work and flush any queued event work */
+       cancel_work_sync(&smsg_event_work);
+       smsg_event_work_fn(&smsg_event_work);
+
+       device_unregister(smsg_app_dev);
+}
+module_exit(smsgiucv_app_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents");
+MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
index 71b97ff..6479273 100644 (file)
@@ -319,8 +319,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
        id->input_handler = zfcp_qdio_int_resp;
        id->output_handler = zfcp_qdio_int_req;
        id->int_parm = (unsigned long) qdio;
-       id->flags = QDIO_INBOUND_0COPY_SBALS |
-                   QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
        id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
        id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
 
index 1d7a878..0d9d6f7 100644 (file)
@@ -595,8 +595,6 @@ static int ses_intf_add(struct device *cdev,
                ses_dev->page10_len = len;
                buf = NULL;
        }
-       kfree(hdr_buf);
-
        scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
        if (!scomp)
                goto err_free;
@@ -608,6 +606,8 @@ static int ses_intf_add(struct device *cdev,
                goto err_free;
        }
 
+       kfree(hdr_buf);
+
        edev->scratch = ses_dev;
        for (i = 0; i < components; i++)
                edev->component[i].scratch = scomp + i;
index 0807b26..fef0e3c 100644 (file)
@@ -226,7 +226,7 @@ static struct scsi_host_template sgiwd93_template = {
        .use_clustering         = DISABLE_CLUSTERING,
 };
 
-static int __init sgiwd93_probe(struct platform_device *pdev)
+static int __devinit sgiwd93_probe(struct platform_device *pdev)
 {
        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
        unsigned char *wdregs = pd->wdregs;
index 37b3359..56cf0bb 100644 (file)
@@ -64,7 +64,7 @@ static struct scsi_host_template snirm710_template = {
        .module         = THIS_MODULE,
 };
 
-static int __init snirm710_probe(struct platform_device *dev)
+static int __devinit snirm710_probe(struct platform_device *dev)
 {
        unsigned long base;
        struct NCR_700_Host_Parameters *hostdata;
index 7c4ebe6..c3db16b 100644 (file)
@@ -2407,6 +2407,21 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
                tty_termios_encode_baud_rate(termios, baud, baud);
 }
 
+static void
+serial8250_set_ldisc(struct uart_port *port)
+{
+       int line = port->line;
+
+       if (line >= port->state->port.tty->driver->num)
+               return;
+
+       if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               serial8250_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
 static void
 serial8250_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
@@ -2628,6 +2643,7 @@ static struct uart_ops serial8250_pops = {
        .startup        = serial8250_startup,
        .shutdown       = serial8250_shutdown,
        .set_termios    = serial8250_set_termios,
+       .set_ldisc      = serial8250_set_ldisc,
        .pm             = serial8250_pm,
        .type           = serial8250_type,
        .release_port   = serial8250_release_port,
index 429a8ae..e4b3c2c 100644 (file)
@@ -471,6 +471,20 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
        spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static void pl010_set_ldisc(struct uart_port *port)
+{
+       int line = port->line;
+
+       if (line >= port->state->port.tty->driver->num)
+               return;
+
+       if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               pl010_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
 static const char *pl010_type(struct uart_port *port)
 {
        return port->type == PORT_AMBA ? "AMBA" : NULL;
@@ -531,6 +545,7 @@ static struct uart_ops amba_pl010_pops = {
        .startup        = pl010_startup,
        .shutdown       = pl010_shutdown,
        .set_termios    = pl010_set_termios,
+       .set_ldisc      = pl010_set_ldisc,
        .type           = pl010_type,
        .release_port   = pl010_release_port,
        .request_port   = pl010_request_port,
index cadb6f7..7ebecc9 100644 (file)
@@ -770,13 +770,8 @@ static struct usb_driver oled_driver = {
        .id_table =     id_table,
 };
 
-static ssize_t version_show(struct class *dev, char *buf)
-{
-       return sprintf(buf, ASUS_OLED_UNDERSCORE_NAME " %s\n",
-                      ASUS_OLED_VERSION);
-}
-
-static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
+static CLASS_ATTR_STRING(version, S_IRUGO,
+                       ASUS_OLED_UNDERSCORE_NAME " " ASUS_OLED_VERSION);
 
 static int __init asus_oled_init(void)
 {
@@ -788,7 +783,7 @@ static int __init asus_oled_init(void)
                return PTR_ERR(oled_class);
        }
 
-       retval = class_create_file(oled_class, &class_attr_version);
+       retval = class_create_file(oled_class, &class_attr_version.attr);
        if (retval) {
                err("Error creating class version file");
                goto error;
@@ -810,7 +805,7 @@ error:
 
 static void __exit asus_oled_exit(void)
 {
-       class_remove_file(oled_class, &class_attr_version);
+       class_remove_file(oled_class, &class_attr_version.attr);
        class_destroy(oled_class);
 
        usb_deregister(&oled_driver);
index 8aa1955..1da73ec 100644 (file)
@@ -44,17 +44,6 @@ config UIO_PDRV_GENIRQ
 
          If you don't know what to do here, say N.
 
-config UIO_SMX
-       tristate "SMX cryptengine UIO interface"
-       help
-         Userspace IO interface to the Cryptography engine found on the
-         Nias Digital SMX boards.  These will be available from Q4 2008
-         from http://www.niasdigital.com.  The userspace part of this
-         driver will be released under the GPL at the same time as the
-         hardware and will be able to be downloaded from the same site.
-
-         If you compile this as a module, it will be called uio_smx.
-
 config UIO_AEC
        tristate "AEC video timestamp device"
        depends on PCI
@@ -74,6 +63,7 @@ config UIO_AEC
 
 config UIO_SERCOS3
        tristate "Automata Sercos III PCI card driver"
+       depends on PCI
        help
          Userspace I/O interface for the Sercos III PCI card from
          Automata GmbH. The userspace part of this driver will be
@@ -87,11 +77,21 @@ config UIO_SERCOS3
 config UIO_PCI_GENERIC
        tristate "Generic driver for PCI 2.3 and PCI Express cards"
        depends on PCI
-       default n
        help
          Generic driver that you can bind, dynamically, to any
          PCI 2.3 compliant and PCI Express card. It is useful,
          primarily, for virtualization scenarios.
          If you compile this as a module, it will be called uio_pci_generic.
 
+config UIO_NETX
+       tristate "Hilscher NetX Card driver"
+       depends on PCI
+       help
+         Driver for Hilscher NetX based fieldbus cards (cifX, comX).
+         This driver requires a userspace component that comes with the card
+         or is available from Hilscher (http://www.hilscher.com).
+
+         To compile this driver as a module, choose M here; the module
+         will be called uio_netx.
+
 endif
index 73b2e75..18fd818 100644 (file)
@@ -2,7 +2,7 @@ obj-$(CONFIG_UIO)       += uio.o
 obj-$(CONFIG_UIO_CIF)  += uio_cif.o
 obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
 obj-$(CONFIG_UIO_PDRV_GENIRQ)  += uio_pdrv_genirq.o
-obj-$(CONFIG_UIO_SMX)  += uio_smx.o
 obj-$(CONFIG_UIO_AEC)  += uio_aec.o
 obj-$(CONFIG_UIO_SERCOS3)      += uio_sercos3.o
 obj-$(CONFIG_UIO_PCI_GENERIC)  += uio_pci_generic.o
+obj-$(CONFIG_UIO_NETX) += uio_netx.o
index e941367..4de382a 100644 (file)
@@ -129,7 +129,7 @@ static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr,
        return entry->show(mem, buf);
 }
 
-static struct sysfs_ops map_sysfs_ops = {
+static const struct sysfs_ops map_sysfs_ops = {
        .show = map_type_show,
 };
 
@@ -217,7 +217,7 @@ static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr,
        return entry->show(port, buf);
 }
 
-static struct sysfs_ops portio_sysfs_ops = {
+static const struct sysfs_ops portio_sysfs_ops = {
        .show = portio_type_show,
 };
 
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c
new file mode 100644 (file)
index 0000000..afbf0bd
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX).
+ * See http://www.hilscher.com for details.
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2008 Manuel Traut <manut@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HILSCHER         0x15CF
+#define PCI_DEVICE_ID_HILSCHER_NETX    0x0000
+#define PCI_SUBDEVICE_ID_NXSB_PCA      0x3235
+#define PCI_SUBDEVICE_ID_NXPCA         0x3335
+
+#define DPM_HOST_INT_EN0       0xfff0
+#define DPM_HOST_INT_STAT0     0xffe0
+
+#define DPM_HOST_INT_MASK      0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN 0x80000000
+
+static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
+{
+       void __iomem *int_enable_reg = dev_info->mem[0].internal_addr
+                                       + DPM_HOST_INT_EN0;
+       void __iomem *int_status_reg = dev_info->mem[0].internal_addr
+                                       + DPM_HOST_INT_STAT0;
+
+       /* Is one of our interrupts enabled and active ? */
+       if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+               & DPM_HOST_INT_MASK))
+               return IRQ_NONE;
+
+       /* Disable interrupt */
+       iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN,
+               int_enable_reg);
+       return IRQ_HANDLED;
+}
+
+static int __devinit netx_pci_probe(struct pci_dev *dev,
+                                       const struct pci_device_id *id)
+{
+       struct uio_info *info;
+       int bar;
+
+       info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (pci_enable_device(dev))
+               goto out_free;
+
+       if (pci_request_regions(dev, "netx"))
+               goto out_disable;
+
+       switch (id->device) {
+       case PCI_DEVICE_ID_HILSCHER_NETX:
+               bar = 0;
+               info->name = "netx";
+               break;
+       default:
+               bar = 2;
+               info->name = "netx_plx";
+       }
+
+       /* BAR0 or 2 points to the card's dual port memory */
+       info->mem[0].addr = pci_resource_start(dev, bar);
+       if (!info->mem[0].addr)
+               goto out_release;
+       info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar),
+                                               pci_resource_len(dev, bar));
+
+       if (!info->mem[0].internal_addr)
+                       goto out_release;
+
+       info->mem[0].size = pci_resource_len(dev, bar);
+       info->mem[0].memtype = UIO_MEM_PHYS;
+       info->irq = dev->irq;
+       info->irq_flags = IRQF_SHARED;
+       info->handler = netx_handler;
+       info->version = "0.0.1";
+
+       /* Make sure all interrupts are disabled */
+       iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
+
+       if (uio_register_device(&dev->dev, info))
+               goto out_unmap;
+
+       pci_set_drvdata(dev, info);
+       dev_info(&dev->dev, "Found %s card, registered UIO device.\n",
+                               info->name);
+
+       return 0;
+
+out_unmap:
+       iounmap(info->mem[0].internal_addr);
+out_release:
+       pci_release_regions(dev);
+out_disable:
+       pci_disable_device(dev);
+out_free:
+       kfree(info);
+       return -ENODEV;
+}
+
+static void netx_pci_remove(struct pci_dev *dev)
+{
+       struct uio_info *info = pci_get_drvdata(dev);
+
+       /* Disable all interrupts */
+       iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
+       uio_unregister_device(info);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       iounmap(info->mem[0].internal_addr);
+
+       kfree(info);
+}
+
+static struct pci_device_id netx_pci_ids[] = {
+       {
+               .vendor =       PCI_VENDOR_ID_HILSCHER,
+               .device =       PCI_DEVICE_ID_HILSCHER_NETX,
+               .subvendor =    0,
+               .subdevice =    0,
+       },
+       {
+               .vendor =       PCI_VENDOR_ID_PLX,
+               .device =       PCI_DEVICE_ID_PLX_9030,
+               .subvendor =    PCI_VENDOR_ID_PLX,
+               .subdevice =    PCI_SUBDEVICE_ID_NXSB_PCA,
+       },
+       {
+               .vendor =       PCI_VENDOR_ID_PLX,
+               .device =       PCI_DEVICE_ID_PLX_9030,
+               .subvendor =    PCI_VENDOR_ID_PLX,
+               .subdevice =    PCI_SUBDEVICE_ID_NXPCA,
+       },
+       { 0, }
+};
+
+static struct pci_driver netx_pci_driver = {
+       .name = "netx",
+       .id_table = netx_pci_ids,
+       .probe = netx_pci_probe,
+       .remove = netx_pci_remove,
+};
+
+static int __init netx_init_module(void)
+{
+       return pci_register_driver(&netx_pci_driver);
+}
+
+static void __exit netx_exit_module(void)
+{
+       pci_unregister_driver(&netx_pci_driver);
+}
+
+module_init(netx_init_module);
+module_exit(netx_exit_module);
+
+MODULE_DEVICE_TABLE(pci, netx_pci_ids);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Manuel Traut");
diff --git a/drivers/uio/uio_smx.c b/drivers/uio/uio_smx.c
deleted file mode 100644 (file)
index 44054a6..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * UIO SMX Cryptengine driver.
- *
- * (C) 2008 Nias Digital P/L <bn@niasdigital.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/uio_driver.h>
-#include <linux/io.h>
-
-#define DRV_NAME "smx-ce"
-#define DRV_VERSION "0.03"
-
-#define SMX_CSR  0x00000000
-#define SMX_EnD  0x00000001
-#define SMX_RUN  0x00000002
-#define SMX_DRDY 0x00000004
-#define SMX_ERR  0x00000008
-
-static irqreturn_t smx_handler(int irq, struct uio_info *dev_info)
-{
-       void __iomem *csr = dev_info->mem[0].internal_addr + SMX_CSR;
-
-       u32 status = ioread32(csr);
-
-       if (!(status & SMX_DRDY))
-               return IRQ_NONE;
-
-       /* Disable interrupt */
-       iowrite32(status & ~SMX_DRDY, csr);
-       return IRQ_HANDLED;
-}
-
-static int __devinit smx_ce_probe(struct platform_device *dev)
-{
-
-       int ret = -ENODEV;
-       struct uio_info *info;
-       struct resource *regs;
-
-       info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!regs) {
-               dev_err(&dev->dev, "No memory resource specified\n");
-               goto out_free;
-       }
-
-       info->mem[0].addr = regs->start;
-       if (!info->mem[0].addr) {
-               dev_err(&dev->dev, "Invalid memory resource\n");
-               goto out_free;
-       }
-
-       info->mem[0].size = regs->end - regs->start + 1;
-       info->mem[0].internal_addr = ioremap(regs->start, info->mem[0].size);
-
-       if (!info->mem[0].internal_addr) {
-               dev_err(&dev->dev, "Can't remap memory address range\n");
-               goto out_free;
-       }
-
-       info->mem[0].memtype = UIO_MEM_PHYS;
-
-       info->name = "smx-ce";
-       info->version = "0.03";
-
-       info->irq = platform_get_irq(dev, 0);
-       if (info->irq < 0) {
-               ret = info->irq;
-               dev_err(&dev->dev, "No (or invalid) IRQ resource specified\n");
-               goto out_unmap;
-       }
-
-       info->irq_flags = IRQF_SHARED;
-       info->handler = smx_handler;
-
-       platform_set_drvdata(dev, info);
-
-       ret = uio_register_device(&dev->dev, info);
-
-       if (ret)
-               goto out_unmap;
-
-       return 0;
-
-out_unmap:
-       iounmap(info->mem[0].internal_addr);
-out_free:
-       kfree(info);
-
-       return ret;
-}
-
-static int __devexit smx_ce_remove(struct platform_device *dev)
-{
-       struct uio_info *info = platform_get_drvdata(dev);
-
-       uio_unregister_device(info);
-       platform_set_drvdata(dev, NULL);
-       iounmap(info->mem[0].internal_addr);
-
-       kfree(info);
-
-       return 0;
-}
-
-static struct platform_driver smx_ce_driver = {
-       .probe          = smx_ce_probe,
-       .remove         = __devexit_p(smx_ce_remove),
-       .driver         = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init smx_ce_init_module(void)
-{
-       return platform_driver_register(&smx_ce_driver);
-}
-module_init(smx_ce_init_module);
-
-static void __exit smx_ce_exit_module(void)
-{
-       platform_driver_unregister(&smx_ce_driver);
-}
-module_exit(smx_ce_exit_module);
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR("Ben Nizette <bn@niasdigital.com>");
index a7037bf..f3c2338 100644 (file)
@@ -489,10 +489,10 @@ void usb_driver_release_interface(struct usb_driver *driver,
        if (device_is_registered(dev)) {
                device_release_driver(dev);
        } else {
-               down(&dev->sem);
+               device_lock(dev);
                usb_unbind_interface(dev);
                dev->driver = NULL;
-               up(&dev->sem);
+               device_unlock(dev);
        }
 }
 EXPORT_SYMBOL_GPL(usb_driver_release_interface);
index da77e41..08bd6db 100644 (file)
 unsigned long beacon_timeout_ms = 500;
 
 static
-ssize_t beacon_timeout_ms_show(struct class *class, char *buf)
+ssize_t beacon_timeout_ms_show(struct class *class,
+                               struct class_attribute *attr,
+                               char *buf)
 {
        return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
 }
 
 static
 ssize_t beacon_timeout_ms_store(struct class *class,
+                               struct class_attribute *attr,
                                const char *buf, size_t size)
 {
        unsigned long bt;
index cdd6c8e..5fad4e7 100644 (file)
@@ -62,12 +62,12 @@ int umc_controller_reset(struct umc_dev *umc)
        struct device *parent = umc->dev.parent;
        int ret = 0;
 
-       if(down_trylock(&parent->sem))
+       if (device_trylock(parent))
                return -EAGAIN;
        ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
        if (ret >= 0)
                ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
-       up(&parent->sem);
+       device_unlock(parent);
 
        return ret;
 }
index d5bcfc1..157485c 100644 (file)
@@ -366,12 +366,12 @@ struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
 
 static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
 {
-       down(&uwb_dev->dev.sem);
+       device_lock(&uwb_dev->dev);
 }
 
 static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
 {
-       up(&uwb_dev->dev.sem);
+       device_unlock(&uwb_dev->dev);
 }
 
 #endif /* #ifndef __UWB_INTERNAL_H__ */
index 0370399..6627c94 100644 (file)
@@ -615,8 +615,7 @@ ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-static
-struct sysfs_ops wss_sysfs_ops = {
+static const struct sysfs_ops wss_sysfs_ops = {
        .show   = wlp_wss_attr_show,
        .store  = wlp_wss_attr_store,
 };
index 83d40ed..1c60053 100644 (file)
@@ -1497,7 +1497,6 @@ config FB_VIA
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select FB_SOFT_CURSOR
        select I2C_ALGOBIT
        select I2C
        help
@@ -1948,6 +1947,27 @@ config FB_S3C2410_DEBUG
          Turn on debugging messages. Note that you can set/unset at run time
          through sysfs
 
+config FB_NUC900
+        bool "NUC900 LCD framebuffer support"
+        depends on FB && ARCH_W90X900
+        select FB_CFB_FILLRECT
+        select FB_CFB_COPYAREA
+        select FB_CFB_IMAGEBLIT
+        ---help---
+          Frame buffer driver for the built-in LCD controller in the Nuvoton
+          NUC900 processor
+
+config GPM1040A0_320X240
+        bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
+        depends on FB_NUC900
+
+config FB_NUC900_DEBUG
+        bool "NUC900 lcd debug messages"
+        depends on FB_NUC900
+        help
+          Turn on debugging messages. Note that you can set/unset at run time
+          through sysfs
+
 config FB_SM501
        tristate "Silicon Motion SM501 framebuffer support"
        depends on FB && MFD_SM501
index 4ecb30c..a42ad55 100644 (file)
@@ -129,6 +129,7 @@ obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)         += mb862xx/
 obj-$(CONFIG_FB_MSM)              += msm/
+obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
index 0bcc59e..43d7d50 100644 (file)
@@ -1221,7 +1221,7 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
        printk("acornfb: freed %dK memory\n", mb_freed);
 }
 
-static int __init acornfb_probe(struct platform_device *dev)
+static int __devinit acornfb_probe(struct platform_device *dev)
 {
        unsigned long size;
        u_int h_sync, v_sync;
index c343169..01554d6 100644 (file)
@@ -504,7 +504,7 @@ static struct fb_ops arcfb_ops = {
        .fb_ioctl       = arcfb_ioctl,
 };
 
-static int __init arcfb_probe(struct platform_device *dev)
+static int __devinit arcfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
index 9fe90ce..e70bc22 100644 (file)
@@ -140,7 +140,7 @@ static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dc
 
                /* 3 <= m <= 257 */
                if (m >= 3 && m <= 257) {
-                       unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ?
+                       unsigned new_error = Ftarget * n >= Fref * m ?
                                               ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
                        if (new_error < best_error) {
                                best_n = n;
@@ -152,7 +152,7 @@ static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dc
                else if (m <= 1028) {
                        /* remember there are still only 8-bits of precision in m, so
                         * avoid over-optimistic error calculations */
-                       unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ?
+                       unsigned new_error = Ftarget * n >= Fref * (m & ~3) ?
                                               ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
                        if (new_error < best_error) {
                                best_n = n;
index e49ae5e..814312a 100644 (file)
@@ -82,7 +82,6 @@ struct bfin_bf54xfb_info {
        unsigned char *fb_buffer;       /* RGB Buffer */
 
        dma_addr_t dma_handle;
-       int lq043_mmap;
        int lq043_open_cnt;
        int irq;
        spinlock_t lock;        /* lock */
@@ -316,7 +315,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user)
        spin_lock(&fbi->lock);
 
        fbi->lq043_open_cnt--;
-       fbi->lq043_mmap = 0;
 
        if (fbi->lq043_open_cnt <= 0) {
 
@@ -374,33 +372,6 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
        return 0;
 }
 
-static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
-
-       struct bfin_bf54xfb_info *fbi = info->par;
-
-       if (fbi->lq043_mmap)
-               return -1;
-
-       spin_lock(&fbi->lock);
-       fbi->lq043_mmap = 1;
-       spin_unlock(&fbi->lock);
-
-       vma->vm_start = (unsigned long)(fbi->fb_buffer);
-
-       vma->vm_end = vma->vm_start + info->fix.smem_len;
-       /* For those who don't understand how mmap works, go read
-        *   Documentation/nommu-mmap.txt.
-        * For those that do, you will know that the VM_MAYSHARE flag
-        * must be set in the vma->vm_flags structure on noMMU
-        *   Other flags can be set, and are documented in
-        *   include/linux/mm.h
-        */
-       vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
-
-       return 0;
-}
-
 int bfin_bf54x_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        if (nocursor)
@@ -452,7 +423,6 @@ static struct fb_ops bfin_bf54x_fb_ops = {
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
-       .fb_mmap = bfin_bf54x_fb_mmap,
        .fb_cursor = bfin_bf54x_fb_cursor,
        .fb_setcolreg = bfin_bf54x_fb_setcolreg,
 };
index b690c26..0387236 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
-#include <linux/dma-mapping.h>
 
 #include <asm/blackfin.h>
 #include <asm/irq.h>
index 2549c53..5653d08 100644 (file)
@@ -87,7 +87,6 @@ struct bfin_t350mcqbfb_info {
        struct device *dev;
        unsigned char *fb_buffer;       /* RGB Buffer */
        dma_addr_t dma_handle;
-       int lq043_mmap;
        int lq043_open_cnt;
        int irq;
        spinlock_t lock;        /* lock */
@@ -235,7 +234,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user)
        spin_lock(&fbi->lock);
 
        fbi->lq043_open_cnt--;
-       fbi->lq043_mmap = 0;
 
        if (fbi->lq043_open_cnt <= 0) {
                bfin_t350mcqb_disable_ppi();
@@ -293,32 +291,6 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var,
        return 0;
 }
 
-static int bfin_t350mcqb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
-       struct bfin_t350mcqbfb_info *fbi = info->par;
-
-       if (fbi->lq043_mmap)
-               return -1;
-
-       spin_lock(&fbi->lock);
-       fbi->lq043_mmap = 1;
-       spin_unlock(&fbi->lock);
-
-       vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET);
-
-       vma->vm_end = vma->vm_start + info->fix.smem_len;
-       /* For those who don't understand how mmap works, go read
-        *   Documentation/nommu-mmap.txt.
-        * For those that do, you will know that the VM_MAYSHARE flag
-        * must be set in the vma->vm_flags structure on noMMU
-        *   Other flags can be set, and are documented in
-        *   include/linux/mm.h
-        */
-       vma->vm_flags |= VM_MAYSHARE | VM_SHARED;
-
-       return 0;
-}
-
 int bfin_t350mcqb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        if (nocursor)
@@ -370,7 +342,6 @@ static struct fb_ops bfin_t350mcqb_fb_ops = {
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
-       .fb_mmap = bfin_t350mcqb_fb_mmap,
        .fb_cursor = bfin_t350mcqb_fb_cursor,
        .fb_setcolreg = bfin_t350mcqb_fb_setcolreg,
 };
index df9ccb9..ebda687 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/list.h>
+#include <linux/firmware.h>
 #include <linux/uaccess.h>
 
 #include <video/broadsheetfb.h>
 
-/* Display specific information */
+/* track panel specific parameters */
+struct panel_info {
+       int w;
+       int h;
+       u16 sdcfg;
+       u16 gdcfg;
+       u16 lutfmt;
+       u16 fsynclen;
+       u16 fendfbegin;
+       u16 lsynclen;
+       u16 lendlbegin;
+       u16 pixclk;
+};
+
+/* table of panel specific parameters to be indexed into by the board drivers */
+static struct panel_info panel_table[] = {
+       {       /* standard 6" on TFT backplane */
+               .w = 800,
+               .h = 600,
+               .sdcfg = (100 | (1 << 8) | (1 << 9)),
+               .gdcfg = 2,
+               .lutfmt = (4 | (1 << 7)),
+               .fsynclen = 4,
+               .fendfbegin = (10 << 8) | 4,
+               .lsynclen = 10,
+               .lendlbegin = (100 << 8) | 4,
+               .pixclk = 6,
+       },
+       {       /* custom 3.7" flexible on PET or steel */
+               .w = 320,
+               .h = 240,
+               .sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
+               .gdcfg = 3,
+               .lutfmt = (4 | (1 << 7)),
+               .fsynclen = 0,
+               .fendfbegin = (80 << 8) | 4,
+               .lsynclen = 10,
+               .lendlbegin = (80 << 8) | 20,
+               .pixclk = 14,
+       },
+       {       /* standard 9.7" on TFT backplane */
+               .w = 1200,
+               .h = 825,
+               .sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
+               .gdcfg = 2,
+               .lutfmt = (4 | (1 << 7)),
+               .fsynclen = 0,
+               .fendfbegin = (4 << 8) | 4,
+               .lsynclen = 4,
+               .lendlbegin = (60 << 8) | 10,
+               .pixclk = 3,
+       },
+};
+
 #define DPY_W 800
 #define DPY_H 600
 
@@ -62,30 +116,30 @@ static struct fb_var_screeninfo broadsheetfb_var __devinitdata = {
 };
 
 /* main broadsheetfb functions */
-static void broadsheet_issue_data(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
 {
        par->board->set_ctl(par, BS_WR, 0);
        par->board->set_hdb(par, data);
        par->board->set_ctl(par, BS_WR, 1);
 }
 
-static void broadsheet_issue_cmd(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
 {
        par->board->set_ctl(par, BS_DC, 0);
-       broadsheet_issue_data(par, data);
+       broadsheet_gpio_issue_data(par, data);
 }
 
-static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
 {
        par->board->wait_for_rdy(par);
 
        par->board->set_ctl(par, BS_CS, 0);
-       broadsheet_issue_cmd(par, data);
+       broadsheet_gpio_issue_cmd(par, data);
        par->board->set_ctl(par, BS_DC, 1);
        par->board->set_ctl(par, BS_CS, 1);
 }
 
-static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
                                        int argc, u16 *argv)
 {
        int i;
@@ -93,15 +147,43 @@ static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
        par->board->wait_for_rdy(par);
 
        par->board->set_ctl(par, BS_CS, 0);
-       broadsheet_issue_cmd(par, cmd);
+       broadsheet_gpio_issue_cmd(par, cmd);
        par->board->set_ctl(par, BS_DC, 1);
 
        for (i = 0; i < argc; i++)
-               broadsheet_issue_data(par, argv[i]);
+               broadsheet_gpio_issue_data(par, argv[i]);
        par->board->set_ctl(par, BS_CS, 1);
 }
 
-static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
+static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+                                   int argc, u16 *argv)
+{
+       int i;
+
+       par->board->mmio_write(par, BS_MMIO_CMD, cmd);
+
+       for (i = 0; i < argc; i++)
+               par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
+}
+
+static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
+{
+       if (par->board->mmio_write)
+               par->board->mmio_write(par, BS_MMIO_CMD, data);
+       else
+               broadsheet_gpio_send_command(par, data);
+}
+
+static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+                                   int argc, u16 *argv)
+{
+       if (par->board->mmio_write)
+               broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
+       else
+               broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
+}
+
+static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
                                        u16 *data)
 {
        int i;
@@ -121,7 +203,30 @@ static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
        par->board->set_ctl(par, BS_CS, 1);
 }
 
-static u16 broadsheet_get_data(struct broadsheetfb_par *par)
+static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
+                                  u16 *data)
+{
+       int i;
+       u16 tmp;
+
+       for (i = 0; i < size; i++) {
+               tmp = (data[i] & 0x0F) << 4;
+               tmp |= (data[i] & 0x0F00) << 4;
+               par->board->mmio_write(par, BS_MMIO_DATA, tmp);
+       }
+
+}
+
+static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
+                                  u16 *data)
+{
+       if (par->board->mmio_write)
+               broadsheet_mmio_burst_write(par, size, data);
+       else
+               broadsheet_gpio_burst_write(par, size, data);
+}
+
+static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
 {
        u16 res;
        /* wait for ready to go hi. (lo is busy) */
@@ -141,7 +246,16 @@ static u16 broadsheet_get_data(struct broadsheetfb_par *par)
        return res;
 }
 
-static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
+
+static u16 broadsheet_get_data(struct broadsheetfb_par *par)
+{
+       if (par->board->mmio_read)
+               return par->board->mmio_read(par);
+       else
+               return broadsheet_gpio_get_data(par);
+}
+
+static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
                                        u16 data)
 {
        /* wait for ready to go hi. (lo is busy) */
@@ -150,44 +264,541 @@ static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
        /* cs lo, dc lo for cmd, we lo for each data, db as usual */
        par->board->set_ctl(par, BS_CS, 0);
 
-       broadsheet_issue_cmd(par, BS_CMD_WR_REG);
+       broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
 
        par->board->set_ctl(par, BS_DC, 1);
 
-       broadsheet_issue_data(par, reg);
-       broadsheet_issue_data(par, data);
+       broadsheet_gpio_issue_data(par, reg);
+       broadsheet_gpio_issue_data(par, data);
 
        par->board->set_ctl(par, BS_CS, 1);
 }
 
+static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
+                                u16 data)
+{
+       par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
+       par->board->mmio_write(par, BS_MMIO_DATA, reg);
+       par->board->mmio_write(par, BS_MMIO_DATA, data);
+
+}
+
+static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
+                                       u16 data)
+{
+       if (par->board->mmio_write)
+               broadsheet_mmio_write_reg(par, reg, data);
+       else
+               broadsheet_gpio_write_reg(par, reg, data);
+}
+
+static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
+                                       u32 data)
+{
+       broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
+       broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
+}
+
+
 static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
 {
-       broadsheet_send_command(par, reg);
-       msleep(100);
+       broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);
+       par->board->wait_for_rdy(par);
        return broadsheet_get_data(par);
 }
 
+/* functions for waveform manipulation */
+static int is_broadsheet_pll_locked(struct broadsheetfb_par *par)
+{
+       return broadsheet_read_reg(par, 0x000A) & 0x0001;
+}
+
+static int broadsheet_setup_plls(struct broadsheetfb_par *par)
+{
+       int retry_count = 0;
+       u16 tmp;
+
+       /* disable arral saemipu mode */
+       broadsheet_write_reg(par, 0x0006, 0x0000);
+
+       broadsheet_write_reg(par, 0x0010, 0x0004);
+       broadsheet_write_reg(par, 0x0012, 0x5949);
+       broadsheet_write_reg(par, 0x0014, 0x0040);
+       broadsheet_write_reg(par, 0x0016, 0x0000);
+
+       do {
+               if (retry_count++ > 100)
+                       return -ETIMEDOUT;
+               mdelay(1);
+       } while (!is_broadsheet_pll_locked(par));
+
+       tmp = broadsheet_read_reg(par, 0x0006);
+       tmp &= ~0x1;
+       broadsheet_write_reg(par, 0x0006, tmp);
+
+       return 0;
+}
+
+static int broadsheet_setup_spi(struct broadsheetfb_par *par)
+{
+
+       broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
+       broadsheet_write_reg(par, 0x0208, 0x0001);
+
+       return 0;
+}
+
+static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,
+                                               u16 *orig_sfmcd)
+{
+
+       *orig_sfmcd = broadsheet_read_reg(par, 0x0204);
+       broadsheet_write_reg(par, 0x0208, 0);
+       broadsheet_write_reg(par, 0x0204, 0);
+       broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
+
+       return 0;
+}
+
+static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,
+                                               u16 reg, int bitnum, int val,
+                                               int timeout)
+{
+       u16 tmp;
+
+       do {
+               tmp = broadsheet_read_reg(par, reg);
+               if (((tmp >> bitnum) & 1) == val)
+                       return 0;
+               mdelay(1);
+       } while (timeout--);
+
+       return -ETIMEDOUT;
+}
+
+static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data)
+{
+       broadsheet_write_reg(par, 0x0202, (data | 0x100));
+
+       return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
+}
+
+static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data)
+{
+       int err;
+       u16 tmp;
+
+       broadsheet_write_reg(par, 0x0202, 0);
+
+       err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
+       if (err)
+               return err;
+
+       tmp = broadsheet_read_reg(par, 0x200);
+
+       *data = tmp & 0xFF;
+
+       return 0;
+}
+
+static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,
+                                                               int timeout)
+{
+       u8 tmp;
+       int err;
+
+       do {
+               broadsheet_write_reg(par, 0x0208, 1);
+
+               err = broadsheet_spiflash_write_byte(par, 0x05);
+               if (err)
+                       goto failout;
+
+               err = broadsheet_spiflash_read_byte(par, &tmp);
+               if (err)
+                       goto failout;
+
+               broadsheet_write_reg(par, 0x0208, 0);
+
+               if (!(tmp & 0x1))
+                       return 0;
+
+               mdelay(5);
+       } while (timeout--);
+
+       dev_err(par->info->device, "Timed out waiting for spiflash status\n");
+       return -ETIMEDOUT;
+
+failout:
+       broadsheet_write_reg(par, 0x0208, 0);
+       return err;
+}
+
+static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,
+                                                       u8 op, u32 addr)
+{
+       int i;
+       u8 tmp;
+       int err;
+
+       broadsheet_write_reg(par, 0x0208, 1);
+
+       err = broadsheet_spiflash_write_byte(par, op);
+       if (err)
+               return err;
+
+       for (i = 2; i >= 0; i--) {
+               tmp = ((addr >> (i * 8)) & 0xFF);
+               err = broadsheet_spiflash_write_byte(par, tmp);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,
+                                               int *flash_type)
+{
+       int err = 0;
+       u8 sig;
+
+       err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);
+       if (err)
+               goto failout;
+
+       err = broadsheet_spiflash_read_byte(par, &sig);
+       if (err)
+               goto failout;
+
+       if ((sig != 0x10) && (sig != 0x11)) {
+               dev_err(par->info->device, "Unexpected flash type\n");
+               err = -EINVAL;
+               goto failout;
+       }
+
+       *flash_type = sig;
+
+failout:
+       broadsheet_write_reg(par, 0x0208, 0);
+       return err;
+}
+
+static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,
+                                       u16 *initial_sfmcd, int *flash_type)
+
+{
+       int err;
+
+       err = broadsheet_setup_plls(par);
+       if (err)
+               return err;
+
+       broadsheet_write_reg(par, 0x0106, 0x0203);
+
+       err = broadsheet_setup_spi(par);
+       if (err)
+               return err;
+
+       err = broadsheet_setup_spiflash(par, initial_sfmcd);
+       if (err)
+               return err;
+
+       return broadsheet_verify_spiflash(par, flash_type);
+}
+
+static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par,
+                                               int mode)
+{
+       int err;
+
+       broadsheet_write_reg(par, 0x0208, 1);
+       if (mode)
+               err = broadsheet_spiflash_write_byte(par, 0x06);
+       else
+               err = broadsheet_spiflash_write_byte(par, 0x04);
+
+       broadsheet_write_reg(par, 0x0208, 0);
+       return err;
+}
+
+static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par,
+                                               int addr)
+{
+       int err;
+
+       broadsheet_spiflash_write_control(par, 1);
+
+       err = broadsheet_spiflash_op_on_address(par, 0xD8, addr);
+
+       broadsheet_write_reg(par, 0x0208, 0);
+
+       if (err)
+               return err;
+
+       err = broadsheet_spiflash_wait_for_status(par, 1000);
+
+       return err;
+}
+
+static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par,
+                                               int addr, int size, char *data)
+{
+       int err;
+       int i;
+
+       err = broadsheet_spiflash_op_on_address(par, 0x03, addr);
+       if (err)
+               goto failout;
+
+       for (i = 0; i < size; i++) {
+               err = broadsheet_spiflash_read_byte(par, &data[i]);
+               if (err)
+                       goto failout;
+       }
+
+failout:
+       broadsheet_write_reg(par, 0x0208, 0);
+       return err;
+}
+
+#define BS_SPIFLASH_PAGE_SIZE 256
+static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par,
+                                               int addr, const char *data)
+{
+       int err;
+       int i;
+
+       broadsheet_spiflash_write_control(par, 1);
+
+       err = broadsheet_spiflash_op_on_address(par, 0x02, addr);
+       if (err)
+               goto failout;
+
+       for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) {
+               err = broadsheet_spiflash_write_byte(par, data[i]);
+               if (err)
+                       goto failout;
+       }
+
+       broadsheet_write_reg(par, 0x0208, 0);
+
+       err = broadsheet_spiflash_wait_for_status(par, 100);
+
+failout:
+       return err;
+}
+
+static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par,
+                               int addr, const char *data, int sector_size)
+{
+       int i;
+       int err;
+
+       for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) {
+               err = broadsheet_spiflash_write_page(par, addr + i, &data[i]);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+/*
+ * The caller must guarantee that the data to be rewritten is entirely
+ * contained within this sector. That is, data_start_addr + data_len
+ * must be less than sector_start_addr + sector_size.
+ */
+static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
+                                       int sector_size, int data_start_addr,
+                                       int data_len, const char *data)
+{
+       int err;
+       char *sector_buffer;
+       int tail_start_addr;
+       int start_sector_addr;
+
+       sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL);
+       if (!sector_buffer)
+               return -ENOMEM;
+
+       /* the start address of the sector is the 0th byte of that sector */
+       start_sector_addr = (data_start_addr / sector_size) * sector_size;
+
+       /*
+        * check if there is head data that we need to readback into our sector
+        * buffer first
+        */
+       if (data_start_addr != start_sector_addr) {
+               /*
+                * we need to read every byte up till the start address of our
+                * data and we put it into our sector buffer.
+                */
+               err = broadsheet_spiflash_read_range(par, start_sector_addr,
+                                               data_start_addr, sector_buffer);
+               if (err)
+                       return err;
+       }
+
+       /* now we copy our data into the right place in the sector buffer */
+       memcpy(sector_buffer + data_start_addr, data, data_len);
+
+       /*
+        * now we check if there is a tail section of the sector that we need to
+        * readback.
+        */
+       tail_start_addr = (data_start_addr + data_len) % sector_size;
+
+       if (tail_start_addr) {
+               int tail_len;
+
+               tail_len = sector_size - tail_start_addr;
+
+               /* now we read this tail into our sector buffer */
+               err = broadsheet_spiflash_read_range(par, tail_start_addr,
+                       tail_len, sector_buffer + tail_start_addr);
+               if (err)
+                       return err;
+       }
+
+       /* if we got here we have the full sector that we want to rewrite. */
+
+       /* first erase the sector */
+       err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
+       if (err)
+               return err;
+
+       /* now write it */
+       err = broadsheet_spiflash_write_sector(par, start_sector_addr,
+                                       sector_buffer, sector_size);
+       return err;
+}
+
+static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr,
+                               const u8 *wfm, int bytecount, int flash_type)
+{
+       int sector_size;
+       int err;
+       int cur_addr;
+       int writecount;
+       int maxlen;
+       int offset = 0;
+
+       switch (flash_type) {
+       case 0x10:
+               sector_size = 32*1024;
+               break;
+       case 0x11:
+       default:
+               sector_size = 64*1024;
+               break;
+       }
+
+       while (bytecount) {
+               cur_addr = wfm_addr + offset;
+               maxlen = roundup(cur_addr, sector_size) - cur_addr;
+               writecount = min(bytecount, maxlen);
+
+               err = broadsheet_spiflash_rewrite_sector(par, sector_size,
+                               cur_addr, writecount, wfm + offset);
+               if (err)
+                       return err;
+
+               offset += writecount;
+               bytecount -= writecount;
+       }
+
+       return 0;
+}
+
+static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par,
+                                               const u8 *wfm, size_t wfm_size)
+{
+       int err = 0;
+       u16 initial_sfmcd = 0;
+       int flash_type = 0;
+
+       err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type);
+       if (err)
+               goto failout;
+
+       err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type);
+
+failout:
+       broadsheet_write_reg(par, 0x0204, initial_sfmcd);
+       return err;
+}
+
+static ssize_t broadsheet_loadstore_waveform(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t len)
+{
+       int err;
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct broadsheetfb_par *par = info->par;
+       const struct firmware *fw_entry;
+
+       if (len < 1)
+               return -EINVAL;
+
+       err = request_firmware(&fw_entry, "broadsheet.wbf", dev);
+       if (err < 0) {
+               dev_err(dev, "Failed to get broadsheet waveform\n");
+               goto err_failed;
+       }
+
+       /* try to enforce reasonable min max on waveform */
+       if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) {
+               dev_err(dev, "Invalid waveform\n");
+               err = -EINVAL;
+               goto err_failed;
+       }
+
+       mutex_lock(&(par->io_lock));
+       err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data,
+                                                       fw_entry->size);
+
+       mutex_unlock(&(par->io_lock));
+       if (err < 0) {
+               dev_err(dev, "Failed to store broadsheet waveform\n");
+               goto err_failed;
+       }
+
+       dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size);
+
+       return len;
+
+err_failed:
+       return err;
+}
+static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
+                       broadsheet_loadstore_waveform);
+
+/* upper level functions that manipulate the display and other stuff */
 static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
 {
        u16 args[5];
-
-       args[0] = DPY_W;
-       args[1] = DPY_H;
-       args[2] = (100 | (1 << 8) | (1 << 9)); /* sdcfg */
-       args[3] = 2; /* gdrv cfg */
-       args[4] = (4 | (1 << 7)); /* lut index format */
+       int xres = par->info->var.xres;
+       int yres = par->info->var.yres;
+
+       args[0] = panel_table[par->panel_index].w;
+       args[1] = panel_table[par->panel_index].h;
+       args[2] = panel_table[par->panel_index].sdcfg;
+       args[3] = panel_table[par->panel_index].gdcfg;
+       args[4] = panel_table[par->panel_index].lutfmt;
        broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
 
        /* did the controller really set it? */
        broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
 
-       args[0] = 4; /* fsync len */
-       args[1] = (10 << 8) | 4; /* fend/fbegin len */
-       args[2] = 10; /* line sync len */
-       args[3] = (100 << 8) | 4; /* line end/begin len */
-       args[4] = 6; /* pixel clock cfg */
+       args[0] = panel_table[par->panel_index].fsynclen;
+       args[1] = panel_table[par->panel_index].fendfbegin;
+       args[2] = panel_table[par->panel_index].lsynclen;
+       args[3] = panel_table[par->panel_index].lendlbegin;
+       args[4] = panel_table[par->panel_index].pixclk;
        broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
 
+       broadsheet_write_reg32(par, 0x310, xres*yres*2);
+
        /* setup waveform */
        args[0] = 0x886;
        args[1] = 0;
@@ -207,8 +818,9 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
        args[0] = 0x154;
        broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
 
-       broadsheet_burst_write(par, DPY_W*DPY_H/2,
-                               (u16 *) par->info->screen_base);
+       broadsheet_burst_write(par, (panel_table[par->panel_index].w *
+                                       panel_table[par->panel_index].h)/2,
+                                       (u16 *) par->info->screen_base);
 
        broadsheet_send_command(par, BS_CMD_LD_IMG_END);
 
@@ -222,6 +834,21 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
        par->board->wait_for_rdy(par);
 }
 
+static void __devinit broadsheet_identify(struct broadsheetfb_par *par)
+{
+       u16 rev, prc;
+       struct device *dev = par->info->device;
+
+       rev = broadsheet_read_reg(par, BS_REG_REV);
+       prc = broadsheet_read_reg(par, BS_REG_PRC);
+       dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc);
+
+       if (prc != 0x0047)
+               dev_warn(dev, "Unrecognized Broadsheet Product Code\n");
+       if (rev != 0x0100)
+               dev_warn(dev, "Unrecognized Broadsheet Revision\n");
+}
+
 static void __devinit broadsheet_init(struct broadsheetfb_par *par)
 {
        broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
@@ -236,6 +863,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
        u16 args[5];
        unsigned char *buf = (unsigned char *)par->info->screen_base;
 
+       mutex_lock(&(par->io_lock));
        /* y1 must be a multiple of 4 so drop the lower bits */
        y1 &= 0xFFFC;
        /* y2 must be a multiple of 4 , but - 1 so up the lower bits */
@@ -265,6 +893,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
        broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
 
        par->board->wait_for_rdy(par);
+       mutex_unlock(&(par->io_lock));
 
 }
 
@@ -272,13 +901,15 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
 {
        u16 args[5];
 
+       mutex_lock(&(par->io_lock));
        args[0] = 0x3 << 4;
        broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
 
        args[0] = 0x154;
        broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
-       broadsheet_burst_write(par, DPY_W*DPY_H/2,
-                               (u16 *) par->info->screen_base);
+       broadsheet_burst_write(par, (panel_table[par->panel_index].w *
+                                       panel_table[par->panel_index].h)/2,
+                                       (u16 *) par->info->screen_base);
 
        broadsheet_send_command(par, BS_CMD_LD_IMG_END);
 
@@ -290,7 +921,7 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
        broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
 
        par->board->wait_for_rdy(par);
-
+       mutex_unlock(&(par->io_lock));
 }
 
 /* this is called back from the deferred io workqueue */
@@ -436,6 +1067,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
        unsigned char *videomemory;
        struct broadsheetfb_par *par;
        int i;
+       int dpyw, dpyh;
+       int panel_index;
 
        /* pick up board specific routines */
        board = dev->dev.platform_data;
@@ -450,7 +1083,24 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
        if (!info)
                goto err;
 
-       videomemorysize = (DPY_W*DPY_H);
+       switch (board->get_panel_type()) {
+       case 37:
+               panel_index = 1;
+               break;
+       case 97:
+               panel_index = 2;
+               break;
+       case 6:
+       default:
+               panel_index = 0;
+               break;
+       }
+
+       dpyw = panel_table[panel_index].w;
+       dpyh = panel_table[panel_index].h;
+
+       videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
+
        videomemory = vmalloc(videomemorysize);
        if (!videomemory)
                goto err_fb_rel;
@@ -460,16 +1110,25 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
        info->screen_base = (char *)videomemory;
        info->fbops = &broadsheetfb_ops;
 
+       broadsheetfb_var.xres = dpyw;
+       broadsheetfb_var.yres = dpyh;
+       broadsheetfb_var.xres_virtual = dpyw;
+       broadsheetfb_var.yres_virtual = dpyh;
        info->var = broadsheetfb_var;
+
+       broadsheetfb_fix.line_length = dpyw;
        info->fix = broadsheetfb_fix;
        info->fix.smem_len = videomemorysize;
        par = info->par;
+       par->panel_index = panel_index;
        par->info = info;
        par->board = board;
        par->write_reg = broadsheet_write_reg;
        par->read_reg = broadsheet_read_reg;
        init_waitqueue_head(&par->waitq);
 
+       mutex_init(&par->io_lock);
+
        info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
 
        info->fbdefio = &broadsheetfb_defio;
@@ -496,13 +1155,20 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
        if (retval < 0)
                goto err_free_irq;
 
+       broadsheet_identify(par);
+
        broadsheet_init(par);
 
        retval = register_framebuffer(info);
        if (retval < 0)
                goto err_free_irq;
+
        platform_set_drvdata(dev, info);
 
+       retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform);
+       if (retval < 0)
+               goto err_unreg_fb;
+
        printk(KERN_INFO
               "fb%d: Broadsheet frame buffer, using %dK of video memory\n",
               info->node, videomemorysize >> 10);
@@ -510,6 +1176,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
 
        return 0;
 
+err_unreg_fb:
+       unregister_framebuffer(info);
 err_free_irq:
        board->cleanup(par);
 err_cmap:
@@ -530,6 +1198,8 @@ static int __devexit broadsheetfb_remove(struct platform_device *dev)
 
        if (info) {
                struct broadsheetfb_par *par = info->par;
+
+               device_remove_file(info->dev, &dev_attr_loadstore_waveform);
                unregister_framebuffer(info);
                fb_deferred_io_cleanup(info);
                par->board->cleanup(par);
index 108b89e..5eb61b5 100644 (file)
@@ -287,7 +287,7 @@ static struct fb_ops cobalt_lcd_fbops = {
        .fb_cursor      = cobalt_lcdfb_cursor,
 };
 
-static int __init cobalt_lcdfb_probe(struct platform_device *dev)
+static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct resource *res;
index d25df51..581d2db 100644 (file)
@@ -210,7 +210,7 @@ static int __init efifb_setup(char *options)
        return 0;
 }
 
-static int __init efifb_probe(struct platform_device *dev)
+static int __devinit efifb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int err;
index 2735b79..6d755bb 100644 (file)
@@ -602,7 +602,7 @@ static int epson1355fb_remove(struct platform_device *dev)
        return 0;
 }
 
-int __init epson1355fb_probe(struct platform_device *dev)
+int __devinit epson1355fb_probe(struct platform_device *dev)
 {
        struct epson1355_par *default_par;
        struct fb_info *info;
index 695fa01..5643a35 100644 (file)
@@ -1128,7 +1128,7 @@ static int __init gbefb_setup(char *options)
        return 0;
 }
 
-static int __init gbefb_probe(struct platform_device *p_dev)
+static int __devinit gbefb_probe(struct platform_device *p_dev)
 {
        int i, ret = 0;
        struct fb_info *info;
index 0129c04..db9b785 100644 (file)
@@ -551,7 +551,7 @@ static struct fb_ops hgafb_ops = {
         *  Initialization
         */
 
-static int __init hgafb_probe(struct platform_device *pdev)
+static int __devinit hgafb_probe(struct platform_device *pdev)
 {
        struct fb_info *info;
 
index 73c83a8..bf78779 100644 (file)
@@ -325,7 +325,7 @@ static struct fb_ops hitfb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __init hitfb_probe(struct platform_device *dev)
+static int __devinit hitfb_probe(struct platform_device *dev)
 {
        unsigned short lcdclor, ldr3, ldvndr;
        struct fb_info *info;
index fabb0c5..8280a58 100644 (file)
 #define CARMINE_MEM_SIZE       0x8000000
 #define DRV_NAME               "mb862xxfb"
 
-#if defined(CONFIG_LWMON5)
-static struct mb862xx_gc_mode lwmon5_gc_mode = {
-       /* Mode for Sharp LQ104V1DG61 TFT LCD Panel */
-       { "640x480", 60, 640, 480, 40000, 48, 16, 32, 11, 96, 2, 0, 0, 0 },
-       /* 16 bits/pixel, 32MB, 100MHz, SDRAM memory mode value */
-       16, 0x2000000, GC_CCF_COT_100, 0x414fb7f2
-};
-#endif
-
 #if defined(CONFIG_SOCRATES)
 static struct mb862xx_gc_mode socrates_gc_mode = {
        /* Mode for Prime View PM070WL4 TFT LCD Panel */
@@ -600,10 +591,6 @@ static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
                goto irqdisp;
        }
 
-#if defined(CONFIG_LWMON5)
-       par->gc_mode = &lwmon5_gc_mode;
-#endif
-
 #if defined(CONFIG_SOCRATES)
        par->gc_mode = &socrates_gc_mode;
 #endif
index 0129f1b..b895aae 100644 (file)
@@ -893,7 +893,7 @@ const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
 }
 
 /**
- * fb_add_videomode: adds videomode entry to modelist
+ * fb_add_videomode - adds videomode entry to modelist
  * @mode: videomode to add
  * @head: struct list_head of modelist
  *
@@ -928,7 +928,7 @@ int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
 }
 
 /**
- * fb_delete_videomode: removed videomode entry from modelist
+ * fb_delete_videomode - removed videomode entry from modelist
  * @mode: videomode to remove
  * @head: struct list_head of modelist
  *
@@ -953,7 +953,7 @@ void fb_delete_videomode(const struct fb_videomode *mode,
 }
 
 /**
- * fb_destroy_modelist: destroy modelist
+ * fb_destroy_modelist - destroy modelist
  * @head: struct list_head of modelist
  */
 void fb_destroy_modelist(struct list_head *head)
@@ -968,7 +968,7 @@ void fb_destroy_modelist(struct list_head *head)
 EXPORT_SYMBOL_GPL(fb_destroy_modelist);
 
 /**
- * fb_videomode_to_modelist: convert mode array to mode list
+ * fb_videomode_to_modelist - convert mode array to mode list
  * @modedb: array of struct fb_videomode
  * @num: number of entries in array
  * @head: struct list_head of modelist
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
new file mode 100644 (file)
index 0000000..6bf0d46
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  Description:
+ *    Nuvoton LCD Controller Driver
+ *  Author:
+ *    Wang Qiang (rurality.linux@gmail.com) 2009/12/11
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-ldm.h>
+#include <mach/fb.h>
+#include <mach/clkdev.h>
+
+#include "nuc900fb.h"
+
+
+/*
+ *  Initialize the nuc900 video (dual) buffer address
+ */
+static void nuc900fb_set_lcdaddr(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       void __iomem *regs = fbi->io;
+       unsigned long vbaddr1, vbaddr2;
+
+       vbaddr1  = info->fix.smem_start;
+       vbaddr2  = info->fix.smem_start;
+       vbaddr2 += info->fix.line_length * info->var.yres;
+
+       /* set frambuffer start phy addr*/
+       writel(vbaddr1, regs + REG_LCM_VA_BADDR0);
+       writel(vbaddr2, regs + REG_LCM_VA_BADDR1);
+
+       writel(fbi->regs.lcd_va_fbctrl, regs + REG_LCM_VA_FBCTRL);
+       writel(fbi->regs.lcd_va_scale, regs + REG_LCM_VA_SCALE);
+}
+
+/*
+ *     calculate divider for lcd div
+ */
+static unsigned int nuc900fb_calc_pixclk(struct nuc900fb_info *fbi,
+                                        unsigned long pixclk)
+{
+       unsigned long clk = fbi->clk_rate;
+       unsigned long long div;
+
+       /* pixclk is in picseconds. our clock is in Hz*/
+       /* div = (clk * pixclk)/10^12 */
+       div = (unsigned long long)clk * pixclk;
+       div >>= 12;
+       do_div(div, 625 * 625UL * 625);
+
+       dev_dbg(fbi->dev, "pixclk %ld, divisor is %lld\n", pixclk, div);
+
+       return div;
+}
+
+/*
+ *     Check the video params of 'var'.
+ */
+static int nuc900fb_check_var(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       struct nuc900fb_mach_info *mach_info = fbi->dev->platform_data;
+       struct nuc900fb_display *display = NULL;
+       struct nuc900fb_display *default_display = mach_info->displays +
+                                                  mach_info->default_display;
+       int i;
+
+       dev_dbg(fbi->dev, "check_var(var=%p, info=%p)\n", var, info);
+
+       /* validate x/y resolution */
+       /* choose default mode if possible */
+       if (var->xres == default_display->xres &&
+           var->yres == default_display->yres &&
+           var->bits_per_pixel == default_display->bpp)
+               display = default_display;
+       else
+               for (i = 0; i < mach_info->num_displays; i++)
+                       if (var->xres == mach_info->displays[i].xres &&
+                           var->yres == mach_info->displays[i].yres &&
+                           var->bits_per_pixel == mach_info->displays[i].bpp) {
+                               display = mach_info->displays + i;
+                               break;
+                       }
+
+       if (display == NULL) {
+               printk(KERN_ERR "wrong resolution or depth %dx%d at %d bit per pixel\n",
+                       var->xres, var->yres, var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       /* it should be the same size as the display */
+       var->xres_virtual       = display->xres;
+       var->yres_virtual       = display->yres;
+       var->height             = display->height;
+       var->width              = display->width;
+
+       /* copy lcd settings */
+       var->pixclock           = display->pixclock;
+       var->left_margin        = display->left_margin;
+       var->right_margin       = display->right_margin;
+       var->upper_margin       = display->upper_margin;
+       var->lower_margin       = display->lower_margin;
+       var->vsync_len          = display->vsync_len;
+       var->hsync_len          = display->hsync_len;
+
+       var->transp.offset      = 0;
+       var->transp.length      = 0;
+
+       fbi->regs.lcd_dccs = display->dccs;
+       fbi->regs.lcd_device_ctrl = display->devctl;
+       fbi->regs.lcd_va_fbctrl = display->fbctrl;
+       fbi->regs.lcd_va_scale = display->scale;
+
+       /* set R/G/B possions */
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+       default:
+               var->red.offset         = 0;
+               var->red.length         = var->bits_per_pixel;
+               var->green              = var->red;
+               var->blue               = var->red;
+               break;
+       case 12:
+               var->red.length         = 4;
+               var->green.length       = 4;
+               var->blue.length        = 4;
+               var->red.offset         = 8;
+               var->green.offset       = 4;
+               var->blue.offset        = 0;
+               break;
+       case 16:
+               var->red.length         = 5;
+               var->green.length       = 6;
+               var->blue.length        = 5;
+               var->red.offset         = 11;
+               var->green.offset       = 5;
+               var->blue.offset        = 0;
+               break;
+       case 18:
+               var->red.length         = 6;
+               var->green.length       = 6;
+               var->blue.length        = 6;
+               var->red.offset         = 12;
+               var->green.offset       = 6;
+               var->blue.offset        = 0;
+               break;
+       case 32:
+               var->red.length         = 8;
+               var->green.length       = 8;
+               var->blue.length        = 8;
+               var->red.offset         = 16;
+               var->green.offset       = 8;
+               var->blue.offset        = 0;
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ *     Calculate lcd register values from var setting & save into hw
+ */
+static void nuc900fb_calculate_lcd_regs(const struct fb_info *info,
+                                       struct nuc900fb_hw *regs)
+{
+       const struct fb_var_screeninfo *var = &info->var;
+       int vtt = var->height + var->upper_margin + var->lower_margin;
+       int htt = var->width + var->left_margin + var->right_margin;
+       int hsync = var->width + var->right_margin;
+       int vsync = var->height + var->lower_margin;
+
+       regs->lcd_crtc_size = LCM_CRTC_SIZE_VTTVAL(vtt) |
+                             LCM_CRTC_SIZE_HTTVAL(htt);
+       regs->lcd_crtc_dend = LCM_CRTC_DEND_VDENDVAL(var->height) |
+                             LCM_CRTC_DEND_HDENDVAL(var->width);
+       regs->lcd_crtc_hr = LCM_CRTC_HR_EVAL(var->width + 5) |
+                           LCM_CRTC_HR_SVAL(var->width + 1);
+       regs->lcd_crtc_hsync = LCM_CRTC_HSYNC_EVAL(hsync + var->hsync_len) |
+                              LCM_CRTC_HSYNC_SVAL(hsync);
+       regs->lcd_crtc_vr = LCM_CRTC_VR_EVAL(vsync + var->vsync_len) |
+                           LCM_CRTC_VR_SVAL(vsync);
+
+}
+
+/*
+ *     Activate (set) the controller from the given framebuffer
+ *     information
+ */
+static void nuc900fb_activate_var(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       void __iomem *regs = fbi->io;
+       struct fb_var_screeninfo *var = &info->var;
+       int clkdiv;
+
+       clkdiv = nuc900fb_calc_pixclk(fbi, var->pixclock) - 1;
+       if (clkdiv < 0)
+               clkdiv = 0;
+
+       nuc900fb_calculate_lcd_regs(info, &fbi->regs);
+
+       /* set the new lcd registers*/
+
+       dev_dbg(fbi->dev, "new lcd register set:\n");
+       dev_dbg(fbi->dev, "dccs       = 0x%08x\n", fbi->regs.lcd_dccs);
+       dev_dbg(fbi->dev, "dev_ctl    = 0x%08x\n", fbi->regs.lcd_device_ctrl);
+       dev_dbg(fbi->dev, "crtc_size  = 0x%08x\n", fbi->regs.lcd_crtc_size);
+       dev_dbg(fbi->dev, "crtc_dend  = 0x%08x\n", fbi->regs.lcd_crtc_dend);
+       dev_dbg(fbi->dev, "crtc_hr    = 0x%08x\n", fbi->regs.lcd_crtc_hr);
+       dev_dbg(fbi->dev, "crtc_hsync = 0x%08x\n", fbi->regs.lcd_crtc_hsync);
+       dev_dbg(fbi->dev, "crtc_vr    = 0x%08x\n", fbi->regs.lcd_crtc_vr);
+
+       writel(fbi->regs.lcd_device_ctrl, regs + REG_LCM_DEV_CTRL);
+       writel(fbi->regs.lcd_crtc_size, regs + REG_LCM_CRTC_SIZE);
+       writel(fbi->regs.lcd_crtc_dend, regs + REG_LCM_CRTC_DEND);
+       writel(fbi->regs.lcd_crtc_hr, regs + REG_LCM_CRTC_HR);
+       writel(fbi->regs.lcd_crtc_hsync, regs + REG_LCM_CRTC_HSYNC);
+       writel(fbi->regs.lcd_crtc_vr, regs + REG_LCM_CRTC_VR);
+
+       /* set lcd address pointers */
+       nuc900fb_set_lcdaddr(info);
+
+       writel(fbi->regs.lcd_dccs, regs + REG_LCM_DCCS);
+}
+
+/*
+ *      Alters the hardware state.
+ *
+ */
+static int nuc900fb_set_par(struct fb_info *info)
+{
+       struct fb_var_screeninfo *var = &info->var;
+
+       switch (var->bits_per_pixel) {
+       case 32:
+       case 24:
+       case 18:
+       case 16:
+       case 12:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       case 1:
+               info->fix.visual = FB_VISUAL_MONO01;
+               break;
+       default:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+       }
+
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
+
+       /* activate this new configuration */
+       nuc900fb_activate_var(info);
+       return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+static int nuc900fb_setcolreg(unsigned regno,
+                              unsigned red, unsigned green, unsigned blue,
+                              unsigned transp, struct fb_info *info)
+{
+       unsigned int val;
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseuo-palette */
+               if (regno < 16) {
+                       u32 *pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red, &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue, &info->var.blue);
+                       pal[regno] = val;
+               }
+               break;
+
+       default:
+               return 1;   /* unknown type */
+       }
+       return 0;
+}
+
+/**
+ *      nuc900fb_blank
+ *
+ */
+static int nuc900fb_blank(int blank_mode, struct fb_info *info)
+{
+
+       return 0;
+}
+
+static struct fb_ops nuc900fb_ops = {
+       .owner                  = THIS_MODULE,
+       .fb_check_var           = nuc900fb_check_var,
+       .fb_set_par             = nuc900fb_set_par,
+       .fb_blank               = nuc900fb_blank,
+       .fb_setcolreg           = nuc900fb_setcolreg,
+       .fb_fillrect            = cfb_fillrect,
+       .fb_copyarea            = cfb_copyarea,
+       .fb_imageblit           = cfb_imageblit,
+};
+
+
+static inline void modify_gpio(void __iomem *reg,
+                              unsigned long set, unsigned long mask)
+{
+       unsigned long tmp;
+       tmp = readl(reg) & ~mask;
+       writel(tmp | set, reg);
+}
+
+/*
+ * Initialise LCD-related registers
+ */
+static int nuc900fb_init_registers(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       struct nuc900fb_mach_info *mach_info = fbi->dev->platform_data;
+       void __iomem *regs = fbi->io;
+
+       /*reset the display engine*/
+       writel(0, regs + REG_LCM_DCCS);
+       writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_ENG_RST,
+              regs + REG_LCM_DCCS);
+       ndelay(100);
+       writel(readl(regs + REG_LCM_DCCS) & (~LCM_DCCS_ENG_RST),
+              regs + REG_LCM_DCCS);
+       ndelay(100);
+
+       writel(0, regs + REG_LCM_DEV_CTRL);
+
+       /* config gpio output */
+       modify_gpio(W90X900_VA_GPIO + 0x54, mach_info->gpio_dir,
+                   mach_info->gpio_dir_mask);
+       modify_gpio(W90X900_VA_GPIO + 0x58, mach_info->gpio_data,
+                   mach_info->gpio_data_mask);
+
+       return 0;
+}
+
+
+/*
+ *    Alloc the SDRAM region of NUC900 for the frame buffer.
+ *    The buffer should be a non-cached, non-buffered, memory region
+ *    to allow palette and pixel writes without flushing the cache.
+ */
+static int __init nuc900fb_map_video_memory(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       dma_addr_t map_dma;
+       unsigned long map_size = PAGE_ALIGN(info->fix.smem_len);
+
+       dev_dbg(fbi->dev, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n",
+               fbi, map_size);
+
+       info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
+                                                       &map_dma, GFP_KERNEL);
+
+       if (!info->screen_base)
+               return -ENOMEM;
+
+       memset(info->screen_base, 0x00, map_size);
+       info->fix.smem_start = map_dma;
+
+       return 0;
+}
+
+static inline void nuc900fb_unmap_video_memory(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+                             info->screen_base, info->fix.smem_start);
+}
+
+static irqreturn_t nuc900fb_irqhandler(int irq, void *dev_id)
+{
+       struct nuc900fb_info *fbi = dev_id;
+       void __iomem *regs = fbi->io;
+       void __iomem *irq_base = fbi->irq_base;
+       unsigned long lcdirq = readl(regs + REG_LCM_INT_CS);
+
+       if (lcdirq & LCM_INT_CS_DISP_F_STATUS) {
+               writel(readl(irq_base) | 1<<30, irq_base);
+
+               /* wait VA_EN low */
+               if ((readl(regs + REG_LCM_DCCS) &
+                   LCM_DCCS_SINGLE) == LCM_DCCS_SINGLE)
+                       while ((readl(regs + REG_LCM_DCCS) &
+                              LCM_DCCS_VA_EN) == LCM_DCCS_VA_EN)
+                               ;
+               /* display_out-enable */
+               writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_DISP_OUT_EN,
+                       regs + REG_LCM_DCCS);
+               /* va-enable*/
+               writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_VA_EN,
+                       regs + REG_LCM_DCCS);
+       } else if (lcdirq & LCM_INT_CS_UNDERRUN_INT) {
+               writel(readl(irq_base) | LCM_INT_CS_UNDERRUN_INT, irq_base);
+       } else if (lcdirq & LCM_INT_CS_BUS_ERROR_INT) {
+               writel(readl(irq_base) | LCM_INT_CS_BUS_ERROR_INT, irq_base);
+       }
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+static int nuc900fb_cpufreq_transition(struct notifier_block *nb,
+                                      unsigned long val, void *data)
+{
+       struct nuc900fb_info *info;
+       struct fb_info *fbinfo;
+       long delta_f;
+       info = container_of(nb, struct nuc900fb_info, freq_transition);
+       fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+
+       delta_f = info->clk_rate - clk_get_rate(info->clk);
+
+       if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
+          (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
+               info->clk_rate = clk_get_rate(info->clk);
+               nuc900fb_activate_var(fbinfo);
+       }
+
+       return 0;
+}
+
+static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
+{
+       fbi->freq_transition.notifier_call = nuc900fb_cpufreq_transition;
+       return cpufreq_register_notifier(&fbi->freq_transition,
+                                 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *fbi)
+{
+       cpufreq_unregister_notifier(&fbi->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int nuc900fb_cpufreq_transition(struct notifier_block *nb,
+                                      unsigned long val, void *data)
+{
+       return 0;
+}
+
+static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
+{
+       return 0;
+}
+
+static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *info)
+{
+}
+#endif
+
+static char driver_name[] = "nuc900fb";
+
+static int __devinit nuc900fb_probe(struct platform_device *pdev)
+{
+       struct nuc900fb_info *fbi;
+       struct nuc900fb_display *display;
+       struct fb_info     *fbinfo;
+       struct nuc900fb_mach_info *mach_info;
+       struct resource *res;
+       int ret;
+       int irq;
+       int i;
+       int size;
+
+       dev_dbg(&pdev->dev, "devinit\n");
+       mach_info = pdev->dev.platform_data;
+       if (mach_info == NULL) {
+               dev_err(&pdev->dev,
+                       "no platform data for lcd, cannot attach\n");
+               return -EINVAL;
+       }
+
+       if (mach_info->default_display > mach_info->num_displays) {
+               dev_err(&pdev->dev,
+                       "default display No. is %d but only %d displays \n",
+                       mach_info->default_display, mach_info->num_displays);
+               return -EINVAL;
+       }
+
+
+       display = mach_info->displays + mach_info->default_display;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for device\n");
+               return -ENOENT;
+       }
+
+       fbinfo = framebuffer_alloc(sizeof(struct nuc900fb_info), &pdev->dev);
+       if (!fbinfo)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, fbinfo);
+
+       fbi = fbinfo->par;
+       fbi->dev = &pdev->dev;
+
+#ifdef CONFIG_CPU_NUC950
+       fbi->drv_type = LCDDRV_NUC950;
+#endif
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       size = (res->end - res->start) + 1;
+       fbi->mem = request_mem_region(res->start, size, pdev->name);
+       if (fbi->mem == NULL) {
+               dev_err(&pdev->dev, "failed to alloc memory region\n");
+               ret = -ENOENT;
+               goto free_fb;
+       }
+
+       fbi->io = ioremap(res->start, size);
+       if (fbi->io == NULL) {
+               dev_err(&pdev->dev, "ioremap() of lcd registers failed\n");
+               ret = -ENXIO;
+               goto release_mem_region;
+       }
+
+       fbi->irq_base = fbi->io + REG_LCM_INT_CS;
+
+
+       /* Stop the LCD */
+       writel(0, fbi->io + REG_LCM_DCCS);
+
+       /* fill the fbinfo*/
+       strcpy(fbinfo->fix.id, driver_name);
+       fbinfo->fix.type                = FB_TYPE_PACKED_PIXELS;
+       fbinfo->fix.type_aux            = 0;
+       fbinfo->fix.xpanstep            = 0;
+       fbinfo->fix.ypanstep            = 0;
+       fbinfo->fix.ywrapstep           = 0;
+       fbinfo->fix.accel               = FB_ACCEL_NONE;
+       fbinfo->var.nonstd              = 0;
+       fbinfo->var.activate            = FB_ACTIVATE_NOW;
+       fbinfo->var.accel_flags         = 0;
+       fbinfo->var.vmode               = FB_VMODE_NONINTERLACED;
+       fbinfo->fbops                   = &nuc900fb_ops;
+       fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
+       fbinfo->pseudo_palette          = &fbi->pseudo_pal;
+
+       ret = request_irq(irq, nuc900fb_irqhandler, IRQF_DISABLED,
+                         pdev->name, fbinfo);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
+                       irq, ret);
+               ret = -EBUSY;
+               goto release_regs;
+       }
+
+       nuc900_driver_clksrc_div(&pdev->dev, "ext", 0x2);
+
+       fbi->clk = clk_get(&pdev->dev, NULL);
+       if (!fbi->clk || IS_ERR(fbi->clk)) {
+               printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n");
+               ret = -ENOENT;
+               goto release_irq;
+       }
+
+       clk_enable(fbi->clk);
+       dev_dbg(&pdev->dev, "got and enabled clock\n");
+
+       fbi->clk_rate = clk_get_rate(fbi->clk);
+
+       /* calutate the video buffer size */
+       for (i = 0; i < mach_info->num_displays; i++) {
+               unsigned long smem_len = mach_info->displays[i].xres;
+               smem_len *= mach_info->displays[i].yres;
+               smem_len *= mach_info->displays[i].bpp;
+               smem_len >>= 3;
+               if (fbinfo->fix.smem_len < smem_len)
+                       fbinfo->fix.smem_len = smem_len;
+       }
+
+       /* Initialize Video Memory */
+       ret = nuc900fb_map_video_memory(fbinfo);
+       if (ret) {
+               printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret);
+               goto release_clock;
+       }
+
+       dev_dbg(&pdev->dev, "got video memory\n");
+
+       fbinfo->var.xres = display->xres;
+       fbinfo->var.yres = display->yres;
+       fbinfo->var.bits_per_pixel = display->bpp;
+
+       nuc900fb_init_registers(fbinfo);
+
+       nuc900fb_check_var(&fbinfo->var, fbinfo);
+
+       ret = nuc900fb_cpufreq_register(fbi);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register cpufreq\n");
+               goto free_video_memory;
+       }
+
+       ret = register_framebuffer(fbinfo);
+       if (ret) {
+               printk(KERN_ERR "failed to register framebuffer device: %d\n",
+                       ret);
+               goto free_cpufreq;
+       }
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+               fbinfo->node, fbinfo->fix.id);
+
+       return 0;
+
+free_cpufreq:
+       nuc900fb_cpufreq_deregister(fbi);
+free_video_memory:
+       nuc900fb_unmap_video_memory(fbinfo);
+release_clock:
+       clk_disable(fbi->clk);
+       clk_put(fbi->clk);
+release_irq:
+       free_irq(irq, fbi);
+release_regs:
+       iounmap(fbi->io);
+release_mem_region:
+       release_mem_region((unsigned long)fbi->mem, size);
+free_fb:
+       framebuffer_release(fbinfo);
+       return ret;
+}
+
+/*
+ * shutdown the lcd controller
+ */
+static void nuc900fb_stop_lcd(struct fb_info *info)
+{
+       struct nuc900fb_info *fbi = info->par;
+       void __iomem *regs = fbi->io;
+
+       writel((~LCM_DCCS_DISP_INT_EN) | (~LCM_DCCS_VA_EN) | (~LCM_DCCS_OSD_EN),
+               regs + REG_LCM_DCCS);
+}
+
+/*
+ *  Cleanup
+ */
+static int nuc900fb_remove(struct platform_device *pdev)
+{
+       struct fb_info *fbinfo = platform_get_drvdata(pdev);
+       struct nuc900fb_info *fbi = fbinfo->par;
+       int irq;
+
+       nuc900fb_stop_lcd(fbinfo);
+       msleep(1);
+
+       nuc900fb_unmap_video_memory(fbinfo);
+
+       iounmap(fbi->io);
+
+       irq = platform_get_irq(pdev, 0);
+       free_irq(irq, fbi);
+
+       release_resource(fbi->mem);
+       kfree(fbi->mem);
+
+       platform_set_drvdata(pdev, NULL);
+       framebuffer_release(fbinfo);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ *     suspend and resume support for the lcd controller
+ */
+
+static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct fb_info     *fbinfo = platform_get_drvdata(dev);
+       struct nuc900fb_info *info = fbinfo->par;
+
+       nuc900fb_stop_lcd();
+       msleep(1);
+       clk_disable(info->clk);
+       return 0;
+}
+
+static int nuc900fb_resume(struct platform_device *dev)
+{
+       struct fb_info     *fbinfo = platform_get_drvdata(dev);
+       struct nuc900fb_info *fbi = fbinfo->par;
+
+       printk(KERN_INFO "nuc900fb resume\n");
+
+       clk_enable(fbi->clk);
+       msleep(1);
+
+       nuc900fb_init_registers(fbinfo);
+       nuc900fb_activate_var(bfinfo);
+
+       return 0;
+}
+
+#else
+#define nuc900fb_suspend NULL
+#define nuc900fb_resume  NULL
+#endif
+
+static struct platform_driver nuc900fb_driver = {
+       .probe          = nuc900fb_probe,
+       .remove         = nuc900fb_remove,
+       .suspend        = nuc900fb_suspend,
+       .resume         = nuc900fb_resume,
+       .driver         = {
+               .name   = "nuc900-lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int __devinit nuc900fb_init(void)
+{
+       return platform_driver_register(&nuc900fb_driver);
+}
+
+static void __exit nuc900fb_cleanup(void)
+{
+       platform_driver_unregister(&nuc900fb_driver);
+}
+
+module_init(nuc900fb_init);
+module_exit(nuc900fb_cleanup);
+
+MODULE_DESCRIPTION("Framebuffer driver for the NUC900");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/nuc900fb.h b/drivers/video/nuc900fb.h
new file mode 100644 (file)
index 0000000..6c23aa3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *   Auther:
+ *        Wang Qiang(rurality.linux@gmail.com)  2009/12/16
+ */
+
+#ifndef __NUC900FB_H
+#define __NUC900FB_H
+
+#include <mach/map.h>
+#include <mach/fb.h>
+
+enum nuc900_lcddrv_type {
+       LCDDRV_NUC910,
+       LCDDRV_NUC930,
+       LCDDRV_NUC932,
+       LCDDRV_NUC950,
+       LCDDRV_NUC960,
+};
+
+
+#define PALETTE_BUFFER_SIZE    256
+#define PALETTE_BUFF_CLEAR     (0x80000000) /* entry is clear/invalid */
+
+struct nuc900fb_info {
+       struct device           *dev;
+       struct clk              *clk;
+
+       struct resource         *mem;
+       void __iomem            *io;
+       void __iomem            *irq_base;
+       int                     drv_type;
+       struct nuc900fb_hw      regs;
+       unsigned long           clk_rate;
+
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block   freq_transition;
+#endif
+
+       /* keep these registers in case we need to re-write palette */
+       u32                     palette_buffer[PALETTE_BUFFER_SIZE];
+       u32                     pseudo_pal[16];
+};
+
+int nuc900fb_init(void);
+
+#endif /* __NUC900FB_H */
index 913142d..9acef00 100644 (file)
@@ -341,7 +341,7 @@ static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
        return manager_attr->store(manager, buf, size);
 }
 
-static struct sysfs_ops manager_sysfs_ops = {
+static const struct sysfs_ops manager_sysfs_ops = {
        .show = manager_attr_show,
        .store = manager_attr_store,
 };
index 0c5bea2..aed3f31 100644 (file)
@@ -320,7 +320,7 @@ static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
        return overlay_attr->store(overlay, buf, size);
 }
 
-static struct sysfs_ops overlay_sysfs_ops = {
+static const struct sysfs_ops overlay_sysfs_ops = {
        .show = overlay_attr_show,
        .store = overlay_attr_store,
 };
index 4beac1d..de40a62 100644 (file)
@@ -85,7 +85,7 @@ static struct fb_ops q40fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __init q40fb_probe(struct platform_device *dev)
+static int __devinit q40fb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
 
index aac6612..2b094de 100644 (file)
@@ -1004,12 +1004,12 @@ dealloc_fb:
        return ret;
 }
 
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __devinit s3c2410fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2410);
 }
 
-static int __init s3c2412fb_probe(struct platform_device *pdev)
+static int __devinit s3c2412fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2412);
 }
index cdaa873..e8b76d6 100644 (file)
@@ -1435,7 +1435,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
        return fbi;
 }
 
-static int __init sa1100fb_probe(struct platform_device *pdev)
+static int __devinit sa1100fb_probe(struct platform_device *pdev)
 {
        struct sa1100fb_info *fbi;
        int ret, irq;
index f860122..7a3a5e2 100644 (file)
@@ -745,7 +745,7 @@ int __init sgivwfb_setup(char *options)
 /*
  *  Initialisation
  */
-static int __init sgivwfb_probe(struct platform_device *dev)
+static int __devinit sgivwfb_probe(struct platform_device *dev)
 {
        struct sgivw_par *par;
        struct fb_info *info;
index 8d7653e..bbd1dbf 100644 (file)
@@ -943,7 +943,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
 
 static int sh_mobile_lcdc_remove(struct platform_device *pdev);
 
-static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 {
        struct fb_info *info;
        struct sh_mobile_lcdc_priv *priv;
index 9d2b6bc..a531a0f 100644 (file)
@@ -1891,9 +1891,6 @@ static struct fb_ops sisfb_ops = {
        .fb_fillrect    = fbcon_sis_fillrect,
        .fb_copyarea    = fbcon_sis_copyarea,
        .fb_imageblit   = cfb_imageblit,
-#ifdef CONFIG_FB_SOFT_CURSOR
-       .fb_cursor      = soft_cursor,
-#endif
        .fb_sync        = fbcon_sis_sync,
 #ifdef SIS_NEW_CONFIG_COMPAT
        .fb_compat_ioctl= sisfb_ioctl,
index bd37ee1..ef4128c 100644 (file)
@@ -226,7 +226,7 @@ static int __init vesafb_setup(char *options)
        return 0;
 }
 
-static int __init vesafb_probe(struct platform_device *dev)
+static int __devinit vesafb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int i, err;
index 050d432..b8ab995 100644 (file)
@@ -479,7 +479,7 @@ static int __init vfb_setup(char *options)
      *  Initialisation
      */
 
-static int __init vfb_probe(struct platform_device *dev)
+static int __devinit vfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
index 5b29389..76d8dae 100644 (file)
@@ -1293,7 +1293,7 @@ static int vga16fb_setup(char *options)
 }
 #endif
 
-static int __init vga16fb_probe(struct platform_device *dev)
+static int __devinit vga16fb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct vga16fb_par *par;
index e533b4b..eeed238 100644 (file)
@@ -4,4 +4,4 @@
 
 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
+viafb-y        :=viafbdev.o hw.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
index 474f428..8c06bd3 100644 (file)
 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;
@@ -142,14 +141,9 @@ 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;
+       int max_hres;
+       int max_vres;
 };
 
 struct lvds_setting_information {
@@ -160,7 +154,6 @@ struct lvds_setting_information {
        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;
index 67b3693..abe59b8 100644 (file)
 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 void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
+       *tmds_chip, struct tmds_setting_information *tmds_setting);
+static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
+       *tmds_chip, struct tmds_setting_information *tmds_setting);
 static int viafb_dvi_query_EDID(void);
 
 static int check_tmds_chip(int device_id_subaddr, int device_id)
@@ -38,23 +37,24 @@ static int check_tmds_chip(int device_id_subaddr, int device_id)
                return FAIL;
 }
 
-void viafb_init_dvi_size(void)
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+       struct tmds_setting_information *tmds_setting)
 {
        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:
+       viafb_dvi_sense();
+       switch (viafb_dvi_query_EDID()) {
+       case 1:
+               dvi_get_panel_size_from_DDCv1(tmds_chip, tmds_setting);
                break;
-       case GET_DVI_SZIE_BY_HW_STRAPPING:
+       case 2:
+               dvi_get_panel_size_from_DDCv2(tmds_chip, tmds_setting);
                break;
-       case GET_DVI_SIZE_BY_VGA_BIOS:
        default:
-               dvi_get_panel_info();
+               printk(KERN_WARNING "viafb_init_dvi_size: DVI panel size undetected!\n");
                break;
        }
+
        return;
 }
 
@@ -189,42 +189,14 @@ static int tmds_register_read_bytes(int index, u8 *buff, int 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)
+void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp,
+       int set_iga)
 {
-       struct VideoModeTable *videoMode = NULL;
+       struct VideoModeTable *rb_mode;
        struct crt_mode_table *pDviTiming;
        unsigned long desirePixelClock, maxPixelClock;
-       int status = 0;
-       videoMode = viafb_get_modetbl_pointer(video_index);
-       pDviTiming = videoMode->crtc;
+       pDviTiming = mode->crtc;
        desirePixelClock = pDviTiming->clk / 1000000;
        maxPixelClock = (unsigned long)viaparinfo->
                tmds_setting_info->max_pixel_clock;
@@ -232,20 +204,14 @@ void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga)
        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);
+               rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr,
+                       mode->crtc[0].crtc.ver_addr);
+               if (rb_mode) {
+                       mode = rb_mode;
+                       pDviTiming = rb_mode->crtc;
                }
        }
-       viafb_fill_crtc_timing(pDviTiming, video_index, mode_bpp / 8, set_iga);
+       viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga);
        viafb_set_output_path(DEVICE_DVI, set_iga,
                        viaparinfo->chip_info->tmds_chip_info.output_interface);
 }
@@ -350,25 +316,18 @@ static int viafb_dvi_query_EDID(void)
                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)
+/* Get Panel Size Using EDID1 Table */
+static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
+       *tmds_chip, struct tmds_setting_information *tmds_setting)
 {
-       int i, max_h = 0, max_v = 0, tmp, restore;
+       int i, max_h = 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;
+       restore = tmds_chip->tmds_chip_slave_addr;
+       tmds_chip->tmds_chip_slave_addr = 0xA0;
 
        rData = tmds_register_read(0x23);
        if (rData & 0x3C)
@@ -414,8 +373,8 @@ static int dvi_get_panel_size_from_DDCv1(void)
                                /* 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;
+                                       tmds_setting->max_pixel_clock =
+                                               EDID_DATA[9] * 10;
                                }
                        }
                        break;
@@ -425,154 +384,88 @@ static int dvi_get_panel_size_from_DDCv1(void)
                }
        }
 
+       tmds_setting->max_hres = max_h;
        switch (max_h) {
        case 640:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_640X480;
+               tmds_setting->max_vres = 480;
                break;
        case 800:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_800X600;
+               tmds_setting->max_vres = 600;
                break;
        case 1024:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1024X768;
+               tmds_setting->max_vres = 768;
                break;
        case 1280:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1280X1024;
+               tmds_setting->max_vres = 1024;
                break;
        case 1400:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1400X1050;
+               tmds_setting->max_vres = 1050;
                break;
        case 1440:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1440X1050;
+               tmds_setting->max_vres = 1050;
                break;
        case 1600:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1600X1200;
+               tmds_setting->max_vres = 1200;
                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;
-               }
-
+               tmds_setting->max_vres = 1080;
                break;
        default:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1024X768;
-               DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d !\
-                                        set default panel size.\n", max_h);
+               DEBUG_MSG(KERN_INFO "Unknown 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;
+               tmds_setting->max_pixel_clock);
+       tmds_chip->tmds_chip_slave_addr = restore;
 }
 
-/*
- *
- * 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)
+/* Get Panel Size Using EDID2 Table */
+static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
+       *tmds_chip, struct tmds_setting_information *tmds_setting)
 {
-       int HSize = 0, restore;
+       int 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;
+       restore = tmds_chip->tmds_chip_slave_addr;
+       tmds_chip->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;
+       tmds_setting->max_hres = R_Buffer[0] + (R_Buffer[1] << 8);
 
-       switch (HSize) {
+       switch (tmds_setting->max_hres) {
        case 640:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_640X480;
+               tmds_setting->max_vres = 480;
                break;
        case 800:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_800X600;
+               tmds_setting->max_vres = 600;
                break;
        case 1024:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1024X768;
+               tmds_setting->max_vres = 768;
                break;
        case 1280:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1280X1024;
+               tmds_setting->max_vres = 1024;
                break;
        case 1400:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1400X1050;
+               tmds_setting->max_vres = 1050;
                break;
        case 1440:
-               viaparinfo->tmds_setting_info->dvi_panel_size =
-                       VIA_RES_1440X1050;
+               tmds_setting->max_vres = 1050;
                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 "Unknown 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();
+               tmds_setting->max_vres = 1200;
                break;
        default:
+               DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d! "
+                       "set default panel size.\n", tmds_setting->max_hres);
                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;
+       tmds_chip->tmds_chip_slave_addr = restore;
 }
 
 /* If Disable DVI, turn off pad */
index e1ec37f..0dffcfd 100644 (file)
 #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);
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+       struct tmds_setting_information *tmds_setting);
+void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp,
+       int set_iga);
 
 #endif /* __DVI_H__ */
index b675cdb..1ee511b 100644 (file)
@@ -23,15 +23,12 @@ 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_CRT_ON = 1;
 int viafb_DVI_ON;
 int viafb_LCD_ON ;
@@ -42,8 +39,6 @@ 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;
 unsigned int viafb_second_xres = 640;
 unsigned int viafb_second_yres = 480;
index d69d0ca..8d95d5f 100644 (file)
@@ -35,7 +35,6 @@
 
 #include "debug.h"
 
-#include "iface.h"
 #include "viafbdev.h"
 #include "chip.h"
 #include "accel.h"
@@ -68,8 +67,6 @@ 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;
index 3e083ff..f2583b1 100644 (file)
@@ -524,7 +524,6 @@ 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(struct pci_dev *pdev,
                                const struct pci_device_id *pdi);
@@ -686,6 +685,84 @@ void viafb_set_secondary_pitch(u32 pitch)
        viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80);
 }
 
+void viafb_set_primary_color_depth(u8 depth)
+{
+       u8 value;
+
+       DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth);
+       switch (depth) {
+       case 8:
+               value = 0x00;
+               break;
+       case 15:
+               value = 0x04;
+               break;
+       case 16:
+               value = 0x14;
+               break;
+       case 24:
+               value = 0x0C;
+               break;
+       case 30:
+               value = 0x08;
+               break;
+       default:
+               printk(KERN_WARNING "viafb_set_primary_color_depth: "
+                       "Unsupported depth: %d\n", depth);
+               return;
+       }
+
+       viafb_write_reg_mask(0x15, VIASR, value, 0x1C);
+}
+
+void viafb_set_secondary_color_depth(u8 depth)
+{
+       u8 value;
+
+       DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth);
+       switch (depth) {
+       case 8:
+               value = 0x00;
+               break;
+       case 16:
+               value = 0x40;
+               break;
+       case 24:
+               value = 0xC0;
+               break;
+       case 30:
+               value = 0x80;
+               break;
+       default:
+               printk(KERN_WARNING "viafb_set_secondary_color_depth: "
+                       "Unsupported depth: %d\n", depth);
+               return;
+       }
+
+       viafb_write_reg_mask(0x67, VIACR, value, 0xC0);
+}
+
+static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+       outb(0xFF, 0x3C6); /* bit mask of palette */
+       outb(index, 0x3C8);
+       outb(red, 0x3C9);
+       outb(green, 0x3C9);
+       outb(blue, 0x3C9);
+}
+
+void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+       viafb_write_reg_mask(0x1A, VIASR, 0x00, 0x01);
+       set_color_register(index, red, green, blue);
+}
+
+void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+       viafb_write_reg_mask(0x1A, VIASR, 0x01, 0x01);
+       set_color_register(index, red, green, blue);
+}
+
 void viafb_set_output_path(int device, int set_iga, int output_interface)
 {
        switch (device) {
@@ -710,11 +787,8 @@ static void set_crt_output_path(int set_iga)
                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;
        }
 }
@@ -904,13 +978,6 @@ static void set_lcd_output_path(int set_iga, int output_interface)
 
                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) {
@@ -987,49 +1054,6 @@ static void set_lcd_output_path(int set_iga, int output_interface)
        }
 }
 
-/* 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 */
@@ -1121,15 +1145,13 @@ void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
        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;
+               break;
        case IGA2:
                reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
                viafb_load_reg_num = fetch_count_reg.
@@ -1499,7 +1521,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
        /* H.W. Reset : ON */
        viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
 
-       if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+       if (set_iga == IGA1) {
                /* Change D,N FOR VCLK */
                switch (viaparinfo->chip_info->gfx_chip_name) {
                case UNICHROME_CLE266:
@@ -1528,7 +1550,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
                }
        }
 
-       if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+       if (set_iga == IGA2) {
                /* Change D,N FOR LCK */
                switch (viaparinfo->chip_info->gfx_chip_name) {
                case UNICHROME_CLE266:
@@ -1557,12 +1579,12 @@ void viafb_set_vclock(u32 CLK, int set_iga)
        viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
 
        /* Reset PLL */
-       if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+       if (set_iga == IGA1) {
                viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
                viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
        }
 
-       if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+       if (set_iga == IGA2) {
                viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0);
                viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0);
        }
@@ -1805,47 +1827,15 @@ void viafb_load_crtc_timing(struct display_timing device_timing,
        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, 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;
 
@@ -1858,8 +1848,10 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
 
        /* 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)) {
+       if ((viafb_LCD_ON | viafb_DVI_ON)
+           && video_mode->crtc[0].crtc.hor_addr == 640
+           && video_mode->crtc[0].crtc.ver_addr == 480
+           && viaparinfo->crt_setting_info->refresh_rate == 60) {
                /* The border is 8 pixels. */
                crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
 
@@ -1912,9 +1904,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
            && (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);
@@ -1956,9 +1945,6 @@ void viafb_update_device_setting(int hres, int vres,
 
                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;
@@ -1975,9 +1961,6 @@ void viafb_update_device_setting(int hres, int vres,
                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) {
@@ -2076,9 +2059,8 @@ static void init_tmds_chip_info(void)
 
        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();
+       viafb_init_dvi_size(&viaparinfo->shared->chip_info.tmds_chip_info,
+               &viaparinfo->shared->tmds_setting_info);
 }
 
 static void init_lvds_chip_info(void)
@@ -2195,28 +2177,19 @@ static void set_display_channel(void)
        }
 }
 
-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 viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
+       struct VideoModeTable *vmode_tbl1, 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;
        }
 
@@ -2267,12 +2240,11 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
                outb(VPIT.SR[i - 1], VIASR + 1);
        }
 
-       viafb_set_primary_address(0);
-       viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+       viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
        viafb_set_iga_path();
 
        /* Write CRTC */
-       viafb_fill_crtc_timing(crt_timing, vmode_index, video_bpp / 8, IGA1);
+       viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
 
        /* Write Graphic Controller */
        for (i = 0; i < StdGR; i++) {
@@ -2292,65 +2264,25 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
 
        /* 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);
-                                       }
-                               }
-                       }
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266
+           || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
+           && vmode_tbl->crtc[0].crtc.hor_addr == 1024
+           && vmode_tbl->crtc[0].crtc.ver_addr == 768) {
+               for (j = 0; j < res_patch_table[0].table_length; j++) {
+                       index = res_patch_table[0].io_reg_table[j].index;
+                       port = res_patch_table[0].io_reg_table[j].port;
+                       value = res_patch_table[0].io_reg_table[j].value;
+                       mask = res_patch_table[0].io_reg_table[j].mask;
+                       viafb_write_reg_mask(index, port, value, mask);
                }
        }
 
        viafb_set_primary_pitch(viafbinfo->fix.line_length);
        viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
                : viafbinfo->fix.line_length);
+       viafb_set_primary_color_depth(viaparinfo->depth);
+       viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
+               : viaparinfo->depth);
        /* Update Refresh Rate Setting */
 
        /* Clear On Screen */
@@ -2359,11 +2291,11 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
        if (viafb_CRT_ON) {
                if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path ==
                        IGA2)) {
-                       viafb_fill_crtc_timing(crt_timing1, vmode_index1,
+                       viafb_fill_crtc_timing(crt_timing1, vmode_tbl1,
                                video_bpp1 / 8,
                                viaparinfo->crt_setting_info->iga_path);
                } else {
-                       viafb_fill_crtc_timing(crt_timing, vmode_index,
+                       viafb_fill_crtc_timing(crt_timing, vmode_tbl,
                                video_bpp / 8,
                                viaparinfo->crt_setting_info->iga_path);
                }
@@ -2373,7 +2305,7 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
                /* 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) {
+               if (vmode_tbl->crtc[0].crtc.hor_addr % 8) {
                        viafb_unlock_crt();
                        viafb_write_reg(CR02, VIACR,
                                viafb_read_reg(VIACR, CR02) - 1);
@@ -2384,14 +2316,14 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
        if (viafb_DVI_ON) {
                if (viafb_SAMM_ON &&
                        (viaparinfo->tmds_setting_info->iga_path == IGA2)) {
-                       viafb_dvi_set_mode(viafb_get_mode_index
+                       viafb_dvi_set_mode(viafb_get_mode
                                     (viaparinfo->tmds_setting_info->h_active,
                                      viaparinfo->tmds_setting_info->
                                      v_active),
                                     video_bpp1, viaparinfo->
                                     tmds_setting_info->iga_path);
                } else {
-                       viafb_dvi_set_mode(viafb_get_mode_index
+                       viafb_dvi_set_mode(viafb_get_mode
                                     (viaparinfo->tmds_setting_info->h_active,
                                      viaparinfo->
                                      tmds_setting_info->v_active),
@@ -2445,8 +2377,8 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
 
        /* 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_Xres = vmode_tbl->crtc[0].crtc.hor_addr;
+               viafb_hotplug_Yres = vmode_tbl->crtc[0].crtc.ver_addr;
                viafb_hotplug_bpp = video_bpp;
                viafb_hotplug_refresh = viafb_refresh;
 
@@ -2706,13 +2638,11 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
 
 /*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)
 {
-       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;
@@ -2721,36 +2651,6 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
        }
 
        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);
index b874d95..12ef32d 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef __HW_H__
 #define __HW_H__
 
+#include "viamode.h"
 #include "global.h"
 
 /***************************************************
@@ -862,8 +863,6 @@ struct pci_device_id_info {
 };
 
 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;
@@ -874,8 +873,9 @@ 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);
+       struct VideoModeTable *video_mode, 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,
@@ -891,16 +891,15 @@ void viafb_lock_crt(void);
 void viafb_unlock_crt(void);
 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);
+int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
+       struct VideoModeTable *vmode_tbl1, int video_bpp1);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+       struct VideoModeTable *vmode_tbl);
 void viafb_init_chip_info(struct pci_dev *pdev,
                          const struct pci_device_id *pdi);
 void viafb_init_dac(int set_iga);
@@ -915,6 +914,8 @@ void viafb_set_primary_address(u32 addr);
 void viafb_set_secondary_address(u32 addr);
 void viafb_set_primary_pitch(u32 pitch);
 void viafb_set_secondary_pitch(u32 pitch);
+void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
+void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
 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
deleted file mode 100644 (file)
index 1570636..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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
deleted file mode 100644 (file)
index 790ec3e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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__ */
index 09353e2..1b1ccdc 100644 (file)
 #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} } }
-};
+#define viafb_compact_res(x, y) (((x)<<16)|(y))
 
 static struct _lcd_scaling_factor lcd_scaling_factor = {
        /* LCD Horizontal Scaling Factor Register */
@@ -59,16 +41,10 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
 
 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 void 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
@@ -98,8 +74,6 @@ static void check_diport_of_integrated_lvds(
 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);
 
@@ -125,33 +99,24 @@ void viafb_init_lcd_size(void)
                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);
+               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);
+               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);
+               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 =
@@ -171,13 +136,13 @@ static bool lvds_identify_integratedlvds(void)
                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");
+                       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");
+                       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): */
@@ -185,8 +150,8 @@ static bool lvds_identify_integratedlvds(void)
                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");
+               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. */
@@ -248,7 +213,7 @@ int viafb_lvds_trasmitter_identify(void)
        return FAIL;
 }
 
-static int fp_id_to_vindex(int panel_id)
+static void fp_id_to_vindex(int panel_id)
 {
        DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
 
@@ -264,7 +229,6 @@ static int fp_id_to_vindex(int 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;
@@ -273,7 +237,6 @@ static int fp_id_to_vindex(int 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;
@@ -282,7 +245,6 @@ static int fp_id_to_vindex(int 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;
@@ -291,7 +253,6 @@ static int fp_id_to_vindex(int 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;
@@ -300,7 +261,6 @@ static int fp_id_to_vindex(int 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;
@@ -309,7 +269,6 @@ static int fp_id_to_vindex(int 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;
@@ -318,7 +277,6 @@ static int fp_id_to_vindex(int 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;
@@ -327,7 +285,6 @@ static int fp_id_to_vindex(int 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;
@@ -336,7 +293,6 @@ static int fp_id_to_vindex(int 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;
@@ -345,7 +301,6 @@ static int fp_id_to_vindex(int 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;
@@ -354,7 +309,6 @@ static int fp_id_to_vindex(int 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;
@@ -363,7 +317,6 @@ static int fp_id_to_vindex(int 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;
@@ -372,7 +325,6 @@ static int fp_id_to_vindex(int 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;
@@ -381,7 +333,6 @@ static int fp_id_to_vindex(int 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;
@@ -390,7 +341,6 @@ static int fp_id_to_vindex(int 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;
@@ -399,7 +349,6 @@ static int fp_id_to_vindex(int 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;
@@ -408,7 +357,6 @@ static int fp_id_to_vindex(int 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;
@@ -417,7 +365,6 @@ static int fp_id_to_vindex(int 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;
@@ -426,7 +373,6 @@ static int fp_id_to_vindex(int 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;
@@ -435,7 +381,6 @@ static int fp_id_to_vindex(int 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;
@@ -444,7 +389,6 @@ static int fp_id_to_vindex(int 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;
@@ -453,7 +397,6 @@ static int fp_id_to_vindex(int 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;
@@ -462,7 +405,6 @@ static int fp_id_to_vindex(int panel_id)
                        LCD_PANEL_ID1_800X600;
                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
                viaparinfo->lvds_setting_info->LCDDithering = 1;
-               return VIA_RES_800X600;
        }
 }
 
@@ -573,284 +515,6 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
        }
 }
 
-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;
-
-       vmode_index = viafb_get_mode_index(set_hres, set_vres);
-       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;
-
-       vmode_index = viafb_get_mode_index(set_hres, set_vres);
-
-       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;
-
-       vmode_index = viafb_get_mode_index(set_hres, set_vres);
-
-       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
@@ -949,29 +613,25 @@ 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 set_hres, set_vres;
-       int panel_hres, panel_vres;
+       int set_hres = plvds_setting_info->h_active;
+       int set_vres = plvds_setting_info->v_active;
+       int panel_hres = plvds_setting_info->lcd_panel_hres;
+       int panel_vres = plvds_setting_info->lcd_panel_vres;
        u32 pll_D_N;
-       int offset;
        struct display_timing mode_crt_reg, panel_crt_reg;
        struct crt_mode_table *panel_crt_table = NULL;
-       struct VideoModeTable *vmode_tbl = NULL;
+       struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres,
+               panel_vres);
 
        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;
@@ -1001,54 +661,12 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
                }
        }
 
-       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 */
-               viafb_set_secondary_pitch(offset << 3);
-               DEBUG_MSG(KERN_INFO "viafb_load_reg!!\n");
-               viafb_load_fetch_count_reg(set_hres, 4, IGA2);
-               /* Fetch count for simultaneous */
-       } else {                /* SAMM */
-               /* 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);
+       /* Fetch count for IGA2 only */
+       viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
 
-               viafb_set_color_depth(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);
 
        fill_lcd_format();
 
@@ -1065,11 +683,6 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
            || (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);
 }
@@ -1283,8 +896,7 @@ void viafb_lcd_enable(void)
                viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
        }
 
-       if ((viaparinfo->lvds_setting_info->iga_path == IGA1)
-           || (viaparinfo->lvds_setting_info->iga_path == IGA1_IGA2)) {
+       if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
                /* CRT path set to IGA2    */
                viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40);
                /* IGA2 path disabled      */
@@ -1476,210 +1088,6 @@ static struct display_timing lcd_centering_timging(struct display_timing
        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;
index 7cd03e2..d55aaa7 100644 (file)
 /* 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
 /* Display path */
 #define IGA1        1
 #define IGA2        2
-#define IGA1_IGA2   3
 
 /* Define Color Depth  */
 #define MODE_8BPP       1
index d53c3d5..aefdeee 100644 (file)
@@ -239,15 +239,3 @@ void viafb_get_gamma_support_state(int bpp, unsigned int *support_state)
        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;
-}
index 2fd4552..1670ba8 100644 (file)
@@ -30,6 +30,5 @@ bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres);
 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__ */
index 3028e7d..ce7783b 100644 (file)
 
 #include "global.h"
 
-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 char *viafb_mode;
+static char *viafb_mode1;
+static int viafb_bpp = 32;
+static int viafb_bpp1 = 32;
+
+static unsigned int viafb_second_offset;
+static int viafb_second_size;
 
 static int viafb_accel = 1;
 
 /* Added for specifying active devices.*/
-char *viafb_active_dev = "";
+char *viafb_active_dev;
 
 /*Added for specify lcd output port*/
 char *viafb_lcd_port = "";
@@ -50,18 +54,78 @@ static void apply_second_mode_setting(struct fb_var_screeninfo
        *sec_var);
 static void retrieve_device_setting(struct viafb_ioctl_setting
        *setting_info);
+static int viafb_pan_display(struct fb_var_screeninfo *var,
+       struct fb_info *info);
 
 static struct fb_ops viafb_ops;
 
 
+static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)
+{
+       var->grayscale = 0;
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
+       var->transp.offset = 0;
+       var->transp.length = 0;
+       var->transp.msb_right = 0;
+       var->nonstd = 0;
+       switch (depth) {
+       case 8:
+               var->bits_per_pixel = 8;
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               break;
+       case 15:
+               var->bits_per_pixel = 16;
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               break;
+       case 16:
+               var->bits_per_pixel = 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 24:
+               var->bits_per_pixel = 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;
+       case 30:
+               var->bits_per_pixel = 32;
+               var->red.offset = 20;
+               var->green.offset = 10;
+               var->blue.offset = 0;
+               var->red.length = 10;
+               var->green.length = 10;
+               var->blue.length = 10;
+               break;
+       }
+}
+
 static void viafb_update_fix(struct fb_info *info)
 {
        u32 bpp = info->var.bits_per_pixel;
 
        info->fix.visual =
                bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-       info->fix.line_length =
-               ((info->var.xres_virtual + 7) & ~7) * bpp / 8;
+       info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
 }
 
 static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -75,6 +139,7 @@ static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
 
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->type_aux = 0;
+       fix->visual = FB_VISUAL_TRUECOLOR;
 
        fix->xpanstep = fix->ywrapstep = 0;
        fix->ypanstep = 1;
@@ -97,9 +162,10 @@ static int viafb_release(struct fb_info *info, int user)
 static int viafb_check_var(struct fb_var_screeninfo *var,
        struct fb_info *info)
 {
-       int vmode_index, htotal, vtotal;
+       int htotal, vtotal, depth;
+       struct VideoModeTable *vmode_entry;
        struct viafb_par *ppar = info->par;
-       u32 long_refresh;
+       u32 long_refresh, line;
 
        DEBUG_MSG(KERN_INFO "viafb_check_var!\n");
        /* Sanity check */
@@ -107,26 +173,36 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
        if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
                return -EINVAL;
 
-       vmode_index = viafb_get_mode_index(var->xres, var->yres);
-       if (vmode_index == VIA_RES_INVALID) {
+       vmode_entry = viafb_get_mode(var->xres, var->yres);
+       if (!vmode_entry) {
                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;
+       depth = fb_get_color_depth(var, &info->fix);
+       if (!depth)
+               depth = var->bits_per_pixel;
 
-       if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
-               var->bits_per_pixel != 32)
+       if (depth < 0 || depth > 32)
                return -EINVAL;
+       else if (!depth)
+               depth = 24;
+       else if (depth == 15 && viafb_dual_fb && ppar->iga_path == IGA1)
+               depth = 15;
+       else if (depth == 30)
+               depth = 30;
+       else if (depth <= 8)
+               depth = 8;
+       else if (depth <= 16)
+               depth = 16;
+       else
+               depth = 24;
 
-       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)
+       viafb_fill_var_color_info(var, depth);
+       line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
+       if (line * var->yres_virtual > ppar->memsize)
                return -EINVAL;
 
        /* Based on var passed in to calculate the refresh,
@@ -142,7 +218,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
        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);
+       viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
        if (info->var.accel_flags & FB_ACCELF_TEXT &&
                !ppar->shared->engine_mmio)
                info->var.accel_flags = 0;
@@ -153,39 +229,45 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
 static int viafb_set_par(struct fb_info *info)
 {
        struct viafb_par *viapar = info->par;
-       int vmode_index;
-       int vmode_index1 = 0;
+       struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL;
        DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
 
        viapar->depth = fb_get_color_depth(&info->var, &info->fix);
-       viafb_update_device_setting(info->var.xres, info->var.yres,
-                             info->var.bits_per_pixel, viafb_refresh, 0);
+       viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
+               viafbinfo->var.bits_per_pixel, viafb_refresh, 0);
 
-       vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres);
-
-       if (viafb_SAMM_ON == 1) {
+       vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres);
+       if (viafb_dual_fb) {
+               vmode_entry1 = viafb_get_mode(viafbinfo1->var.xres,
+                       viafbinfo1->var.yres);
+               viafb_update_device_setting(viafbinfo1->var.xres,
+                       viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,
+                       viafb_refresh1, 1);
+       } else 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,
+               vmode_entry1 = viafb_get_mode(viafb_second_xres,
                        viafb_second_yres);
-               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) {
+       if (vmode_entry) {
                viafb_update_fix(info);
-               viafb_bpp = info->var.bits_per_pixel;
+               if (viafb_dual_fb && viapar->iga_path == IGA2)
+                       viafb_bpp1 = info->var.bits_per_pixel;
+               else
+                       viafb_bpp = info->var.bits_per_pixel;
+
                if (info->var.accel_flags & FB_ACCELF_TEXT)
                        info->flags &= ~FBINFO_HWACCEL_DISABLED;
                else
                        info->flags |= FBINFO_HWACCEL_DISABLED;
-               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);
+               viafb_setmode(vmode_entry, info->var.bits_per_pixel,
+                       vmode_entry1, viafb_bpp1);
+               viafb_pan_display(&info->var, info);
        }
 
        return 0;
@@ -195,234 +277,52 @@ static int viafb_set_par(struct fb_info *info)
 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;
+       struct viafb_par *viapar = info->par;
+       u32 r, g, b;
 
-}
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+               if (regno > 255)
+                       return -EINVAL;
 
-/*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);
-               }
+               if (!viafb_dual_fb || viapar->iga_path == IGA1)
+                       viafb_set_primary_color_register(regno, red >> 8,
+                               green >> 8, blue >> 8);
 
-               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);
-               }
+               if (!viafb_dual_fb || viapar->iga_path == IGA2)
+                       viafb_set_secondary_color_register(regno, red >> 8,
+                               green >> 8, blue >> 8);
+       } else {
+               if (regno > 15)
+                       return -EINVAL;
 
-               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;
+               r = (red >> (16 - info->var.red.length))
+                       << info->var.red.offset;
+               b = (blue >> (16 - info->var.blue.length))
+                       << info->var.blue.offset;
+               g = (green >> (16 - info->var.green.length))
+                       << info->var.green.offset;
+               ((u32 *) info->pseudo_palette)[regno] = r | g | b;
        }
+
        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;
+       struct viafb_par *viapar = info->par;
+       u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
+               * (var->bits_per_pixel / 8) + viapar->vram_addr;
+
+       DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
+       if (!viafb_dual_fb) {
+               viafb_set_primary_address(vram_addr);
+               viafb_set_secondary_address(vram_addr);
+       } else if (viapar->iga_path == IGA1)
+               viafb_set_primary_address(vram_addr);
+       else
+               viafb_set_secondary_address(vram_addr);
 
-       DEBUG_MSG(KERN_INFO "\nviafb_pan_display,offset =%d ", offset);
-       viafb_set_primary_address(offset);
        return 0;
 }
 
@@ -476,6 +376,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
        u32 gpu32;
 
        DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
+       printk(KERN_WARNING "viafb_ioctl: Please avoid this interface as it is unstable and might change or vanish at any time!\n");
        memset(&u, 0, sizeof(u));
 
        switch (cmd) {
@@ -1015,23 +916,6 @@ static int viafb_sync(struct fb_info *info)
        return 0;
 }
 
-int viafb_get_mode_index(int hres, int vres)
-{
-       u32 i;
-       DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n");
-
-       for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
-               if (CLE266Modes[i].mode_array &&
-                       CLE266Modes[i].crtc[0].crtc.hor_addr == hres &&
-                       CLE266Modes[i].crtc[0].crtc.ver_addr == vres)
-                       break;
-
-       if (i == NUM_TOTAL_MODETABLE)
-               return VIA_RES_INVALID;
-
-       return CLE266Modes[i].ModeIndex;
-}
-
 static void check_available_device_to_enable(int device_id)
 {
        int device_num = 0;
@@ -1330,7 +1214,7 @@ static void retrieve_device_setting(struct viafb_ioctl_setting
        setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
 }
 
-static void parse_active_dev(void)
+static int parse_active_dev(void)
 {
        viafb_CRT_ON = STATE_OFF;
        viafb_DVI_ON = STATE_OFF;
@@ -1341,60 +1225,63 @@ static void parse_active_dev(void)
           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)) {
+       if (!viafb_active_dev) {
+               viafb_CRT_ON = STATE_ON;
+               viafb_SAMM_ON = STATE_OFF;
+       } else if (!strcmp(viafb_active_dev, "CRT+DVI")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "DVI+CRT")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "CRT+LCD")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "LCD+CRT")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "DVI+LCD")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "LCD+DVI")) {
                /* 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)) {
+       } else if (!strcmp(viafb_active_dev, "LCD+LCD2")) {
                viafb_LCD_ON = STATE_ON;
                viafb_LCD2_ON = STATE_ON;
                viafb_primary_dev = LCD_Device;
-       } else if (!strncmp(viafb_active_dev, "LCD2+LCD", 8)) {
+       } else if (!strcmp(viafb_active_dev, "LCD2+LCD")) {
                viafb_LCD_ON = STATE_ON;
                viafb_LCD2_ON = STATE_ON;
                viafb_primary_dev = LCD2_Device;
-       } else if (!strncmp(viafb_active_dev, "CRT", 3)) {
+       } else if (!strcmp(viafb_active_dev, "CRT")) {
                /* CRT only */
                viafb_CRT_ON = STATE_ON;
                viafb_SAMM_ON = STATE_OFF;
-       } else if (!strncmp(viafb_active_dev, "DVI", 3)) {
+       } else if (!strcmp(viafb_active_dev, "DVI")) {
                /* DVI only */
                viafb_DVI_ON = STATE_ON;
                viafb_SAMM_ON = STATE_OFF;
-       } else if (!strncmp(viafb_active_dev, "LCD", 3)) {
+       } else if (!strcmp(viafb_active_dev, "LCD")) {
                /* LCD only */
                viafb_LCD_ON = STATE_ON;
                viafb_SAMM_ON = STATE_OFF;
-       } else {
-               viafb_CRT_ON = STATE_ON;
-               viafb_SAMM_ON = STATE_OFF;
-       }
+       } else
+               return -EINVAL;
+
+       return 0;
 }
 
 static int parse_port(char *opt_str, int *output_interface)
@@ -1823,35 +1710,37 @@ static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
        remove_proc_entry("viafb", NULL);
 }
 
-static void parse_mode(const char *str, u32 *xres, u32 *yres)
+static int parse_mode(const char *str, u32 *xres, u32 *yres)
 {
        char *ptr;
 
+       if (!str) {
+               *xres = 640;
+               *yres = 480;
+               return 0;
+       }
+
        *xres = simple_strtoul(str, &ptr, 10);
        if (ptr[0] != 'x')
-               goto out_default;
+               return -EINVAL;
 
        *yres = simple_strtoul(&ptr[1], &ptr, 10);
        if (ptr[0])
-               goto out_default;
-
-       return;
+               return -EINVAL;
 
-out_default:
-       printk(KERN_WARNING "viafb received invalid mode string: %s\n", str);
-       *xres = 640;
-       *yres = 480;
+       return 0;
 }
 
 static int __devinit via_pci_probe(struct pci_dev *pdev,
                                   const struct pci_device_id *ent)
 {
        u32 default_xres, default_yres;
-       int vmode_index;
+       struct VideoModeTable *vmode_entry;
+       struct fb_var_screeninfo default_var;
        u32 viafb_par_length;
 
        DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
-
+       memset(&default_var, 0, sizeof(default_var));
        viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);
 
        /* Allocate fb_info and ***_par here, also including some other needed
@@ -1877,7 +1766,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
 
        if (viafb_dual_fb)
                viafb_SAMM_ON = 1;
-       parse_active_dev();
        parse_lcd_port();
        parse_dvi_port();
 
@@ -1926,9 +1814,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        }
 
        parse_mode(viafb_mode, &default_xres, &default_yres);
-       vmode_index = viafb_get_mode_index(default_xres, default_yres);
-       DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index);
-
+       vmode_entry = viafb_get_mode(default_xres, default_yres);
        if (viafb_SAMM_ON == 1) {
                parse_mode(viafb_mode1, &viafb_second_xres,
                        &viafb_second_yres);
@@ -1947,19 +1833,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
                        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) {
@@ -1972,8 +1845,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        }
        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;
@@ -1982,6 +1853,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        default_var.lower_margin = 4;
        default_var.hsync_len = default_var.left_margin;
        default_var.vsync_len = 4;
+       viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
+       viafbinfo->var = default_var;
 
        if (viafb_dual_fb) {
                viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev);
@@ -2016,8 +1889,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
                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,
@@ -2037,9 +1908,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
                        &viafbinfo1->fix);
        }
 
-       viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
-       viafb_check_var(&default_var, viafbinfo);
-       viafbinfo->var = default_var;
+       viafb_check_var(&viafbinfo->var, viafbinfo);
        viafb_update_fix(viafbinfo);
        viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
                &viafbinfo->fix);
@@ -2197,12 +2066,20 @@ static struct pci_driver viafb_driver = {
 
 static int __init viafb_init(void)
 {
+       u32 dummy;
 #ifndef MODULE
        char *option = NULL;
        if (fb_get_options("viafb", &option))
                return -ENODEV;
        viafb_setup(option);
 #endif
+       if (parse_mode(viafb_mode, &dummy, &dummy)
+               || parse_mode(viafb_mode1, &dummy, &dummy)
+               || viafb_bpp < 0 || viafb_bpp > 32
+               || viafb_bpp1 < 0 || viafb_bpp1 > 32
+               || parse_active_dev())
+               return -EINVAL;
+
        printk(KERN_INFO
        "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
               VERSION_MAJOR, VERSION_MINOR);
@@ -2230,15 +2107,12 @@ static struct fb_ops viafb_ops = {
        .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, S_IRUSR);
-
 module_param(viafb_mode, charp, S_IRUSR);
 MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");
 
index 0c94d24..61b5953 100644 (file)
@@ -83,22 +83,16 @@ struct viafb_par {
 
 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_hotplug;
-extern int viafb_memsize;
 
 extern int strict_strtoul(const char *cp, unsigned int base,
        unsigned long *res);
 
-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);
 u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
        *plvds_setting_info, struct lvds_chip_information
        *plvds_chip_info, u8 index);
index b74f8a6..af50e24 100644 (file)
@@ -412,7 +412,7 @@ struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C},
 };
 
 struct patch_table res_patch_table[] = {
-       {VIA_RES_1024X768, ARRAY_SIZE(PM1024x768), PM1024x768}
+       {ARRAY_SIZE(PM1024x768), PM1024x768}
 };
 
 /* struct VPITTable {
@@ -879,169 +879,151 @@ struct crt_mode_table CRTM2048x1536[] = {
         {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[] = {
+struct VideoModeTable viafb_modes[] = {
        /* Display : 480x640 (GTF) */
-       {VIA_RES_480X640, CRTM480x640, ARRAY_SIZE(CRTM480x640)},
+       {CRTM480x640, ARRAY_SIZE(CRTM480x640)},
 
        /* Display : 640x480 */
-       {VIA_RES_640X480, CRTM640x480, ARRAY_SIZE(CRTM640x480)},
+       {CRTM640x480, ARRAY_SIZE(CRTM640x480)},
 
        /* Display : 720x480 (GTF) */
-       {VIA_RES_720X480, CRTM720x480, ARRAY_SIZE(CRTM720x480)},
+       {CRTM720x480, ARRAY_SIZE(CRTM720x480)},
 
        /* Display : 720x576 (GTF) */
-       {VIA_RES_720X576, CRTM720x576, ARRAY_SIZE(CRTM720x576)},
+       {CRTM720x576, ARRAY_SIZE(CRTM720x576)},
 
        /* Display : 800x600 */
-       {VIA_RES_800X600, CRTM800x600, ARRAY_SIZE(CRTM800x600)},
+       {CRTM800x600, ARRAY_SIZE(CRTM800x600)},
 
        /* Display : 800x480 (CVT) */
-       {VIA_RES_800X480, CRTM800x480, ARRAY_SIZE(CRTM800x480)},
+       {CRTM800x480, ARRAY_SIZE(CRTM800x480)},
 
        /* Display : 848x480 (CVT) */
-       {VIA_RES_848X480, CRTM848x480, ARRAY_SIZE(CRTM848x480)},
+       {CRTM848x480, ARRAY_SIZE(CRTM848x480)},
 
        /* Display : 852x480 (GTF) */
-       {VIA_RES_856X480, CRTM852x480, ARRAY_SIZE(CRTM852x480)},
+       {CRTM852x480, ARRAY_SIZE(CRTM852x480)},
 
        /* Display : 1024x512 (GTF) */
-       {VIA_RES_1024X512, CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
+       {CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
 
        /* Display : 1024x600 */
-       {VIA_RES_1024X600, CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
-
-       /* Display : 1024x576 (GTF) */
-       /*{ VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, */
+       {CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
 
        /* Display : 1024x768 */
-       {VIA_RES_1024X768, CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
+       {CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
 
        /* Display : 1152x864 */
-       {VIA_RES_1152X864, CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
+       {CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
 
        /* Display : 1280x768 (GTF) */
-       {VIA_RES_1280X768, CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
+       {CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
 
        /* Display : 960x600 (CVT) */
-       {VIA_RES_960X600, CRTM960x600, ARRAY_SIZE(CRTM960x600)},
+       {CRTM960x600, ARRAY_SIZE(CRTM960x600)},
 
        /* Display : 1000x600 (GTF) */
-       {VIA_RES_1000X600, CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
+       {CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
 
        /* Display : 1024x576 (GTF) */
-       {VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
+       {CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
 
        /* Display : 1088x612 (GTF) */
-       {VIA_RES_1088X612, CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
+       {CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
 
        /* Display : 1152x720 (CVT) */
-       {VIA_RES_1152X720, CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
+       {CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
 
        /* Display : 1200x720 (GTF) */
-       {VIA_RES_1200X720, CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
+       {CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
 
        /* Display : 1280x600 (GTF) */
-       {VIA_RES_1280X600, CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
+       {CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
 
        /* Display : 1280x800 (CVT) */
-       {VIA_RES_1280X800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
-
-       /* Display : 1280x800 (GTF) */
-       /*{ M1280x800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, */
+       {CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
 
        /* Display : 1280x960 */
-       {VIA_RES_1280X960, CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
+       {CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
 
        /* Display : 1280x1024 */
-       {VIA_RES_1280X1024, CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
+       {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)},
+       {CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
 
        /* Display : 1366x768 */
-       {VIA_RES_1366X768, CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
+       {CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
 
        /* Display : 1368x768 (GTF) */
-       /*{ M1368x768,CRTM1368x768,ARRAY_SIZE(CRTM1368x768)}, */
-       /* Display : 1368x768 (GTF) */
-       {VIA_RES_1368X768, CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
+       {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)},
+       {CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
 
        /* 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)},
+       {CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
 
        /* 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)},
+       {CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
 
        /* Display : 1600x1024 (GTF) */
-       {VIA_RES_1600X1024, CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
+       {CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
 
        /* Display : 1600x1200 */
-       {VIA_RES_1600X1200, CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
+       {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)},
+       {CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
 
        /* Display : 1792x1344 (DMT) */
-       {VIA_RES_1792X1344, CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
+       {CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
 
        /* Display : 1856x1392 (DMT) */
-       {VIA_RES_1856X1392, CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
+       {CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
 
        /* Display : 1920x1440 */
-       {VIA_RES_1920X1440, CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
+       {CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
 
        /* Display : 2048x1536 */
-       {VIA_RES_2048X1536, CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
+       {CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
 
        /* Display : 1280x720 */
-       {VIA_RES_1280X720, CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
+       {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)},
+       {CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
 
        /* 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)},
+       {CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
 
        /* Display : 1400x1050 (CVT) */
-       {VIA_RES_1400X1050, CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
+       {CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
 };
+
+struct VideoModeTable viafb_rb_modes[] = {
+       /* Display : 1360x768 (CVT Reduce Blanking) */
+       {CRTM1360x768_RB, ARRAY_SIZE(CRTM1360x768_RB)},
+
+       /* Display : 1440x900 (CVT Reduce Blanking) */
+       {CRTM1440x900_RB, ARRAY_SIZE(CRTM1440x900_RB)},
+
+       /* Display : 1400x1050 (CVT Reduce Blanking) */
+       {CRTM1400x1050_RB, ARRAY_SIZE(CRTM1400x1050_RB)},
+
+       /* Display : 1600x900 (CVT Reduce Blanking) */
+       {CRTM1600x900_RB, ARRAY_SIZE(CRTM1600x900_RB)},
+
+       /* Display : 1680x1050 (CVT Reduce Blanking) */
+       {CRTM1680x1050_RB, ARRAY_SIZE(CRTM1680x1050_RB)},
+
+       /* Display : 1920x1080 (CVT Reduce Blanking) */
+       {CRTM1920x1080_RB, ARRAY_SIZE(CRTM1920x1080_RB)},
+
+       /* Display : 1920x1200 (CVT Reduce Blanking) */
+       {CRTM1920x1200_RB, ARRAY_SIZE(CRTM1920x1200_RB)}
+};
+
 struct crt_mode_table CEAM1280x720[] = {
        {REFRESH_60, CLK_74_270M, M1280X720_CEA_R60_HSP,
         M1280X720_CEA_R60_VSP,
@@ -1056,8 +1038,8 @@ struct crt_mode_table CEAM1920x1080[] = {
 };
 struct VideoModeTable CEA_HDMI_Modes[] = {
        /* Display : 1280x720 */
-       {VIA_RES_1280X720, CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
-       {VIA_RES_1920X1080, CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
+       {CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
+       {CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
 };
 
 int NUM_TOTAL_RES_MAP_REFRESH = ARRAY_SIZE(res_map_refresh_tbl);
@@ -1069,4 +1051,28 @@ int NUM_TOTAL_CX700_ModeXregs = ARRAY_SIZE(CX700_ModeXregs);
 int NUM_TOTAL_VX855_ModeXregs = ARRAY_SIZE(VX855_ModeXregs);
 int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs);
 int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table);
-int NUM_TOTAL_MODETABLE = ARRAY_SIZE(CLE266Modes);
+
+
+struct VideoModeTable *viafb_get_mode(int hres, int vres)
+{
+       u32 i;
+       for (i = 0; i < ARRAY_SIZE(viafb_modes); i++)
+               if (viafb_modes[i].mode_array &&
+                       viafb_modes[i].crtc[0].crtc.hor_addr == hres &&
+                       viafb_modes[i].crtc[0].crtc.ver_addr == vres)
+                       return &viafb_modes[i];
+
+       return NULL;
+}
+
+struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+{
+       u32 i;
+       for (i = 0; i < ARRAY_SIZE(viafb_rb_modes); i++)
+               if (viafb_rb_modes[i].mode_array &&
+                       viafb_rb_modes[i].crtc[0].crtc.hor_addr == hres &&
+                       viafb_rb_modes[i].crtc[0].crtc.ver_addr == vres)
+                       return &viafb_rb_modes[i];
+
+       return NULL;
+}
index a9d6554..5b1ced8 100644 (file)
@@ -32,13 +32,11 @@ struct VPITTable {
 };
 
 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;
 };
@@ -59,13 +57,11 @@ extern int NUM_TOTAL_CX700_ModeXregs;
 extern int NUM_TOTAL_VX855_ModeXregs;
 extern int NUM_TOTAL_CLE266_ModeXregs;
 extern int NUM_TOTAL_PATCH_MODE;
-extern int NUM_TOTAL_MODETABLE;
 
 /********************/
 /* Mode Table       */
 /********************/
 
-extern struct VideoModeTable CLE266Modes[];
 extern struct crt_mode_table CEAM1280x720[];
 extern struct crt_mode_table CEAM1920x1080[];
 extern struct VideoModeTable CEA_HDMI_Modes[];
@@ -81,4 +77,8 @@ extern struct io_reg CLE266_ModeXregs[];
 extern struct io_reg PM1024x768[];
 extern struct patch_table res_patch_table[];
 extern struct VPITTable VPIT;
+
+struct VideoModeTable *viafb_get_mode(int hres, int vres);
+struct VideoModeTable *viafb_get_rb_mode(int hres, int vres);
+
 #endif /* __VIAMODE_H__ */
index 2376f68..5d22395 100644 (file)
@@ -628,7 +628,7 @@ static int w100fb_resume(struct platform_device *dev)
 #endif
 
 
-int __init w100fb_probe(struct platform_device *pdev)
+int __devinit w100fb_probe(struct platform_device *pdev)
 {
        int err = -EIO;
        struct w100fb_mach_info *inf;
index 406caa6..e5f7441 100644 (file)
@@ -214,7 +214,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
                         (++retries < DS2482_WAIT_IDLE_TIMEOUT));
        }
 
-       if (retries > DS2482_WAIT_IDLE_TIMEOUT)
+       if (retries >= DS2482_WAIT_IDLE_TIMEOUT)
                printk(KERN_ERR "%s: timeout on channel %d\n",
                       __func__, pdev->channel);
 
index 65244c0..4926703 100644 (file)
@@ -102,7 +102,7 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
        return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
 }
 
-static int __init mxc_w1_probe(struct platform_device *pdev)
+static int __devinit mxc_w1_probe(struct platform_device *pdev)
 {
        struct mxc_w1_device *mdev;
        struct resource *res;
@@ -166,7 +166,7 @@ failed_clk:
 /*
  * disassociate the w1 device from the driver
  */
-static int mxc_w1_remove(struct platform_device *pdev)
+static int __devexit mxc_w1_remove(struct platform_device *pdev)
 {
        struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
        struct resource *res;
index 0d92969..22977d3 100644 (file)
@@ -72,7 +72,7 @@ struct hdq_data {
        int                     init_trans;
 };
 
-static int __init omap_hdq_probe(struct platform_device *pdev);
+static int __devinit omap_hdq_probe(struct platform_device *pdev);
 static int omap_hdq_remove(struct platform_device *pdev);
 
 static struct platform_driver omap_hdq_driver = {
@@ -558,7 +558,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
        return;
 }
 
-static int __init omap_hdq_probe(struct platform_device *pdev)
+static int __devinit omap_hdq_probe(struct platform_device *pdev)
 {
        struct hdq_data *hdq_data;
        struct resource *res;
index 3da3f48..bdcdbd5 100644 (file)
@@ -55,6 +55,11 @@ config SOFT_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called softdog.
 
+config MAX63XX_WATCHDOG
+       tristate "Max63xx watchdog"
+       help
+         Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
+
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
        depends on MFD_WM831X
@@ -289,6 +294,17 @@ config ADX_WATCHDOG
          Say Y here if you want support for the watchdog timer on Avionic
          Design Xanthos boards.
 
+config TS72XX_WATCHDOG
+       tristate "TS-72XX SBC Watchdog"
+       depends on MACH_TS72XX
+       help
+         Technologic Systems TS-7200, TS-7250 and TS-7260 boards have
+         watchdog timer implemented in a external CPLD chip. Say Y here
+         if you want to support for the watchdog timer on TS-72XX boards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ts72xx_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
@@ -845,10 +861,10 @@ config TXX9_WDT
 # POWERPC Architecture
 
 config GEF_WDT
-       tristate "GE Fanuc Watchdog Timer"
+       tristate "GE Watchdog Timer"
        depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
        ---help---
-         Watchdog timer found in a number of GE Fanuc single board computers.
+         Watchdog timer found in a number of GE single board computers.
 
 config MPC5200_WDT
        bool "MPC52xx Watchdog Timer"
index 475c611..5e3cb95 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
+obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -142,4 +143,5 @@ obj-$(CONFIG_WATCHDOG_CP1XXX)               += cpwd.o
 # Architecture Independant
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
+obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
index 4d18c87..2ffce4d 100644 (file)
@@ -150,7 +150,7 @@ static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int options, retval = -EINVAL;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
                .firmware_version = 1,
                .identity = WATCHDOG_NAME,
index 824d076..4d40965 100644 (file)
@@ -137,7 +137,7 @@ static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int new_timeout;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING |
                           WDIOF_SETTIMEOUT |
                           WDIOF_MAGICCLOSE,
index 9d7d155..a5ca7a6 100644 (file)
@@ -37,7 +37,7 @@ struct adx_wdt {
        spinlock_t lock;
 };
 
-static struct watchdog_info adx_wdt_info = {
+static const struct watchdog_info adx_wdt_info = {
        .identity = "Avionic Design Xanthos Watchdog",
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
 };
index 937a80f..1e9caea 100644 (file)
@@ -180,7 +180,7 @@ static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_KEEPALIVEPING |
                                        WDIOF_SETTIMEOUT |
                                        WDIOF_MAGICCLOSE,
index f90afdb..d8d4da9 100644 (file)
@@ -238,7 +238,7 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
                                                        | WDIOF_MAGICCLOSE,
                .firmware_version = 1,
index 2bb95cd..c764c52 100644 (file)
@@ -219,7 +219,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data,
 static long ar7_wdt_ioctl(struct file *file,
                                        unsigned int cmd, unsigned long arg)
 {
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .identity = LONGNAME,
                .firmware_version = 1,
                .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
index 0378479..6873376 100644 (file)
@@ -202,7 +202,7 @@ static int at32_wdt_get_status(void)
        return status;
 }
 
-static struct watchdog_info at32_wdt_info = {
+static const struct watchdog_info at32_wdt_info = {
        .identity       = "at32ap700x watchdog",
        .options        = WDIOF_SETTIMEOUT |
                          WDIOF_KEEPALIVEPING |
index b185daf..b3046dc 100644 (file)
@@ -121,7 +121,7 @@ static int at91_wdt_settimeout(int new_time)
        return 0;
 }
 
-static struct watchdog_info at91_wdt_info = {
+static const struct watchdog_info at91_wdt_info = {
        .identity       = "at91 watchdog",
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
 };
index 751c003..5f24552 100644 (file)
@@ -149,7 +149,7 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
        return len;
 }
 
-static struct watchdog_info bcm47xx_wdt_info = {
+static const struct watchdog_info bcm47xx_wdt_info = {
        .identity       = DRV_NAME,
        .options        = WDIOF_SETTIMEOUT |
                                WDIOF_KEEPALIVEPING |
index 2159e66..9c7ccd1 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
@@ -74,7 +72,7 @@
 
 static unsigned int timeout = WATCHDOG_TIMEOUT;
 static int nowayout = WATCHDOG_NOWAYOUT;
-static struct watchdog_info bfin_wdt_info;
+static const struct watchdog_info bfin_wdt_info;
 static unsigned long open_check;
 static char expect_close;
 static DEFINE_SPINLOCK(bfin_wdt_spinlock);
@@ -309,26 +307,6 @@ static long bfin_wdt_ioctl(struct file *file,
        }
 }
 
-/**
- *     bfin_wdt_notify_sys - Notifier Handler
- *     @this: notifier block
- *     @code: notifier event
- *     @unused: unused
- *
- *     Handles specific events, such as turning off the watchdog during a
- *     shutdown event.
- */
-static int bfin_wdt_notify_sys(struct notifier_block *this,
-                                       unsigned long code, void *unused)
-{
-       stampit();
-
-       if (code == SYS_DOWN || code == SYS_HALT)
-               bfin_wdt_stop();
-
-       return NOTIFY_DONE;
-}
-
 #ifdef CONFIG_PM
 static int state_before_suspend;
 
@@ -388,40 +366,28 @@ static struct miscdevice bfin_wdt_miscdev = {
        .fops     = &bfin_wdt_fops,
 };
 
-static struct watchdog_info bfin_wdt_info = {
+static const struct watchdog_info bfin_wdt_info = {
        .identity = "Blackfin Watchdog",
        .options  = WDIOF_SETTIMEOUT |
                    WDIOF_KEEPALIVEPING |
                    WDIOF_MAGICCLOSE,
 };
 
-static struct notifier_block bfin_wdt_notifier = {
-       .notifier_call = bfin_wdt_notify_sys,
-};
-
 /**
  *     bfin_wdt_probe - Initialize module
  *
- *     Registers the misc device and notifier handler.  Actual device
+ *     Registers the misc device.  Actual device
  *     initialization is handled by bfin_wdt_open().
  */
 static int __devinit bfin_wdt_probe(struct platform_device *pdev)
 {
        int ret;
 
-       ret = register_reboot_notifier(&bfin_wdt_notifier);
-       if (ret) {
-               pr_devinit(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
-               return ret;
-       }
-
        ret = misc_register(&bfin_wdt_miscdev);
        if (ret) {
                pr_devinit(KERN_ERR PFX
                        "cannot register miscdev on minor=%d (err=%d)\n",
                                WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&bfin_wdt_notifier);
                return ret;
        }
 
@@ -434,21 +400,33 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
 /**
  *     bfin_wdt_remove - Initialize module
  *
- *     Unregisters the misc device and notifier handler.  Actual device
+ *     Unregisters the misc device.  Actual device
  *     deinitialization is handled by bfin_wdt_close().
  */
 static int __devexit bfin_wdt_remove(struct platform_device *pdev)
 {
        misc_deregister(&bfin_wdt_miscdev);
-       unregister_reboot_notifier(&bfin_wdt_notifier);
        return 0;
 }
 
+/**
+ *     bfin_wdt_shutdown - Soft Shutdown Handler
+ *
+ *     Handles the soft shutdown event.
+ */
+static void bfin_wdt_shutdown(struct platform_device *pdev)
+{
+       stampit();
+
+       bfin_wdt_stop();
+}
+
 static struct platform_device *bfin_wdt_device;
 
 static struct platform_driver bfin_wdt_driver = {
        .probe     = bfin_wdt_probe,
        .remove    = __devexit_p(bfin_wdt_remove),
+       .shutdown  = bfin_wdt_shutdown,
        .suspend   = bfin_wdt_suspend,
        .resume    = bfin_wdt_resume,
        .driver    = {
index e8380ef..8b724aa 100644 (file)
@@ -121,7 +121,7 @@ static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
        return count;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity = "PowerPC Book-E Watchdog",
 };
index 923cc68..9291506 100644 (file)
@@ -257,7 +257,7 @@ static long coh901327_ioctl(struct file *file, unsigned int cmd,
                struct watchdog_info __user *ident;
                int __user *i;
        } uarg;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options                = WDIOF_CARDRESET |
                                          WDIOF_SETTIMEOUT |
                                          WDIOF_KEEPALIVEPING,
index 71f6d7e..edd3475 100644 (file)
@@ -154,7 +154,7 @@ static long cpu5wdt_ioctl(struct file *file, unsigned int cmd,
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
        unsigned int value;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_CARDRESET,
                .identity = "CPU5 WDT",
        };
index 081f295..37ea052 100644 (file)
@@ -403,7 +403,7 @@ static int cpwd_release(struct inode *inode, struct file *file)
 
 static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       static struct watchdog_info info = {
+       static const struct watchdog_info info = {
                .options                = WDIOF_SETTIMEOUT,
                .firmware_version       = 1,
                .identity               = DRIVER_NAME,
index 887136d..56162c8 100644 (file)
@@ -142,7 +142,7 @@ davinci_wdt_write(struct file *file, const char *data, size_t len,
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_KEEPALIVEPING,
        .identity = "DaVinci Watchdog",
 };
index cdd55e0..88ed54e 100644 (file)
@@ -131,7 +131,7 @@ ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
        .identity = "EP93xx Watchdog",
 };
index 9add354..d1c4e55 100644 (file)
@@ -238,7 +238,7 @@ static long eurwdt_ioctl(struct file *file,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options          = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
                                                        | WDIOF_MAGICCLOSE,
                .firmware_version = 1,
index 734d980..abdbad0 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * GE Fanuc watchdog userspace interface
+ * GE watchdog userspace interface
  *
- * Author:  Martyn Welch <martyn.welch@gefanuc.com>
+ * Author:  Martyn Welch <martyn.welch@ge.com>
  *
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Copyright 2008 GE 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
@@ -161,11 +161,11 @@ static long gef_wdt_ioctl(struct file *file, unsigned int cmd,
        int timeout;
        int options;
        void __user *argp = (void __user *)arg;
-       static struct watchdog_info info = {
+       static const struct watchdog_info info = {
                .options =      WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
                                WDIOF_KEEPALIVEPING,
                .firmware_version = 0,
-               .identity = "GE Fanuc watchdog",
+               .identity = "GE watchdog",
        };
 
        switch (cmd) {
@@ -311,7 +311,7 @@ static struct of_platform_driver gef_wdt_driver = {
 
 static int __init gef_wdt_init(void)
 {
-       printk(KERN_INFO "GE Fanuc watchdog driver\n");
+       printk(KERN_INFO "GE watchdog driver\n");
        return of_register_platform_driver(&gef_wdt_driver);
 }
 
@@ -323,8 +323,8 @@ static void __exit gef_wdt_exit(void)
 module_init(gef_wdt_init);
 module_exit(gef_wdt_exit);
 
-MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>");
-MODULE_DESCRIPTION("GE Fanuc watchdog driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
+MODULE_DESCRIPTION("GE watchdog driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform: gef_wdt");
index 38252ff..9b49b12 100644 (file)
@@ -142,7 +142,7 @@ static long geodewdt_ioctl(struct file *file, unsigned int cmd,
        int __user *p = argp;
        int interval;
 
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
                | WDIOF_MAGICCLOSE,
                .firmware_version =     1,
index a6c5674..70c2c24 100644 (file)
@@ -554,7 +554,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data,
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT |
                   WDIOF_KEEPALIVEPING |
                   WDIOF_MAGICCLOSE,
index 7ba0b11..bb9750a 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
@@ -42,7 +41,7 @@
 #include <linux/io.h>
 
 /* Module and version information */
-#define ESB_VERSION "0.04"
+#define ESB_VERSION "0.05"
 #define ESB_MODULE_NAME "i6300ESB timer"
 #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
 #define PFX ESB_MODULE_NAME ": "
@@ -65,7 +64,7 @@
 /* Config register bits */
 #define ESB_WDT_REBOOT  (0x01 << 5)   /* Enable reboot on timeout          */
 #define ESB_WDT_FREQ    (0x01 << 2)   /* Decrement frequency               */
-#define ESB_WDT_INTTYPE (0x11 << 0)   /* Interrupt type on timer1 timeout  */
+#define ESB_WDT_INTTYPE (0x03 << 0)   /* Interrupt type on timer1 timeout  */
 
 /* Reload register bits */
 #define ESB_WDT_TIMEOUT (0x01 << 9)    /* Watchdog timed out                */
@@ -82,7 +81,9 @@ static unsigned long timer_alive;
 static struct pci_dev *esb_pci;
 static unsigned short triggered; /* The status of the watchdog upon boot */
 static char esb_expect_close;
-static struct platform_device *esb_platform_device;
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
 
 /* module parameters */
 /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */
@@ -111,8 +112,8 @@ MODULE_PARM_DESC(nowayout,
  */
 static inline void esb_unlock_registers(void)
 {
-       writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
-       writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+       writew(ESB_UNLOCK1, ESB_RELOAD_REG);
+       writew(ESB_UNLOCK2, ESB_RELOAD_REG);
 }
 
 static int esb_timer_start(void)
@@ -256,7 +257,7 @@ static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int new_heartbeat;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT |
                                        WDIOF_KEEPALIVEPING |
                                        WDIOF_MAGICCLOSE,
@@ -332,11 +333,6 @@ static struct miscdevice esb_miscdev = {
 
 /*
  * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
  */
 static struct pci_device_id esb_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
@@ -348,29 +344,19 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
  *      Init & exit routines
  */
 
-static unsigned char __devinit esb_getdevice(void)
+static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
 {
-       /*
-        *      Find the PCI device
-        */
-
-       esb_pci = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                       PCI_DEVICE_ID_INTEL_ESB_9, NULL);
-
-       if (!esb_pci)
-               return 0;
-
-       if (pci_enable_device(esb_pci)) {
+       if (pci_enable_device(pdev)) {
                printk(KERN_ERR PFX "failed to enable device\n");
                goto err_devput;
        }
 
-       if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+       if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
                printk(KERN_ERR PFX "failed to request region\n");
                goto err_disable;
        }
 
-       BASEADDR = pci_ioremap_bar(esb_pci, 0);
+       BASEADDR = pci_ioremap_bar(pdev, 0);
        if (BASEADDR == NULL) {
                /* Something's wrong here, BASEADDR has to be set */
                printk(KERN_ERR PFX "failed to get BASEADDR\n");
@@ -378,14 +364,14 @@ static unsigned char __devinit esb_getdevice(void)
        }
 
        /* Done */
+       esb_pci = pdev;
        return 1;
 
 err_release:
-       pci_release_region(esb_pci, 0);
+       pci_release_region(pdev, 0);
 err_disable:
-       pci_disable_device(esb_pci);
+       pci_disable_device(pdev);
 err_devput:
-       pci_dev_put(esb_pci);
        return 0;
 }
 
@@ -430,12 +416,23 @@ static void __devinit esb_initdevice(void)
        esb_timer_set_heartbeat(heartbeat);
 }
 
-static int __devinit esb_probe(struct platform_device *dev)
+static int __devinit esb_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
 {
        int ret;
 
+       cards_found++;
+       if (cards_found == 1)
+               printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
+                       ESB_VERSION);
+
+       if (cards_found > 1) {
+               printk(KERN_ERR PFX "This driver only supports 1 device\n");
+               return -ENODEV;
+       }
+
        /* Check whether or not the hardware watchdog is there */
-       if (!esb_getdevice() || esb_pci == NULL)
+       if (!esb_getdevice(pdev) || esb_pci == NULL)
                return -ENODEV;
 
        /* Check that the heartbeat value is within it's range;
@@ -467,11 +464,11 @@ err_unmap:
        iounmap(BASEADDR);
        pci_release_region(esb_pci, 0);
        pci_disable_device(esb_pci);
-       pci_dev_put(esb_pci);
+       esb_pci = NULL;
        return ret;
 }
 
-static int __devexit esb_remove(struct platform_device *dev)
+static void __devexit esb_remove(struct pci_dev *pdev)
 {
        /* Stop the timer before we leave */
        if (!nowayout)
@@ -482,54 +479,30 @@ static int __devexit esb_remove(struct platform_device *dev)
        iounmap(BASEADDR);
        pci_release_region(esb_pci, 0);
        pci_disable_device(esb_pci);
-       pci_dev_put(esb_pci);
-       return 0;
+       esb_pci = NULL;
 }
 
-static void esb_shutdown(struct platform_device *dev)
+static void esb_shutdown(struct pci_dev *pdev)
 {
        esb_timer_stop();
 }
 
-static struct platform_driver esb_platform_driver = {
+static struct pci_driver esb_driver = {
+       .name           = ESB_MODULE_NAME,
+       .id_table       = esb_pci_tbl,
        .probe          = esb_probe,
        .remove         = __devexit_p(esb_remove),
        .shutdown       = esb_shutdown,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = ESB_MODULE_NAME,
-       },
 };
 
 static int __init watchdog_init(void)
 {
-       int err;
-
-       printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
-               ESB_VERSION);
-
-       err = platform_driver_register(&esb_platform_driver);
-       if (err)
-               return err;
-
-       esb_platform_device = platform_device_register_simple(ESB_MODULE_NAME,
-                                                               -1, NULL, 0);
-       if (IS_ERR(esb_platform_device)) {
-               err = PTR_ERR(esb_platform_device);
-               goto unreg_platform_driver;
-       }
-
-       return 0;
-
-unreg_platform_driver:
-       platform_driver_unregister(&esb_platform_driver);
-       return err;
+       return pci_register_driver(&esb_driver);
 }
 
 static void __exit watchdog_cleanup(void)
 {
-       platform_device_unregister(esb_platform_device);
-       platform_driver_unregister(&esb_platform_driver);
+       pci_unregister_driver(&esb_driver);
        printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
 }
 
index 4bdb7f1..44bc6aa 100644 (file)
@@ -584,7 +584,7 @@ static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
        int new_heartbeat;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT |
                                        WDIOF_KEEPALIVEPING |
                                        WDIOF_MAGICCLOSE,
@@ -698,7 +698,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        if (iTCO_wdt_private.iTCO_version == 2) {
                pci_read_config_dword(pdev, 0xf0, &base_address);
                if ((base_address & 1) == 0) {
-                       printk(KERN_ERR PFX "RCBA is disabled by harddware\n");
+                       printk(KERN_ERR PFX "RCBA is disabled by hardware\n");
                        ret = -ENODEV;
                        goto out;
                }
@@ -708,8 +708,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
 
        /* Check chipset's NO_REBOOT bit */
        if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
-               printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
-                                       "reboot disabled by hardware\n");
+               printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
+                                       "platform may have disabled it\n");
                ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
                goto out_unmap;
        }
@@ -805,6 +805,7 @@ static void __devexit iTCO_wdt_cleanup(void)
 
 static int __devinit iTCO_wdt_probe(struct platform_device *dev)
 {
+       int ret = -ENODEV;
        int found = 0;
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *ent;
@@ -814,19 +815,17 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
        for_each_pci_dev(pdev) {
                ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
                if (ent) {
-                       if (!(iTCO_wdt_init(pdev, ent, dev))) {
-                               found++;
+                       found++;
+                       ret = iTCO_wdt_init(pdev, ent, dev);
+                       if (!ret)
                                break;
-                       }
                }
        }
 
-       if (!found) {
+       if (!found)
                printk(KERN_INFO PFX "No card detected\n");
-               return -ENODEV;
-       }
 
-       return 0;
+       return ret;
 }
 
 static int __devexit iTCO_wdt_remove(struct platform_device *dev)
index 4bef3dd..0149d8d 100644 (file)
@@ -174,7 +174,7 @@ static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
 
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
                                                        | WDIOF_MAGICCLOSE,
                .firmware_version = 1,
index bea8a12..1cc5609 100644 (file)
@@ -111,7 +111,7 @@ static long indydog_ioctl(struct file *file, unsigned int cmd,
                                                        unsigned long arg)
 {
        int options, retval = -EINVAL;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options                = WDIOF_KEEPALIVEPING,
                .firmware_version       = 0,
                .identity               = "Hardware Watchdog for SGI IP22",
index daed48d..f52c162 100644 (file)
@@ -236,7 +236,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .identity = "IT8712F Watchdog",
                .firmware_version = 1,
                .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
index cc133c5..b709b3b 100644 (file)
@@ -421,7 +421,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf,
        return count;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
        .firmware_version =     1,
        .identity = WATCHDOG_NAME,
index 3c79dc5..e86952a 100644 (file)
@@ -100,7 +100,7 @@ static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
 }
 
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
                                WDIOF_KEEPALIVEPING,
        .identity       = "IXP2000 Watchdog",
index 147b4d5..e02c0ec 100644 (file)
@@ -89,7 +89,7 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options        = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
                          WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity       = "IXP4xx Watchdog",
index e1c8276..2852bb2 100644 (file)
@@ -145,7 +145,7 @@ static int ks8695_wdt_close(struct inode *inode, struct file *file)
        return 0;
 }
 
-static struct watchdog_info ks8695_wdt_info = {
+static const struct watchdog_info ks8695_wdt_info = {
        .identity       = "ks8695 watchdog",
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
 };
index 47d7197..2d118cf 100644 (file)
@@ -101,7 +101,7 @@ MODULE_PARM_DESC(nowayout,
 
 #define PFX "machzwd"
 
-static struct watchdog_info zf_info = {
+static const struct watchdog_info zf_info = {
        .options                = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .firmware_version       = 1,
        .identity               = "ZF-Logic watchdog",
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
new file mode 100644 (file)
index 0000000..6eb91d7
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * drivers/char/watchdog/max63xx_wdt.c
+ *
+ * Driver for max63{69,70,71,72,73,74} watchdog timers
+ *
+ * Copyright (C) 2009 Marc Zyngier <maz@misterjones.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * This driver assumes the watchdog pins are memory mapped (as it is
+ * the case for the Arcom Zeus). Should it be connected over GPIOs or
+ * another interface, some abstraction will have to be introduced.
+ */
+
+#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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/device.h>
+
+#define DEFAULT_HEARTBEAT 60
+#define MAX_HEARTBEAT     60
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+static int nowayout  = WATCHDOG_NOWAYOUT;
+
+/*
+ * Memory mapping: a single byte, 3 first lower bits to select bit 3
+ * to ping the watchdog.
+ */
+#define MAX6369_WDSET  (7 << 0)
+#define MAX6369_WDI    (1 << 3)
+
+static DEFINE_SPINLOCK(io_lock);
+
+static unsigned long wdt_status;
+#define WDT_IN_USE     0
+#define WDT_RUNNING    1
+#define WDT_OK_TO_CLOSE 2
+
+static int nodelay;
+static struct resource *wdt_mem;
+static void __iomem    *wdt_base;
+static struct platform_device *max63xx_pdev;
+
+/*
+ * The timeout values used are actually the absolute minimum the chip
+ * offers. Typical values on my board are slightly over twice as long
+ * (10s setting ends up with a 25s timeout), and can be up to 3 times
+ * the nominal setting (according to the datasheet). So please take
+ * these values with a grain of salt. Same goes for the initial delay
+ * "feature". Only max6373/74 have a few settings without this initial
+ * delay (selected with the "nodelay" parameter).
+ *
+ * I also decided to remove from the tables any timeout smaller than a
+ * second, as it looked completly overkill...
+ */
+
+/* Timeouts in second */
+struct max63xx_timeout {
+       u8 wdset;
+       u8 tdelay;
+       u8 twd;
+};
+
+static struct max63xx_timeout max6369_table[] = {
+       { 5,  1,  1 },
+       { 6, 10, 10 },
+       { 7, 60, 60 },
+       { },
+};
+
+static struct max63xx_timeout max6371_table[] = {
+       { 6, 60,  3 },
+       { 7, 60, 60 },
+       { },
+};
+
+static struct max63xx_timeout max6373_table[] = {
+       { 2, 60,  1 },
+       { 5,  0,  1 },
+       { 1,  3,  3 },
+       { 7, 60, 10 },
+       { 6,  0, 10 },
+       { },
+};
+
+static struct max63xx_timeout *current_timeout;
+
+static struct max63xx_timeout *
+max63xx_select_timeout(struct max63xx_timeout *table, int value)
+{
+       while (table->twd) {
+               if (value <= table->twd) {
+                       if (nodelay && table->tdelay == 0)
+                               return table;
+
+                       if (!nodelay)
+                               return table;
+               }
+
+               table++;
+       }
+
+       return NULL;
+}
+
+static void max63xx_wdt_ping(void)
+{
+       u8 val;
+
+       spin_lock(&io_lock);
+
+       val = __raw_readb(wdt_base);
+
+       __raw_writeb(val | MAX6369_WDI, wdt_base);
+       __raw_writeb(val & ~MAX6369_WDI, wdt_base);
+
+       spin_unlock(&io_lock);
+}
+
+static void max63xx_wdt_enable(struct max63xx_timeout *entry)
+{
+       u8 val;
+
+       if (test_and_set_bit(WDT_RUNNING, &wdt_status))
+               return;
+
+       spin_lock(&io_lock);
+
+       val = __raw_readb(wdt_base);
+       val &= ~MAX6369_WDSET;
+       val |= entry->wdset;
+       __raw_writeb(val, wdt_base);
+
+       spin_unlock(&io_lock);
+
+       /* check for a edge triggered startup */
+       if (entry->tdelay == 0)
+               max63xx_wdt_ping();
+}
+
+static void max63xx_wdt_disable(void)
+{
+       spin_lock(&io_lock);
+
+       __raw_writeb(3, wdt_base);
+
+       spin_unlock(&io_lock);
+
+       clear_bit(WDT_RUNNING, &wdt_status);
+}
+
+static int max63xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       max63xx_wdt_enable(current_timeout);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t max63xx_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);
+                       }
+               }
+
+               max63xx_wdt_ping();
+       }
+
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .identity = "max63xx Watchdog",
+};
+
+static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       int ret = -ENOTTY;
+
+       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:
+               max63xx_wdt_ping();
+               ret = 0;
+               break;
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int max63xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               max63xx_wdt_disable();
+       else
+               dev_crit(&max63xx_pdev->dev,
+                        "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 max63xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = max63xx_wdt_write,
+       .unlocked_ioctl = max63xx_wdt_ioctl,
+       .open           = max63xx_wdt_open,
+       .release        = max63xx_wdt_release,
+};
+
+static struct miscdevice max63xx_wdt_miscdev = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &max63xx_wdt_fops,
+};
+
+static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       int size;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct max63xx_timeout *table;
+
+       table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
+
+       if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+               heartbeat = DEFAULT_HEARTBEAT;
+
+       dev_info(dev, "requesting %ds heartbeat\n", heartbeat);
+       current_timeout = max63xx_select_timeout(table, heartbeat);
+
+       if (!current_timeout) {
+               dev_err(dev, "unable to satisfy heartbeat request\n");
+               return -EINVAL;
+       }
+
+       dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
+                current_timeout->twd, current_timeout->tdelay);
+
+       heartbeat = current_timeout->twd;
+
+       max63xx_pdev = pdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "failed to get memory region resource\n");
+               return -ENOENT;
+       }
+
+       size = resource_size(res);
+       wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+       if (wdt_mem == NULL) {
+               dev_err(dev, "failed to get memory region\n");
+               return -ENOENT;
+       }
+
+       wdt_base = ioremap(res->start, size);
+       if (!wdt_base) {
+               dev_err(dev, "failed to map memory region\n");
+               ret = -ENOMEM;
+               goto out_request;
+       }
+
+       ret = misc_register(&max63xx_wdt_miscdev);
+       if (ret < 0) {
+               dev_err(dev, "cannot register misc device\n");
+               goto out_unmap;
+       }
+
+       return 0;
+
+out_unmap:
+       iounmap(wdt_base);
+out_request:
+       release_resource(wdt_mem);
+       kfree(wdt_mem);
+
+       return ret;
+}
+
+static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
+{
+       misc_deregister(&max63xx_wdt_miscdev);
+       if (wdt_mem) {
+               release_resource(wdt_mem);
+               kfree(wdt_mem);
+               wdt_mem = NULL;
+       }
+
+       if (wdt_base)
+               iounmap(wdt_base);
+
+       return 0;
+}
+
+static struct platform_device_id max63xx_id_table[] = {
+       { "max6369_wdt", (kernel_ulong_t)max6369_table, },
+       { "max6370_wdt", (kernel_ulong_t)max6369_table, },
+       { "max6371_wdt", (kernel_ulong_t)max6371_table, },
+       { "max6372_wdt", (kernel_ulong_t)max6371_table, },
+       { "max6373_wdt", (kernel_ulong_t)max6373_table, },
+       { "max6374_wdt", (kernel_ulong_t)max6373_table, },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, max63xx_id_table);
+
+static struct platform_driver max63xx_wdt_driver = {
+       .probe          = max63xx_wdt_probe,
+       .remove         = __devexit_p(max63xx_wdt_remove),
+       .id_table       = max63xx_id_table,
+       .driver         = {
+               .name   = "max63xx_wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init max63xx_wdt_init(void)
+{
+       return platform_driver_register(&max63xx_wdt_driver);
+}
+
+static void __exit max63xx_wdt_exit(void)
+{
+       platform_driver_unregister(&max63xx_wdt_driver);
+}
+
+module_init(max63xx_wdt_init);
+module_exit(max63xx_wdt_exit);
+
+MODULE_AUTHOR("Marc Zyngier <maz@misterjones.org>");
+MODULE_DESCRIPTION("max63xx Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+                "Watchdog heartbeat period in seconds from 1 to "
+                __MODULE_STRING(MAX_HEARTBEAT) ", default "
+                __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+module_param(nodelay, int, 0);
+MODULE_PARM_DESC(nodelay,
+                "Force selection of a timeout setting without initial delay "
+                "(max6373/74 only, default=0)");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 407b025..bc820d1 100644 (file)
@@ -201,7 +201,7 @@ static long mixcomwd_ioctl(struct file *file,
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
        int status;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
                .firmware_version = 1,
                .identity = "MixCOM watchdog",
index 38c588e..4e3941c 100644 (file)
@@ -148,7 +148,7 @@ static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING,
                .firmware_version = 1,
                .identity = "MPC8xxx",
index a2dc07c..b0646da 100644 (file)
@@ -213,7 +213,7 @@ static ssize_t mpcore_wdt_write(struct file *file, const char *data,
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options                = WDIOF_SETTIMEOUT |
                                  WDIOF_KEEPALIVEPING |
                                  WDIOF_MAGICCLOSE,
index a51dbe4..97f8a48 100644 (file)
@@ -179,7 +179,7 @@ static long mv64x60_wdt_ioctl(struct file *file,
        int timeout;
        int options;
        void __user *argp = (void __user *)arg;
-       static struct watchdog_info info = {
+       static const struct watchdog_info info = {
                .options =      WDIOF_SETTIMEOUT        |
                                WDIOF_MAGICCLOSE        |
                                WDIOF_KEEPALIVEPING,
index 1a2b916..d3aa2f1 100644 (file)
@@ -407,7 +407,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
                int __user *i;
        } uarg;
 
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options          = WDIOF_KEEPALIVEPING |
                                    WDIOF_SETTIMEOUT |
                                    WDIOF_MAGICCLOSE,
index aa95123..06f7922 100644 (file)
@@ -606,7 +606,7 @@ static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int temperature;
        int new_heartbeat;
        int __user *argp = (int __user *)arg;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_OVERHEAT |
                                        WDIOF_CARDRESET |
                                        WDIOF_KEEPALIVEPING |
index 698f51b..64374d6 100644 (file)
@@ -481,7 +481,7 @@ static long pcipcwd_ioctl(struct file *file, unsigned int cmd,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_OVERHEAT |
                                        WDIOF_CARDRESET |
                                        WDIOF_KEEPALIVEPING |
index 052fe45..8e4eacc 100644 (file)
@@ -404,7 +404,7 @@ static long usb_pcwd_ioctl(struct file *file, unsigned int cmd,
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_KEEPALIVEPING |
                                        WDIOF_SETTIMEOUT |
                                        WDIOF_MAGICCLOSE,
index 2d22e99..435ec2a 100644 (file)
@@ -52,7 +52,7 @@ static struct {
        struct timer_list timer;        /* The timer that pings the watchdog */
 } pikawdt_private;
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .identity       = DRV_NAME,
        .options        = WDIOF_CARDRESET |
                          WDIOF_SETTIMEOUT |
index 538ec2c..09102f0 100644 (file)
@@ -141,7 +141,7 @@ static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
        int options, new_timeout = 0;
        uint32_t timeout, timeout_left = 0;
 
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
                .firmware_version = 0,
                .identity = "Hardware Watchdog for PNX833x",
index bf12d06..d4c29b5 100644 (file)
@@ -198,7 +198,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
        void __user *argp = (void __user *)arg;
        int new_timeout;
        unsigned int value;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT |
                                        WDIOF_KEEPALIVEPING |
                                        WDIOF_MAGICCLOSE,
index 4976bfd..69c6adb 100644 (file)
@@ -149,7 +149,7 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
 {
        void __user *argp = (void __user *)arg;
        unsigned int value;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_CARDRESET,
                .identity = "RDC321x WDT",
        };
index c14ae86..ae57bf9 100644 (file)
@@ -85,7 +85,7 @@ static int riowd_release(struct inode *inode, struct file *filp)
 
 static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       static struct watchdog_info info = {
+       static const struct watchdog_info info = {
                .options                = WDIOF_SETTIMEOUT,
                .firmware_version       = 1,
                .identity               = DRIVER_NAME,
index e6763d2..8d44c9b 100644 (file)
@@ -111,7 +111,7 @@ out:
 }
 
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
                                WDIOF_KEEPALIVEPING,
        .identity       = WATCHDOG_NAME,
index 569eb29..9c40f48 100644 (file)
@@ -250,7 +250,7 @@ static long sch311x_wdt_ioctl(struct file *file, unsigned int cmd,
        int new_timeout;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
-       static struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options                = WDIOF_KEEPALIVEPING |
                                          WDIOF_SETTIMEOUT |
                                          WDIOF_MAGICCLOSE,
index 5dd9526..b3421fd 100644 (file)
@@ -94,7 +94,7 @@ static ssize_t stmp3xxx_wdt_write(struct file *file, const char __user *data,
        return len;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options        = WDIOF_CARDRESET |
                          WDIOF_MAGICCLOSE |
                          WDIOF_SETTIMEOUT |
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
new file mode 100644 (file)
index 0000000..565a2c3
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Watchdog driver for Technologic Systems TS-72xx based SBCs
+ * (TS-7200, TS-7250 and TS-7260). These boards have external
+ * glue logic CPLD chip, which includes programmable watchdog
+ * timer.
+ *
+ * Copyright (c) 2009 Mika Westerberg <mika.westerberg@iki.fi>
+ *
+ * This driver is based on ep93xx_wdt and wm831x_wdt drivers.
+ *
+ * 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/fs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+
+#define TS72XX_WDT_FEED_VAL            0x05
+#define TS72XX_WDT_DEFAULT_TIMEOUT     8
+
+static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
+                         "(1 <= timeout <= 8, default="
+                         __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
+                         ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+/**
+ * struct ts72xx_wdt - watchdog control structure
+ * @lock: lock that protects this structure
+ * @regval: watchdog timeout value suitable for control register
+ * @flags: flags controlling watchdog device state
+ * @control_reg: watchdog control register
+ * @feed_reg: watchdog feed register
+ * @pdev: back pointer to platform dev
+ */
+struct ts72xx_wdt {
+       struct mutex    lock;
+       int             regval;
+
+#define TS72XX_WDT_BUSY_FLAG           1
+#define TS72XX_WDT_EXPECT_CLOSE_FLAG   2
+       int             flags;
+
+       void __iomem    *control_reg;
+       void __iomem    *feed_reg;
+
+       struct platform_device *pdev;
+};
+
+struct platform_device *ts72xx_wdt_pdev;
+
+/*
+ * TS-72xx Watchdog supports following timeouts (value written
+ * to control register):
+ *     value   description
+ *     -------------------------
+ *     0x00    watchdog disabled
+ *     0x01    250ms
+ *     0x02    500ms
+ *     0x03    1s
+ *     0x04    reserved
+ *     0x05    2s
+ *     0x06    4s
+ *     0x07    8s
+ *
+ * Timeouts below 1s are not very usable so we don't
+ * allow them at all.
+ *
+ * We provide two functions that convert between these:
+ * timeout_to_regval() and regval_to_timeout().
+ */
+static const struct {
+       int     timeout;
+       int     regval;
+} ts72xx_wdt_map[] = {
+       { 1, 3 },
+       { 2, 5 },
+       { 4, 6 },
+       { 8, 7 },
+};
+
+/**
+ * timeout_to_regval() - converts given timeout to control register value
+ * @new_timeout: timeout in seconds to be converted
+ *
+ * Function converts given @new_timeout into valid value that can
+ * be programmed into watchdog control register. When conversion is
+ * not possible, function returns %-EINVAL.
+ */
+static int timeout_to_regval(int new_timeout)
+{
+       int i;
+
+       /* first limit it to 1 - 8 seconds */
+       new_timeout = clamp_val(new_timeout, 1, 8);
+
+       for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
+               if (ts72xx_wdt_map[i].timeout >= new_timeout)
+                       return ts72xx_wdt_map[i].regval;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * regval_to_timeout() - converts control register value to timeout
+ * @regval: control register value to be converted
+ *
+ * Function converts given @regval to timeout in seconds (1, 2, 4 or 8).
+ * If @regval cannot be converted, function returns %-EINVAL.
+ */
+static int regval_to_timeout(int regval)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
+               if (ts72xx_wdt_map[i].regval == regval)
+                       return ts72xx_wdt_map[i].timeout;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * ts72xx_wdt_kick() - kick the watchdog
+ * @wdt: watchdog to be kicked
+ *
+ * Called with @wdt->lock held.
+ */
+static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt)
+{
+       __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg);
+}
+
+/**
+ * ts72xx_wdt_start() - starts the watchdog timer
+ * @wdt: watchdog to be started
+ *
+ * This function programs timeout to watchdog timer
+ * and starts it.
+ *
+ * Called with @wdt->lock held.
+ */
+static void ts72xx_wdt_start(struct ts72xx_wdt *wdt)
+{
+       /*
+        * To program the wdt, it first must be "fed" and
+        * only after that (within 30 usecs) the configuration
+        * can be changed.
+        */
+       ts72xx_wdt_kick(wdt);
+       __raw_writeb((u8)wdt->regval, wdt->control_reg);
+}
+
+/**
+ * ts72xx_wdt_stop() - stops the watchdog timer
+ * @wdt: watchdog to be stopped
+ *
+ * Called with @wdt->lock held.
+ */
+static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt)
+{
+       ts72xx_wdt_kick(wdt);
+       __raw_writeb(0, wdt->control_reg);
+}
+
+static int ts72xx_wdt_open(struct inode *inode, struct file *file)
+{
+       struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev);
+       int regval;
+
+       /*
+        * Try to convert default timeout to valid register
+        * value first.
+        */
+       regval = timeout_to_regval(timeout);
+       if (regval < 0) {
+               dev_err(&wdt->pdev->dev,
+                       "failed to convert timeout (%d) to register value\n",
+                       timeout);
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&wdt->lock))
+               return -ERESTARTSYS;
+
+       if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) {
+               mutex_unlock(&wdt->lock);
+               return -EBUSY;
+       }
+
+       wdt->flags = TS72XX_WDT_BUSY_FLAG;
+       wdt->regval = regval;
+       file->private_data = wdt;
+
+       ts72xx_wdt_start(wdt);
+
+       mutex_unlock(&wdt->lock);
+       return nonseekable_open(inode, file);
+}
+
+static int ts72xx_wdt_release(struct inode *inode, struct file *file)
+{
+       struct ts72xx_wdt *wdt = file->private_data;
+
+       if (mutex_lock_interruptible(&wdt->lock))
+               return -ERESTARTSYS;
+
+       if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) {
+               ts72xx_wdt_stop(wdt);
+       } else {
+               dev_warn(&wdt->pdev->dev,
+                        "TS-72XX WDT device closed unexpectly. "
+                        "Watchdog timer will not stop!\n");
+               /*
+                * Kick it one more time, to give userland some time
+                * to recover (for example, respawning the kicker
+                * daemon).
+                */
+               ts72xx_wdt_kick(wdt);
+       }
+
+       wdt->flags = 0;
+
+       mutex_unlock(&wdt->lock);
+       return 0;
+}
+
+static ssize_t ts72xx_wdt_write(struct file *file,
+                               const char __user *data,
+                               size_t len,
+                               loff_t *ppos)
+{
+       struct ts72xx_wdt *wdt = file->private_data;
+
+       if (!len)
+               return 0;
+
+       if (mutex_lock_interruptible(&wdt->lock))
+               return -ERESTARTSYS;
+
+       ts72xx_wdt_kick(wdt);
+
+       /*
+        * Support for magic character closing. User process
+        * writes 'V' into the device, just before it is closed.
+        * This means that we know that the wdt timer can be
+        * stopped after user closes the device.
+        */
+       if (!nowayout) {
+               int i;
+
+               for (i = 0; i < len; i++) {
+                       char c;
+
+                       /* In case it was set long ago */
+                       wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG;
+
+                       if (get_user(c, data + i)) {
+                               mutex_unlock(&wdt->lock);
+                               return -EFAULT;
+                       }
+                       if (c == 'V') {
+                               wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG;
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&wdt->lock);
+       return len;
+}
+
+static const struct watchdog_info winfo = {
+       .options                = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+                                 WDIOF_MAGICCLOSE,
+       .firmware_version       = 1,
+       .identity               = "TS-72XX WDT",
+};
+
+static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       struct ts72xx_wdt *wdt = file->private_data;
+       void __user *argp = (void __user *)arg;
+       int __user *p = (int __user *)argp;
+       int error = 0;
+
+       if (mutex_lock_interruptible(&wdt->lock))
+               return -ERESTARTSYS;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               error = copy_to_user(argp, &winfo, sizeof(winfo));
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_KEEPALIVE:
+               ts72xx_wdt_kick(wdt);
+               break;
+
+       case WDIOC_SETOPTIONS: {
+               int options;
+
+               if (get_user(options, p)) {
+                       error = -EFAULT;
+                       break;
+               }
+
+               error = -EINVAL;
+
+               if ((options & WDIOS_DISABLECARD) != 0) {
+                       ts72xx_wdt_stop(wdt);
+                       error = 0;
+               }
+               if ((options & WDIOS_ENABLECARD) != 0) {
+                       ts72xx_wdt_start(wdt);
+                       error = 0;
+               }
+
+               break;
+       }
+
+       case WDIOC_SETTIMEOUT: {
+               int new_timeout;
+
+               if (get_user(new_timeout, p)) {
+                       error = -EFAULT;
+               } else {
+                       int regval;
+
+                       regval = timeout_to_regval(new_timeout);
+                       if (regval < 0) {
+                               error = -EINVAL;
+                       } else {
+                               ts72xx_wdt_stop(wdt);
+                               wdt->regval = regval;
+                               ts72xx_wdt_start(wdt);
+                       }
+               }
+               if (error)
+                       break;
+
+               /*FALLTHROUGH*/
+       }
+
+       case WDIOC_GETTIMEOUT:
+               if (put_user(regval_to_timeout(wdt->regval), p))
+                       error = -EFAULT;
+               break;
+
+       default:
+               error = -ENOTTY;
+               break;
+       }
+
+       mutex_unlock(&wdt->lock);
+       return error;
+}
+
+static const struct file_operations ts72xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .open           = ts72xx_wdt_open,
+       .release        = ts72xx_wdt_release,
+       .write          = ts72xx_wdt_write,
+       .unlocked_ioctl = ts72xx_wdt_ioctl,
+};
+
+static struct miscdevice ts72xx_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &ts72xx_wdt_fops,
+};
+
+static __devinit int ts72xx_wdt_probe(struct platform_device *pdev)
+{
+       struct ts72xx_wdt *wdt;
+       struct resource *r1, *r2;
+       int error = 0;
+
+       wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL);
+       if (!wdt) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r1) {
+               dev_err(&pdev->dev, "failed to get memory resource\n");
+               error = -ENODEV;
+               goto fail;
+       }
+
+       r1 = request_mem_region(r1->start, resource_size(r1), pdev->name);
+       if (!r1) {
+               dev_err(&pdev->dev, "cannot request memory region\n");
+               error = -EBUSY;
+               goto fail;
+       }
+
+       wdt->control_reg = ioremap(r1->start, resource_size(r1));
+       if (!wdt->control_reg) {
+               dev_err(&pdev->dev, "failed to map memory\n");
+               error = -ENODEV;
+               goto fail_free_control;
+       }
+
+       r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!r2) {
+               dev_err(&pdev->dev, "failed to get memory resource\n");
+               error = -ENODEV;
+               goto fail_unmap_control;
+       }
+
+       r2 = request_mem_region(r2->start, resource_size(r2), pdev->name);
+       if (!r2) {
+               dev_err(&pdev->dev, "cannot request memory region\n");
+               error = -EBUSY;
+               goto fail_unmap_control;
+       }
+
+       wdt->feed_reg = ioremap(r2->start, resource_size(r2));
+       if (!wdt->feed_reg) {
+               dev_err(&pdev->dev, "failed to map memory\n");
+               error = -ENODEV;
+               goto fail_free_feed;
+       }
+
+       platform_set_drvdata(pdev, wdt);
+       ts72xx_wdt_pdev = pdev;
+       wdt->pdev = pdev;
+       mutex_init(&wdt->lock);
+
+       error = misc_register(&ts72xx_wdt_miscdev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register miscdev\n");
+               goto fail_unmap_feed;
+       }
+
+       dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
+
+       return 0;
+
+fail_unmap_feed:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(wdt->feed_reg);
+fail_free_feed:
+       release_mem_region(r2->start, resource_size(r2));
+fail_unmap_control:
+       iounmap(wdt->control_reg);
+fail_free_control:
+       release_mem_region(r1->start, resource_size(r1));
+fail:
+       kfree(wdt);
+       return error;
+}
+
+static __devexit int ts72xx_wdt_remove(struct platform_device *pdev)
+{
+       struct ts72xx_wdt *wdt = platform_get_drvdata(pdev);
+       struct resource *res;
+       int error;
+
+       error = misc_deregister(&ts72xx_wdt_miscdev);
+       platform_set_drvdata(pdev, NULL);
+
+       iounmap(wdt->feed_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       release_mem_region(res->start, resource_size(res));
+
+       iounmap(wdt->control_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(wdt);
+       return error;
+}
+
+static struct platform_driver ts72xx_wdt_driver = {
+       .probe          = ts72xx_wdt_probe,
+       .remove         = __devexit_p(ts72xx_wdt_remove),
+       .driver         = {
+               .name   = "ts72xx-wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __init int ts72xx_wdt_init(void)
+{
+       return platform_driver_register(&ts72xx_wdt_driver);
+}
+module_init(ts72xx_wdt_init);
+
+static __exit void ts72xx_wdt_exit(void)
+{
+       platform_driver_unregister(&ts72xx_wdt_driver);
+}
+module_exit(ts72xx_wdt_exit);
+
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_DESCRIPTION("TS-72xx SBC Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ts72xx-wdt");
index d635566..9e9ed7b 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/fs.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/uaccess.h>
 #include <linux/platform_device.h>
@@ -166,14 +165,6 @@ static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
        }
 }
 
-static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
-       void *unused)
-{
-       if (code == SYS_DOWN || code == SYS_HALT)
-               txx9wdt_stop();
-       return NOTIFY_DONE;
-}
-
 static const struct file_operations txx9wdt_fops = {
        .owner          =       THIS_MODULE,
        .llseek         =       no_llseek,
@@ -189,10 +180,6 @@ static struct miscdevice txx9wdt_miscdev = {
        .fops   =       &txx9wdt_fops,
 };
 
-static struct notifier_block txx9wdt_notifier = {
-       .notifier_call = txx9wdt_notify_sys,
-};
-
 static int __init txx9wdt_probe(struct platform_device *dev)
 {
        struct resource *res;
@@ -221,13 +208,8 @@ static int __init txx9wdt_probe(struct platform_device *dev)
        if (!txx9wdt_reg)
                goto exit_busy;
 
-       ret = register_reboot_notifier(&txx9wdt_notifier);
-       if (ret)
-               goto exit;
-
        ret = misc_register(&txx9wdt_miscdev);
        if (ret) {
-               unregister_reboot_notifier(&txx9wdt_notifier);
                goto exit;
        }
 
@@ -249,14 +231,19 @@ exit:
 static int __exit txx9wdt_remove(struct platform_device *dev)
 {
        misc_deregister(&txx9wdt_miscdev);
-       unregister_reboot_notifier(&txx9wdt_notifier);
        clk_disable(txx9_imclk);
        clk_put(txx9_imclk);
        return 0;
 }
 
+static void txx9wdt_shutdown(struct platform_device *dev)
+{
+       txx9wdt_stop();
+}
+
 static struct platform_driver txx9wdt_driver = {
        .remove = __exit_p(txx9wdt_remove),
+       .shutdown = txx9wdt_shutdown,
        .driver = {
                .name = "txx9wdt",
                .owner = THIS_MODULE,
index f201acc..0f5288d 100644 (file)
@@ -201,7 +201,7 @@ 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 struct watchdog_info ident = {
+       static const struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
                                                        WDIOF_MAGICCLOSE,
                .firmware_version = 1,
index 0560182..6e6743d 100644 (file)
@@ -371,7 +371,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf,
  *      according to their available features.
  */
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
        .firmware_version =     1,
        .identity = WATCHDOG_NAME,
index 5bfb1f2..94ec22b 100644 (file)
@@ -312,7 +312,7 @@ static long wdrtas_ioctl(struct file *file, unsigned int cmd,
 {
        int __user *argp = (void __user *)arg;
        int i;
-       static struct watchdog_info wdinfo = {
+       static const struct watchdog_info wdinfo = {
                .options = WDRTAS_SUPPORTED_MASK,
                .firmware_version = 0,
                .identity = "wdrtas",
index 3bbefe9..bfda2e9 100644 (file)
@@ -358,7 +358,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int new_heartbeat;
        int status;
 
-       static struct watchdog_info ident = {
+       struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT|
                                        WDIOF_MAGICCLOSE|
                                        WDIOF_KEEPALIVEPING,
index f368dd8..7b22e3c 100644 (file)
@@ -412,7 +412,7 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
        int new_heartbeat;
        int status;
 
-       static struct watchdog_info ident = {
+       struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT|
                                        WDIOF_MAGICCLOSE|
                                        WDIOF_KEEPALIVEPING,
index 775bcd8..8c4b2d5 100644 (file)
@@ -213,7 +213,7 @@ static ssize_t wm831x_wdt_write(struct file *file,
        return count;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "WM831x Watchdog",
 };
index a2d2e8e..89dd7b0 100644 (file)
@@ -177,7 +177,7 @@ static ssize_t wm8350_wdt_write(struct file *file,
        return count;
 }
 
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "WM8350 Watchdog",
 };
index ae5cb05..bb71ab2 100644 (file)
@@ -426,7 +426,7 @@ static ssize_t hyp_sysfs_store(struct kobject *kobj,
        return 0;
 }
 
-static struct sysfs_ops hyp_sysfs_ops = {
+static const struct sysfs_ops hyp_sysfs_ops = {
        .show = hyp_sysfs_show,
        .store = hyp_sysfs_store,
 };
index 2b59201..0427183 100644 (file)
@@ -901,7 +901,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->highest_objectid = 0;
        root->name = NULL;
        root->in_sysfs = 0;
-       root->inode_tree.rb_node = NULL;
+       root->inode_tree = RB_ROOT;
 
        INIT_LIST_HEAD(&root->dirty_list);
        INIT_LIST_HEAD(&root->orphan_list);
@@ -1673,7 +1673,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        insert_inode_hash(fs_info->btree_inode);
 
        spin_lock_init(&fs_info->block_group_cache_lock);
-       fs_info->block_group_cache_tree.rb_node = NULL;
+       fs_info->block_group_cache_tree = RB_ROOT;
 
        extent_io_tree_init(&fs_info->freed_extents[0],
                             fs_info->btree_inode->i_mapping, GFP_NOFS);
index b177ed3..7073cbb 100644 (file)
@@ -104,8 +104,8 @@ void extent_io_exit(void)
 void extent_io_tree_init(struct extent_io_tree *tree,
                          struct address_space *mapping, gfp_t mask)
 {
-       tree->state.rb_node = NULL;
-       tree->buffer.rb_node = NULL;
+       tree->state = RB_ROOT;
+       tree->buffer = RB_ROOT;
        tree->ops = NULL;
        tree->dirty_bytes = 0;
        spin_lock_init(&tree->lock);
index 428fcac..28d87ba 100644 (file)
@@ -35,7 +35,7 @@ void extent_map_exit(void)
  */
 void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
 {
-       tree->map.rb_node = NULL;
+       tree->map = RB_ROOT;
        rwlock_init(&tree->lock);
 }
 
index cb2849f..dd831ed 100644 (file)
@@ -870,7 +870,7 @@ __btrfs_return_cluster_to_free_space(
                tree_insert_offset(&block_group->free_space_offset,
                                   entry->offset, &entry->offset_index, 0);
        }
-       cluster->root.rb_node = NULL;
+       cluster->root = RB_ROOT;
 
 out:
        spin_unlock(&cluster->lock);
@@ -1355,7 +1355,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
 {
        spin_lock_init(&cluster->lock);
        spin_lock_init(&cluster->refill_lock);
-       cluster->root.rb_node = NULL;
+       cluster->root = RB_ROOT;
        cluster->max_size = 0;
        cluster->points_to_bitmap = false;
        INIT_LIST_HEAD(&cluster->block_group_list);
index 1fe1282..9116c6d 100644 (file)
@@ -129,7 +129,7 @@ static inline void
 btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t)
 {
        mutex_init(&t->mutex);
-       t->tree.rb_node = NULL;
+       t->tree = RB_ROOT;
        t->last = NULL;
 }
 
index bc283ad..e2a55cb 100644 (file)
@@ -52,7 +52,7 @@ static inline size_t btrfs_leaf_ref_size(int nr_extents)
 
 static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree)
 {
-       tree->root.rb_node = NULL;
+       tree->root = RB_ROOT;
        INIT_LIST_HEAD(&tree->list);
        spin_lock_init(&tree->lock);
 }
index ab7ab53..0109e56 100644 (file)
@@ -170,14 +170,14 @@ struct async_merge {
 
 static void mapping_tree_init(struct mapping_tree *tree)
 {
-       tree->rb_root.rb_node = NULL;
+       tree->rb_root = RB_ROOT;
        spin_lock_init(&tree->lock);
 }
 
 static void backref_cache_init(struct backref_cache *cache)
 {
        int i;
-       cache->rb_root.rb_node = NULL;
+       cache->rb_root = RB_ROOT;
        for (i = 0; i < BTRFS_MAX_LEVEL; i++)
                INIT_LIST_HEAD(&cache->pending[i]);
        spin_lock_init(&cache->lock);
index 8a1ea6e..f8b4521 100644 (file)
@@ -128,7 +128,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
 {
        struct btrfs_fs_info *info = root->fs_info;
        substring_t args[MAX_OPT_ARGS];
-       char *p, *num;
+       char *p, *num, *orig;
        int intarg;
        int ret = 0;
 
@@ -143,6 +143,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
        if (!options)
                return -ENOMEM;
 
+       orig = options;
 
        while ((p = strsep(&options, ",")) != NULL) {
                int token;
@@ -280,7 +281,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                }
        }
 out:
-       kfree(options);
+       kfree(orig);
        return ret;
 }
 
index a240b6f..4ce16ef 100644 (file)
@@ -164,12 +164,12 @@ static void btrfs_root_release(struct kobject *kobj)
        complete(&root->kobj_unregister);
 }
 
-static struct sysfs_ops btrfs_super_attr_ops = {
+static const struct sysfs_ops btrfs_super_attr_ops = {
        .show   = btrfs_super_attr_show,
        .store  = btrfs_super_attr_store,
 };
 
-static struct sysfs_ops btrfs_root_attr_ops = {
+static const struct sysfs_ops btrfs_root_attr_ops = {
        .show   = btrfs_root_attr_show,
        .store  = btrfs_root_attr_store,
 };
index b2acc79..2a36e23 100644 (file)
@@ -69,7 +69,7 @@ static noinline int join_transaction(struct btrfs_root *root)
                cur_trans->commit_done = 0;
                cur_trans->start_time = get_seconds();
 
-               cur_trans->delayed_refs.root.rb_node = NULL;
+               cur_trans->delayed_refs.root = RB_ROOT;
                cur_trans->delayed_refs.num_entries = 0;
                cur_trans->delayed_refs.num_heads_ready = 0;
                cur_trans->delayed_refs.num_heads = 0;
index 6fa5302..bc3212e 100644 (file)
@@ -3265,7 +3265,7 @@ static void recalc_bh_state(void)
        
 struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
 {
-       struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
+       struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags);
        if (ret) {
                INIT_LIST_HEAD(&ret->b_assoc_buffers);
                get_cpu_var(bh_accounting).nr++;
@@ -3352,15 +3352,6 @@ int bh_submit_read(struct buffer_head *bh)
 }
 EXPORT_SYMBOL(bh_submit_read);
 
-static void
-init_buffer_head(void *data)
-{
-       struct buffer_head *bh = data;
-
-       memset(bh, 0, sizeof(*bh));
-       INIT_LIST_HEAD(&bh->b_assoc_buffers);
-}
-
 void __init buffer_init(void)
 {
        int nrpages;
@@ -3369,7 +3360,7 @@ void __init buffer_init(void)
                        sizeof(struct buffer_head), 0,
                                (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
                                SLAB_MEM_SPREAD),
-                               init_buffer_head);
+                               NULL);
 
        /*
         * Limit the bh occupancy to 10% of ZONE_NORMAL
index 00d90c2..030602d 100644 (file)
@@ -1795,6 +1795,24 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
        return ret;
 }
 
+struct compat_sel_arg_struct {
+       compat_ulong_t n;
+       compat_uptr_t inp;
+       compat_uptr_t outp;
+       compat_uptr_t exp;
+       compat_uptr_t tvp;
+};
+
+asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg)
+{
+       struct compat_sel_arg_struct a;
+
+       if (copy_from_user(&a, arg, sizeof(a)))
+               return -EFAULT;
+       return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
+                                compat_ptr(a.exp), compat_ptr(a.tvp));
+}
+
 #ifdef HAVE_SET_RESTORE_SIGMASK
 static long do_compat_pselect(int n, compat_ulong_t __user *inp,
        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
index 26a8bd4..f994a7d 100644 (file)
@@ -148,7 +148,7 @@ static void lockspace_kobj_release(struct kobject *k)
        kfree(ls);
 }
 
-static struct sysfs_ops dlm_attr_ops = {
+static const struct sysfs_ops dlm_attr_ops = {
        .show  = dlm_attr_show,
        .store = dlm_attr_store,
 };
index 2b83b96..ce84a6e 100644 (file)
@@ -2358,7 +2358,7 @@ static void ext4_sb_release(struct kobject *kobj)
 }
 
 
-static struct sysfs_ops ext4_attr_ops = {
+static const struct sysfs_ops ext4_attr_ops = {
        .show   = ext4_attr_show,
        .store  = ext4_attr_store,
 };
index 864dac2..cc94bb9 100644 (file)
@@ -1,7 +1,6 @@
 
 config FSCACHE
        tristate "General filesystem local caching manager"
-       depends on EXPERIMENTAL
        select SLOW_WORK
        help
          This option enables a generic filesystem caching manager that can be
index b5f1a46..419042f 100644 (file)
@@ -49,7 +49,7 @@ static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
        return a->store ? a->store(sdp, buf, len) : len;
 }
 
-static struct sysfs_ops gfs2_attr_ops = {
+static const struct sysfs_ops gfs2_attr_ops = {
        .show  = gfs2_attr_show,
        .store = gfs2_attr_store,
 };
@@ -574,7 +574,7 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
        return 0;
 }
 
-static struct kset_uevent_ops gfs2_uevent_ops = {
+static const struct kset_uevent_ops gfs2_uevent_ops = {
        .uevent = gfs2_uevent,
 };
 
index b39da87..3bb928a 100644 (file)
@@ -136,7 +136,7 @@ static ssize_t mlog_store(struct kobject *obj, struct attribute *attr,
        return mlog_mask_store(mlog_attr->mask, buf, count);
 }
 
-static struct sysfs_ops mlog_attr_ops = {
+static const struct sysfs_ops mlog_attr_ops = {
        .show  = mlog_show,
        .store = mlog_store,
 };
index d8d0c65..73e743e 100644 (file)
@@ -72,9 +72,9 @@
 
 #include "tcp_internal.h"
 
-#define SC_NODEF_FMT "node %s (num %u) at %u.%u.%u.%u:%u"
+#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u"
 #define SC_NODEF_ARGS(sc) sc->sc_node->nd_name, sc->sc_node->nd_num,   \
-                         NIPQUAD(sc->sc_node->nd_ipv4_address),        \
+                         &sc->sc_node->nd_ipv4_address,                \
                          ntohs(sc->sc_node->nd_ipv4_port)
 
 /*
index 73715e9..500a669 100644 (file)
@@ -691,6 +691,23 @@ SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
 }
 #endif /* HAVE_SET_RESTORE_SIGMASK */
 
+#ifdef __ARCH_WANT_SYS_OLD_SELECT
+struct sel_arg_struct {
+       unsigned long n;
+       fd_set __user *inp, *outp, *exp;
+       struct timeval __user *tvp;
+};
+
+SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg)
+{
+       struct sel_arg_struct a;
+
+       if (copy_from_user(&a, arg, sizeof(a)))
+               return -EFAULT;
+       return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+#endif
+
 struct poll_list {
        struct poll_list *next;
        int len;
index a0a500a..e9d2935 100644 (file)
@@ -54,14 +54,14 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
        int rc;
 
        /* need attr_sd for attr, its parent for kobj */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        rc = -EIO;
        if (attr->read)
                rc = attr->read(kobj, attr, buffer, off, count);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 
        return rc;
 }
@@ -125,14 +125,14 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
        int rc;
 
        /* need attr_sd for attr, its parent for kobj */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        rc = -EIO;
        if (attr->write)
                rc = attr->write(kobj, attr, buffer, offset, count);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 
        return rc;
 }
@@ -184,12 +184,12 @@ static void bin_vma_open(struct vm_area_struct *vma)
        if (!bb->vm_ops || !bb->vm_ops->open)
                return;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return;
 
        bb->vm_ops->open(vma);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 }
 
 static void bin_vma_close(struct vm_area_struct *vma)
@@ -201,12 +201,12 @@ static void bin_vma_close(struct vm_area_struct *vma)
        if (!bb->vm_ops || !bb->vm_ops->close)
                return;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return;
 
        bb->vm_ops->close(vma);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 }
 
 static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -219,12 +219,12 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (!bb->vm_ops || !bb->vm_ops->fault)
                return VM_FAULT_SIGBUS;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return VM_FAULT_SIGBUS;
 
        ret = bb->vm_ops->fault(vma, vmf);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return ret;
 }
 
@@ -241,12 +241,12 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (!bb->vm_ops->page_mkwrite)
                return 0;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return VM_FAULT_SIGBUS;
 
        ret = bb->vm_ops->page_mkwrite(vma, vmf);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return ret;
 }
 
@@ -261,12 +261,12 @@ static int bin_access(struct vm_area_struct *vma, unsigned long addr,
        if (!bb->vm_ops || !bb->vm_ops->access)
                return -EINVAL;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -EINVAL;
 
        ret = bb->vm_ops->access(vma, addr, buf, len, write);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return ret;
 }
 
@@ -281,12 +281,12 @@ static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
        if (!bb->vm_ops || !bb->vm_ops->set_policy)
                return 0;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -EINVAL;
 
        ret = bb->vm_ops->set_policy(vma, new);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return ret;
 }
 
@@ -301,12 +301,12 @@ static struct mempolicy *bin_get_policy(struct vm_area_struct *vma,
        if (!bb->vm_ops || !bb->vm_ops->get_policy)
                return vma->vm_policy;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return vma->vm_policy;
 
        pol = bb->vm_ops->get_policy(vma, addr);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return pol;
 }
 
@@ -321,12 +321,12 @@ static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from,
        if (!bb->vm_ops || !bb->vm_ops->migrate)
                return 0;
 
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return 0;
 
        ret = bb->vm_ops->migrate(vma, from, to, flags);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return ret;
 }
 #endif
@@ -356,7 +356,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
 
        /* need attr_sd for attr, its parent for kobj */
        rc = -ENODEV;
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                goto out_unlock;
 
        rc = -EINVAL;
@@ -384,7 +384,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
        bb->vm_ops = vma->vm_ops;
        vma->vm_ops = &bin_vm_ops;
 out_put:
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 out_unlock:
        mutex_unlock(&bb->mutex);
 
@@ -399,7 +399,7 @@ static int open(struct inode * inode, struct file * file)
        int error;
 
        /* binary file operations requires both @sd and its parent */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        error = -EACCES;
@@ -426,11 +426,11 @@ static int open(struct inode * inode, struct file * file)
        mutex_unlock(&sysfs_bin_lock);
 
        /* open succeeded, put active references */
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return 0;
 
  err_out:
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        kfree(bb);
        return error;
 }
index 699f371..5907178 100644 (file)
@@ -93,7 +93,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
  *     RETURNS:
  *     Pointer to @sd on success, NULL on failure.
  */
-static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
 {
        if (unlikely(!sd))
                return NULL;
@@ -124,7 +124,7 @@ static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
  *     Put an active reference to @sd.  This function is noop if @sd
  *     is NULL.
  */
-static void sysfs_put_active(struct sysfs_dirent *sd)
+void sysfs_put_active(struct sysfs_dirent *sd)
 {
        struct completion *cmpl;
        int v;
@@ -144,45 +144,6 @@ static void sysfs_put_active(struct sysfs_dirent *sd)
        complete(cmpl);
 }
 
-/**
- *     sysfs_get_active_two - get active references to sysfs_dirent and parent
- *     @sd: sysfs_dirent of interest
- *
- *     Get active reference to @sd and its parent.  Parent's active
- *     reference is grabbed first.  This function is noop if @sd is
- *     NULL.
- *
- *     RETURNS:
- *     Pointer to @sd on success, NULL on failure.
- */
-struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd)
-{
-       if (sd) {
-               if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent)))
-                       return NULL;
-               if (unlikely(!sysfs_get_active(sd))) {
-                       sysfs_put_active(sd->s_parent);
-                       return NULL;
-               }
-       }
-       return sd;
-}
-
-/**
- *     sysfs_put_active_two - put active references to sysfs_dirent and parent
- *     @sd: sysfs_dirent of interest
- *
- *     Put active references to @sd and its parent.  This function is
- *     noop if @sd is NULL.
- */
-void sysfs_put_active_two(struct sysfs_dirent *sd)
-{
-       if (sd) {
-               sysfs_put_active(sd);
-               sysfs_put_active(sd->s_parent);
-       }
-}
-
 /**
  *     sysfs_deactivate - deactivate sysfs_dirent
  *     @sd: sysfs_dirent to deactivate
@@ -195,6 +156,10 @@ static void sysfs_deactivate(struct sysfs_dirent *sd)
        int v;
 
        BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED));
+
+       if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF))
+               return;
+
        sd->s_sibling = (void *)&wait;
 
        rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_);
@@ -354,7 +319,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
 
        atomic_set(&sd->s_count, 1);
        atomic_set(&sd->s_active, 0);
-       sysfs_dirent_init_lockdep(sd);
 
        sd->s_name = name;
        sd->s_mode = mode;
@@ -681,7 +645,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
        }
 
        /* attach dentry and inode */
-       inode = sysfs_get_inode(sd);
+       inode = sysfs_get_inode(dir->i_sb, sd);
        if (!inode) {
                ret = ERR_PTR(-ENOMEM);
                goto out_unlock;
@@ -837,11 +801,46 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd)
        return (sd->s_mode >> 12) & 15;
 }
 
+static int sysfs_dir_release(struct inode *inode, struct file *filp)
+{
+       sysfs_put(filp->private_data);
+       return 0;
+}
+
+static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd,
+       ino_t ino, struct sysfs_dirent *pos)
+{
+       if (pos) {
+               int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
+                       pos->s_parent == parent_sd &&
+                       ino == pos->s_ino;
+               sysfs_put(pos);
+               if (valid)
+                       return pos;
+       }
+       pos = NULL;
+       if ((ino > 1) && (ino < INT_MAX)) {
+               pos = parent_sd->s_dir.children;
+               while (pos && (ino > pos->s_ino))
+                       pos = pos->s_sibling;
+       }
+       return pos;
+}
+
+static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd,
+       ino_t ino, struct sysfs_dirent *pos)
+{
+       pos = sysfs_dir_pos(parent_sd, ino, pos);
+       if (pos)
+               pos = pos->s_sibling;
+       return pos;
+}
+
 static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-       struct sysfs_dirent *pos;
+       struct sysfs_dirent *pos = filp->private_data;
        ino_t ino;
 
        if (filp->f_pos == 0) {
@@ -857,29 +856,31 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
                if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
                        filp->f_pos++;
        }
-       if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {
-               mutex_lock(&sysfs_mutex);
-
-               /* Skip the dentries we have already reported */
-               pos = parent_sd->s_dir.children;
-               while (pos && (filp->f_pos > pos->s_ino))
-                       pos = pos->s_sibling;
-
-               for ( ; pos; pos = pos->s_sibling) {
-                       const char * name;
-                       int len;
-
-                       name = pos->s_name;
-                       len = strlen(name);
-                       filp->f_pos = ino = pos->s_ino;
+       mutex_lock(&sysfs_mutex);
+       for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos);
+            pos;
+            pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) {
+               const char * name;
+               unsigned int type;
+               int len, ret;
+
+               name = pos->s_name;
+               len = strlen(name);
+               ino = pos->s_ino;
+               type = dt_type(pos);
+               filp->f_pos = ino;
+               filp->private_data = sysfs_get(pos);
 
-                       if (filldir(dirent, name, len, filp->f_pos, ino,
-                                        dt_type(pos)) < 0)
-                               break;
-               }
-               if (!pos)
-                       filp->f_pos = INT_MAX;
                mutex_unlock(&sysfs_mutex);
+               ret = filldir(dirent, name, len, filp->f_pos, ino, type);
+               mutex_lock(&sysfs_mutex);
+               if (ret < 0)
+                       break;
+       }
+       mutex_unlock(&sysfs_mutex);
+       if ((filp->f_pos > 1) && !pos) { /* EOF */
+               filp->f_pos = INT_MAX;
+               filp->private_data = NULL;
        }
        return 0;
 }
@@ -888,5 +889,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 const struct file_operations sysfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = sysfs_readdir,
+       .release        = sysfs_dir_release,
        .llseek         = generic_file_llseek,
 };
index dc30d9e..e222b25 100644 (file)
@@ -53,7 +53,7 @@ struct sysfs_buffer {
        size_t                  count;
        loff_t                  pos;
        char                    * page;
-       struct sysfs_ops        * ops;
+       const struct sysfs_ops  * ops;
        struct mutex            mutex;
        int                     needs_read_fill;
        int                     event;
@@ -75,7 +75,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
-       struct sysfs_ops * ops = buffer->ops;
+       const struct sysfs_ops * ops = buffer->ops;
        int ret = 0;
        ssize_t count;
 
@@ -85,13 +85,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
                return -ENOMEM;
 
        /* need attr_sd for attr and ops, its parent for kobj */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        buffer->event = atomic_read(&attr_sd->s_attr.open->event);
        count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 
        /*
         * The code works fine with PAGE_SIZE return but it's likely to
@@ -199,16 +199,16 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
-       struct sysfs_ops * ops = buffer->ops;
+       const struct sysfs_ops * ops = buffer->ops;
        int rc;
 
        /* need attr_sd for attr and ops, its parent for kobj */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 
        return rc;
 }
@@ -335,7 +335,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        struct sysfs_buffer *buffer;
-       struct sysfs_ops *ops;
+       const struct sysfs_ops *ops;
        int error = -EACCES;
        char *p;
 
@@ -344,7 +344,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
                memmove(last_sysfs_file, p, strlen(p) + 1);
 
        /* need attr_sd for attr and ops, its parent for kobj */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                return -ENODEV;
 
        /* every kobject with an attribute needs a ktype assigned */
@@ -393,13 +393,13 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
                goto err_free;
 
        /* open succeeded, put active references */
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return 0;
 
  err_free:
        kfree(buffer);
  err_out:
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
        return error;
 }
 
@@ -437,12 +437,12 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
        struct sysfs_open_dirent *od = attr_sd->s_attr.open;
 
        /* need parent for the kobj, grab both */
-       if (!sysfs_get_active_two(attr_sd))
+       if (!sysfs_get_active(attr_sd))
                goto trigger;
 
        poll_wait(filp, &od->poll, wait);
 
-       sysfs_put_active_two(attr_sd);
+       sysfs_put_active(attr_sd);
 
        if (buffer->event != atomic_read(&od->event))
                goto trigger;
@@ -509,6 +509,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
        if (!sd)
                return -ENOMEM;
        sd->s_attr.attr = (void *)attr;
+       sysfs_dirent_init_lockdep(sd);
 
        sysfs_addrm_start(&acxt, dir_sd);
        rc = sysfs_add_one(&acxt, sd);
@@ -542,6 +543,18 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
 
 }
 
+int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
+{
+       int err = 0;
+       int i;
+
+       for (i = 0; ptr[i] && !err; i++)
+               err = sysfs_create_file(kobj, ptr[i]);
+       if (err)
+               while (--i >= 0)
+                       sysfs_remove_file(kobj, ptr[i]);
+       return err;
+}
 
 /**
  * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
@@ -614,6 +627,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
        sysfs_hash_and_remove(kobj->sd, attr->name);
 }
 
+void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
+{
+       int i;
+       for (i = 0; ptr[i]; i++)
+               sysfs_remove_file(kobj, ptr[i]);
+}
 
 /**
  * sysfs_remove_file_from_group - remove an attribute file from a group.
@@ -732,3 +751,5 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
 
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
+EXPORT_SYMBOL_GPL(sysfs_remove_files);
+EXPORT_SYMBOL_GPL(sysfs_create_files);
index 6a06a1d..082daae 100644 (file)
@@ -111,20 +111,20 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
        if (!sd)
                return -EINVAL;
 
+       mutex_lock(&sysfs_mutex);
        error = inode_change_ok(inode, iattr);
        if (error)
-               return error;
+               goto out;
 
        iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
 
        error = inode_setattr(inode, iattr);
        if (error)
-               return error;
+               goto out;
 
-       mutex_lock(&sysfs_mutex);
        error = sysfs_sd_setattr(sd, iattr);
+out:
        mutex_unlock(&sysfs_mutex);
-
        return error;
 }
 
@@ -283,6 +283,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 
 /**
  *     sysfs_get_inode - get inode for sysfs_dirent
+ *     @sb: super block
  *     @sd: sysfs_dirent to allocate inode for
  *
  *     Get inode for @sd.  If such inode doesn't exist, a new inode
@@ -295,11 +296,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
  *     RETURNS:
  *     Pointer to allocated inode on success, NULL on failure.
  */
-struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
+struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
 {
        struct inode *inode;
 
-       inode = iget_locked(sysfs_sb, sd->s_ino);
+       inode = iget_locked(sb, sd->s_ino);
        if (inode && (inode->i_state & I_NEW))
                sysfs_init_inode(sd, inode);
 
index 4974995..0cb1088 100644 (file)
@@ -23,7 +23,6 @@
 
 
 static struct vfsmount *sysfs_mount;
-struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
@@ -50,11 +49,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = SYSFS_MAGIC;
        sb->s_op = &sysfs_ops;
        sb->s_time_gran = 1;
-       sysfs_sb = sb;
 
        /* get root inode, initialize and unlock it */
        mutex_lock(&sysfs_mutex);
-       inode = sysfs_get_inode(&sysfs_root);
+       inode = sysfs_get_inode(sb, &sysfs_root);
        mutex_unlock(&sysfs_mutex);
        if (!inode) {
                pr_debug("sysfs: could not get root inode\n");
index c5eff49..1b9a3a1 100644 (file)
@@ -123,6 +123,44 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
        sysfs_hash_and_remove(parent_sd, name);
 }
 
+/**
+ *     sysfs_rename_link - rename symlink in object's directory.
+ *     @kobj:  object we're acting for.
+ *     @targ:  object we're pointing to.
+ *     @old:   previous name of the symlink.
+ *     @new:   new name of the symlink.
+ *
+ *     A helper function for the common rename symlink idiom.
+ */
+int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
+                       const char *old, const char *new)
+{
+       struct sysfs_dirent *parent_sd, *sd = NULL;
+       int result;
+
+       if (!kobj)
+               parent_sd = &sysfs_root;
+       else
+               parent_sd = kobj->sd;
+
+       result = -ENOENT;
+       sd = sysfs_get_dirent(parent_sd, old);
+       if (!sd)
+               goto out;
+
+       result = -EINVAL;
+       if (sysfs_type(sd) != SYSFS_KOBJ_LINK)
+               goto out;
+       if (sd->s_symlink.target_sd->s_dir.kobj != targ)
+               goto out;
+
+       result = sysfs_rename(sd, parent_sd, new);
+
+out:
+       sysfs_put(sd);
+       return result;
+}
+
 static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
                                 struct sysfs_dirent *target_sd, char *path)
 {
index cdd9377..30f5a44 100644 (file)
@@ -66,8 +66,8 @@ struct sysfs_dirent {
        };
 
        unsigned int            s_flags;
+       unsigned short          s_mode;
        ino_t                   s_ino;
-       umode_t                 s_mode;
        struct sysfs_inode_attrs *s_iattr;
 };
 
@@ -79,6 +79,7 @@ struct sysfs_dirent {
 #define SYSFS_KOBJ_BIN_ATTR            0x0004
 #define SYSFS_KOBJ_LINK                        0x0008
 #define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)
+#define SYSFS_ACTIVE_REF               (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
 
 #define SYSFS_FLAG_MASK                        ~SYSFS_TYPE_MASK
 #define SYSFS_FLAG_REMOVED             0x0200
@@ -91,9 +92,12 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 #define sysfs_dirent_init_lockdep(sd)                          \
 do {                                                           \
-       static struct lock_class_key __key;                     \
+       struct attribute *attr = sd->s_attr.attr;               \
+       struct lock_class_key *key = attr->key;                 \
+       if (!key)                                               \
+               key = &attr->skey;                              \
                                                                \
-       lockdep_init_map(&sd->dep_map, "s_active", &__key, 0);  \
+       lockdep_init_map(&sd->dep_map, "s_active", key, 0);     \
 } while(0)
 #else
 #define sysfs_dirent_init_lockdep(sd) do {} while(0)
@@ -111,7 +115,6 @@ struct sysfs_addrm_cxt {
  * mount.c
  */
 extern struct sysfs_dirent sysfs_root;
-extern struct super_block *sysfs_sb;
 extern struct kmem_cache *sysfs_dir_cachep;
 
 /*
@@ -124,8 +127,8 @@ extern const struct file_operations sysfs_dir_operations;
 extern const struct inode_operations sysfs_dir_inode_operations;
 
 struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
-struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
-void sysfs_put_active_two(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
+void sysfs_put_active(struct sysfs_dirent *sd);
 void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
                       struct sysfs_dirent *parent_sd);
 int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
@@ -168,7 +171,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
 /*
  * inode.c
  */
-struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
+struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd);
 void sysfs_delete_inode(struct inode *inode);
 int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
 int sysfs_permission(struct inode *inode, int mask);
index 66b63a7..14743d9 100644 (file)
@@ -1016,6 +1016,9 @@ magic_found:
                case UFS_FSSTABLE:
                        UFSD("fs is stable\n");
                        break;
+               case UFS_FSLOG:
+                       UFSD("fs is logging fs\n");
+                       break;
                case UFS_FSOSF1:
                        UFSD("fs is DEC OSF/1\n");
                        break;
index 54bde18..6943ec6 100644 (file)
@@ -138,6 +138,7 @@ typedef __u16 __bitwise __fs16;
 
 #define UFS_USEEFT  ((__u16)65535)
 
+/* fs_clean values */
 #define UFS_FSOK      0x7c269d38
 #define UFS_FSACTIVE  ((__s8)0x00)
 #define UFS_FSCLEAN   ((__s8)0x01)
@@ -145,6 +146,11 @@ typedef __u16 __bitwise __fs16;
 #define UFS_FSOSF1    ((__s8)0x03)     /* is this correct for DEC OSF/1? */
 #define UFS_FSBAD     ((__s8)0xff)
 
+/* Solaris-specific fs_clean values */
+#define UFS_FSSUSPEND ((__s8)0xfe)     /* temporarily suspended */
+#define UFS_FSLOG     ((__s8)0xfd)     /* logging fs */
+#define UFS_FSFIX     ((__s8)0xfc)     /* being repaired while mounted */
+
 /* From here to next blank line, s_flags for ufs_sb_info */
 /* directory entry encoding */
 #define UFS_DE_MASK            0x00000010      /* mask for the following */
@@ -227,11 +233,16 @@ typedef __u16 __bitwise __fs16;
  */
 #define ufs_cbtocylno(bno) \
        ((bno) * uspi->s_nspf / uspi->s_spc)
-#define ufs_cbtorpos(bno) \
+#define ufs_cbtorpos(bno)                                    \
+       ((UFS_SB(sb)->s_flags & UFS_CG_SUN) ?                 \
+        (((((bno) * uspi->s_nspf % uspi->s_spc) %            \
+           uspi->s_nsect) *                                  \
+          uspi->s_nrpos) / uspi->s_nsect)                    \
+        :                                                    \
        ((((bno) * uspi->s_nspf % uspi->s_spc / uspi->s_nsect \
        * uspi->s_trackskew + (bno) * uspi->s_nspf % uspi->s_spc \
        % uspi->s_nsect * uspi->s_interleave) % uspi->s_nsect \
-       * uspi->s_nrpos) / uspi->s_npsect)
+         * uspi->s_nrpos) / uspi->s_npsect))
 
 /*
  * The following macros optimize certain frequently calculated
index 37b3706..1437b7d 100644 (file)
@@ -6,9 +6,6 @@
 
 #include <linux/dma-mapping.h>
 
-/* note pci_set_dma_mask isn't here, since it's a public function
- * exported from drivers/pci, use dma_supported instead */
-
 static inline int
 pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
@@ -104,4 +101,16 @@ pci_dma_mapping_error(struct pci_dev *pdev, dma_addr_t dma_addr)
        return dma_mapping_error(&pdev->dev, dma_addr);
 }
 
+#ifdef CONFIG_PCI
+static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return dma_set_mask(&dev->dev, mask);
+}
+
+static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return dma_set_coherent_mask(&dev->dev, mask);
+}
+#endif
+
 #endif
index 882dc72..3e4737f 100644 (file)
@@ -121,16 +121,15 @@ struct vfsmount;
 struct super_block;
 struct pacct_struct;
 struct pid_namespace;
+extern int acct_parm[]; /* for sysctl */
 extern void acct_auto_close_mnt(struct vfsmount *m);
 extern void acct_auto_close(struct super_block *sb);
-extern void acct_init_pacct(struct pacct_struct *pacct);
 extern void acct_collect(long exitcode, int group_dead);
 extern void acct_process(void);
 extern void acct_exit_ns(struct pid_namespace *);
 #else
 #define acct_auto_close_mnt(x) do { } while (0)
 #define acct_auto_close(x)     do { } while (0)
-#define acct_init_pacct(x)     do { } while (0)
 #define acct_collect(x,y)      do { } while (0)
 #define acct_process()         do { } while (0)
 #define acct_exit_ns(ns)       do { } while (0)
index c9bbcb2..b8ad1ea 100644 (file)
@@ -37,16 +37,24 @@ extern void cgroup_post_fork(struct task_struct *p);
 extern void cgroup_exit(struct task_struct *p, int run_callbacks);
 extern int cgroupstats_build(struct cgroupstats *stats,
                                struct dentry *dentry);
+extern int cgroup_load_subsys(struct cgroup_subsys *ss);
+extern void cgroup_unload_subsys(struct cgroup_subsys *ss);
 
 extern const struct file_operations proc_cgroup_operations;
 
-/* Define the enumeration of all cgroup subsystems */
+/* Define the enumeration of all builtin cgroup subsystems */
 #define SUBSYS(_x) _x ## _subsys_id,
 enum cgroup_subsys_id {
 #include <linux/cgroup_subsys.h>
-       CGROUP_SUBSYS_COUNT
+       CGROUP_BUILTIN_SUBSYS_COUNT
 };
 #undef SUBSYS
+/*
+ * This define indicates the maximum number of subsystems that can be loaded
+ * at once. We limit to this many since cgroupfs_root has subsys_bits to keep
+ * track of all of them.
+ */
+#define CGROUP_SUBSYS_COUNT (BITS_PER_BYTE*sizeof(unsigned long))
 
 /* Per-subsystem/per-cgroup state maintained by the system. */
 struct cgroup_subsys_state {
@@ -76,6 +84,12 @@ enum {
        CSS_REMOVED, /* This CSS is dead */
 };
 
+/* Caller must verify that the css is not for root cgroup */
+static inline void __css_get(struct cgroup_subsys_state *css, int count)
+{
+       atomic_add(count, &css->refcnt);
+}
+
 /*
  * Call css_get() to hold a reference on the css; it can be used
  * for a reference obtained via:
@@ -87,7 +101,7 @@ static inline void css_get(struct cgroup_subsys_state *css)
 {
        /* We don't need to reference count the root state */
        if (!test_bit(CSS_ROOT, &css->flags))
-               atomic_inc(&css->refcnt);
+               __css_get(css, 1);
 }
 
 static inline bool css_is_removed(struct cgroup_subsys_state *css)
@@ -118,11 +132,11 @@ static inline bool css_tryget(struct cgroup_subsys_state *css)
  * css_get() or css_tryget()
  */
 
-extern void __css_put(struct cgroup_subsys_state *css);
+extern void __css_put(struct cgroup_subsys_state *css, int count);
 static inline void css_put(struct cgroup_subsys_state *css)
 {
        if (!test_bit(CSS_ROOT, &css->flags))
-               __css_put(css);
+               __css_put(css, 1);
 }
 
 /* bits in struct cgroup flags field */
@@ -221,6 +235,10 @@ struct cgroup {
 
        /* For RCU-protected deletion */
        struct rcu_head rcu_head;
+
+       /* List of events which userspace want to recieve */
+       struct list_head event_list;
+       spinlock_t event_list_lock;
 };
 
 /*
@@ -258,7 +276,8 @@ struct css_set {
        /*
         * Set of subsystem states, one for each subsystem. This array
         * is immutable after creation apart from the init_css_set
-        * during subsystem registration (at boot time).
+        * during subsystem registration (at boot time) and modular subsystem
+        * loading/unloading.
         */
        struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
 
@@ -363,6 +382,23 @@ struct cftype {
        int (*trigger)(struct cgroup *cgrp, unsigned int event);
 
        int (*release)(struct inode *inode, struct file *file);
+
+       /*
+        * register_event() callback will be used to add new userspace
+        * waiter for changes related to the cftype. Implement it if
+        * you want to provide this functionality. Use eventfd_signal()
+        * on eventfd to send notification to userspace.
+        */
+       int (*register_event)(struct cgroup *cgrp, struct cftype *cft,
+                       struct eventfd_ctx *eventfd, const char *args);
+       /*
+        * unregister_event() callback will be called when userspace
+        * closes the eventfd or on cgroup removing.
+        * This callback must be implemented, if you want provide
+        * notification functionality.
+        */
+       int (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
+                       struct eventfd_ctx *eventfd);
 };
 
 struct cgroup_scanner {
@@ -428,6 +464,8 @@ struct cgroup_subsys {
        void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
                          struct task_struct *tsk, bool threadgroup);
+       void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
+                         struct task_struct *tsk, bool threadgroup);
        void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
                        struct cgroup *old_cgrp, struct task_struct *tsk,
                        bool threadgroup);
@@ -472,6 +510,9 @@ struct cgroup_subsys {
        /* used when use_id == true */
        struct idr idr;
        spinlock_t id_lock;
+
+       /* should be defined only by modular subsystems */
+       struct module *module;
 };
 
 #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
index ef68119..717c691 100644 (file)
@@ -23,6 +23,7 @@
 typedef __compat_uid32_t       compat_uid_t;
 typedef __compat_gid32_t       compat_gid_t;
 
+struct compat_sel_arg_struct;
 struct rusage;
 
 struct compat_itimerspec { 
@@ -249,6 +250,8 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
                compat_ulong_t __user *outp, compat_ulong_t __user *exp,
                struct compat_timeval __user *tvp);
 
+asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg);
+
 asmlinkage long compat_sys_wait4(compat_pid_t pid,
                                 compat_uint_t __user *stat_addr, int options,
                                 struct compat_rusage __user *ru);
index b3c91d7..8ba66a9 100644 (file)
@@ -16,6 +16,8 @@ static inline int dump_write(struct file *file, const void *addr, int nr)
 
 static inline int dump_seek(struct file *file, loff_t off)
 {
+       int ret = 1;
+
        if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
                if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
                        return 0;
@@ -29,13 +31,15 @@ static inline int dump_seek(struct file *file, loff_t off)
 
                        if (n > PAGE_SIZE)
                                n = PAGE_SIZE;
-                       if (!dump_write(file, buf, n))
-                               return 0;
+                       if (!dump_write(file, buf, n)) {
+                               ret = 0;
+                               break;
+                       }
                        off -= n;
                }
                free_page((unsigned long)buf);
        }
-       return 1;
+       return ret;
 }
 
 #endif /* _LINUX_COREDUMP_H */
index 5032b9a..ad5ec1d 100644 (file)
 
 /* Code active when included from pre-boot environment: */
 
+/*
+ * Some architectures want to ensure there is no local data in their
+ * pre-boot environment, so that data can arbitarily relocated (via
+ * GOT references).  This is achieved by defining STATIC_RW_DATA to
+ * be null.
+ */
+#ifndef STATIC_RW_DATA
+#define STATIC_RW_DATA static
+#endif
+
 /* A trivial malloc implementation, adapted from
  *  malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
  */
-static unsigned long malloc_ptr;
-static int malloc_count;
+STATIC_RW_DATA unsigned long malloc_ptr;
+STATIC_RW_DATA int malloc_count;
 
 static void *malloc(int size)
 {
index b30527d..1821928 100644 (file)
@@ -106,7 +106,7 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 
 /* All 4 notifers below get called with the target struct device *
  * as an argument. Note that those functions are likely to be called
- * with the device semaphore held in the core, so be careful.
+ * with the device lock held in the core, so be careful.
  */
 #define BUS_NOTIFY_ADD_DEVICE          0x00000001 /* device added */
 #define BUS_NOTIFY_DEL_DEVICE          0x00000002 /* device removed */
@@ -251,8 +251,10 @@ extern struct device *class_find_device(struct class *class,
 
 struct class_attribute {
        struct attribute attr;
-       ssize_t (*show)(struct class *class, char *buf);
-       ssize_t (*store)(struct class *class, const char *buf, size_t count);
+       ssize_t (*show)(struct class *class, struct class_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct class *class, struct class_attribute *attr,
+                       const char *buf, size_t count);
 };
 
 #define CLASS_ATTR(_name, _mode, _show, _store)                        \
@@ -263,6 +265,23 @@ extern int __must_check class_create_file(struct class *class,
 extern void class_remove_file(struct class *class,
                              const struct class_attribute *attr);
 
+/* Simple class attribute that is just a static string */
+
+struct class_attribute_string {
+       struct class_attribute attr;
+       char *str;
+};
+
+/* Currently read-only only */
+#define _CLASS_ATTR_STRING(_name, _mode, _str) \
+       { __ATTR(_name, _mode, show_class_attr_string, NULL), _str }
+#define CLASS_ATTR_STRING(_name, _mode, _str) \
+       struct class_attribute_string class_attr_##_name = \
+               _CLASS_ATTR_STRING(_name, _mode, _str)
+
+extern ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr,
+                        char *buf);
+
 struct class_interface {
        struct list_head        node;
        struct class            *class;
@@ -489,6 +508,21 @@ static inline bool device_async_suspend_enabled(struct device *dev)
        return !!dev->power.async_suspend;
 }
 
+static inline void device_lock(struct device *dev)
+{
+       down(&dev->sem);
+}
+
+static inline int device_trylock(struct device *dev)
+{
+       return down_trylock(&dev->sem);
+}
+
+static inline void device_unlock(struct device *dev)
+{
+       up(&dev->sem);
+}
+
 void driver_init(void);
 
 /*
index 91b7618..ca32ed7 100644 (file)
@@ -127,6 +127,14 @@ static inline u64 dma_get_mask(struct device *dev)
        return DMA_BIT_MASK(32);
 }
 
+static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+       if (!dma_supported(dev, mask))
+               return -EIO;
+       dev->coherent_dma_mask = mask;
+       return 0;
+}
+
 extern u64 dma_get_required_mask(struct device *dev);
 
 static inline unsigned int dma_get_max_seg_size(struct device *dev)
@@ -232,4 +240,20 @@ struct dma_attrs;
 
 #endif /* CONFIG_HAVE_DMA_ATTRS */
 
+#ifdef CONFIG_NEED_DMA_MAP_STATE
+#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME)        dma_addr_t ADDR_NAME
+#define DEFINE_DMA_UNMAP_LEN(LEN_NAME)          __u32 LEN_NAME
+#define dma_unmap_addr(PTR, ADDR_NAME)           ((PTR)->ADDR_NAME)
+#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL)  (((PTR)->ADDR_NAME) = (VAL))
+#define dma_unmap_len(PTR, LEN_NAME)             ((PTR)->LEN_NAME)
+#define dma_unmap_len_set(PTR, LEN_NAME, VAL)    (((PTR)->LEN_NAME) = (VAL))
+#else
+#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME)
+#define DEFINE_DMA_UNMAP_LEN(LEN_NAME)
+#define dma_unmap_addr(PTR, ADDR_NAME)           (0)
+#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL)  do { } while (0)
+#define dma_unmap_len(PTR, LEN_NAME)             (0)
+#define dma_unmap_len_set(PTR, LEN_NAME, VAL)    do { } while (0)
+#endif
+
 #endif
index abec69b..b1ed1cd 100644 (file)
@@ -32,14 +32,6 @@ extern struct fs_struct init_fs;
 }
 
 extern struct nsproxy init_nsproxy;
-#define INIT_NSPROXY(nsproxy) {                                                \
-       .pid_ns         = &init_pid_ns,                                 \
-       .count          = ATOMIC_INIT(1),                               \
-       .uts_ns         = &init_uts_ns,                                 \
-       .mnt_ns         = NULL,                                         \
-       INIT_NET_NS(net_ns)                                             \
-       INIT_IPC_NS(ipc_ns)                                             \
-}
 
 #define INIT_SIGHAND(sighand) {                                                \
        .count          = ATOMIC_INIT(1),                               \
index 1195a80..a0bb301 100644 (file)
@@ -42,7 +42,7 @@ struct io_context {
        unsigned short ioprio;
        unsigned short ioprio_changed;
 
-#ifdef CONFIG_BLK_CGROUP
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
        unsigned short cgroup_changed;
 #endif
 
index 07baa38..5195298 100644 (file)
@@ -62,11 +62,6 @@ extern struct ipc_namespace init_ipc_ns;
 extern atomic_t nr_ipc_ns;
 
 extern spinlock_t mq_lock;
-#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
-#define INIT_IPC_NS(ns)                .ns             = &init_ipc_ns,
-#else
-#define INIT_IPC_NS(ns)
-#endif
 
 #ifdef CONFIG_SYSVIPC
 extern int register_ipcns_notifier(struct ipc_namespace *);
index f7c9c75..4b48318 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/ipmi_smi.h>
 
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
index 384ca8b..facb27f 100644 (file)
@@ -27,6 +27,7 @@
 #define KMOD_PATH_LEN 256
 
 #ifdef CONFIG_MODULES
+extern char modprobe_path[]; /* for sysctl */
 /* modprobe exit status on success, -ve on error.  Return value
  * usually useless though. */
 extern int __request_module(bool wait, const char *name, ...) \
index 58ae8e0..3950d3c 100644 (file)
@@ -106,7 +106,7 @@ extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
 
 struct kobj_type {
        void (*release)(struct kobject *kobj);
-       struct sysfs_ops *sysfs_ops;
+       const struct sysfs_ops *sysfs_ops;
        struct attribute **default_attrs;
 };
 
@@ -118,9 +118,9 @@ struct kobj_uevent_env {
 };
 
 struct kset_uevent_ops {
-       int (*filter)(struct kset *kset, struct kobject *kobj);
-       const char *(*name)(struct kset *kset, struct kobject *kobj);
-       int (*uevent)(struct kset *kset, struct kobject *kobj,
+       int (* const filter)(struct kset *kset, struct kobject *kobj);
+       const char *(* const name)(struct kset *kset, struct kobject *kobj);
+       int (* const uevent)(struct kset *kset, struct kobject *kobj,
                      struct kobj_uevent_env *env);
 };
 
@@ -132,7 +132,7 @@ struct kobj_attribute {
                         const char *buf, size_t count);
 };
 
-extern struct sysfs_ops kobj_sysfs_ops;
+extern const struct sysfs_ops kobj_sysfs_ops;
 
 /**
  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
@@ -155,14 +155,14 @@ struct kset {
        struct list_head list;
        spinlock_t list_lock;
        struct kobject kobj;
-       struct kset_uevent_ops *uevent_ops;
+       const struct kset_uevent_ops *uevent_ops;
 };
 
 extern void kset_init(struct kset *kset);
 extern int __must_check kset_register(struct kset *kset);
 extern void kset_unregister(struct kset *kset);
 extern struct kset * __must_check kset_create_and_add(const char *name,
-                                               struct kset_uevent_ops *u,
+                                               const struct kset_uevent_ops *u,
                                                struct kobject *parent_kobj);
 
 static inline struct kset *to_kset(struct kobject *kobj)
index 10206a8..a03977a 100644 (file)
 struct task_struct;
 struct lockdep_map;
 
+/* for sysctl */
+extern int prove_locking;
+extern int lock_stat;
+
 #ifdef CONFIG_LOCKDEP
 
 #include <linux/linkage.h>
index 1f9b119..44301c6 100644 (file)
@@ -124,7 +124,6 @@ static inline bool mem_cgroup_disabled(void)
        return false;
 }
 
-extern bool mem_cgroup_oom_called(struct task_struct *task);
 void mem_cgroup_update_file_mapped(struct page *page, int val);
 unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                                                gfp_t gfp_mask, int nid,
@@ -258,11 +257,6 @@ static inline bool mem_cgroup_disabled(void)
        return true;
 }
 
-static inline bool mem_cgroup_oom_called(struct task_struct *task)
-{
-       return false;
-}
-
 static inline int
 mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
 {
index 3899395..e70f21b 100644 (file)
@@ -971,7 +971,13 @@ static inline void setmax_mm_hiwater_rss(unsigned long *maxrss,
                *maxrss = hiwater_rss;
 }
 
+#if defined(SPLIT_RSS_COUNTING)
 void sync_mm_rss(struct task_struct *task, struct mm_struct *mm);
+#else
+static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
+{
+}
+#endif
 
 /*
  * A callback you can register to apply pressure to ageable caches.
@@ -1459,5 +1465,7 @@ extern void shake_page(struct page *p, int access);
 extern atomic_long_t mce_bad_pages;
 extern int soft_offline_page(struct page *page, int flags);
 
+extern void dump_page(struct page *page);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 048b462..b8bb9a6 100644 (file)
@@ -203,7 +203,7 @@ enum {
        NR_MM_COUNTERS
 };
 
-#if USE_SPLIT_PTLOCKS
+#if USE_SPLIT_PTLOCKS && defined(CONFIG_MMU)
 #define SPLIT_RSS_COUNTING
 struct mm_rss_stat {
        atomic_long_t count[NR_MM_COUNTERS];
index dd618eb..5e869ff 100644 (file)
@@ -175,6 +175,7 @@ struct notifier_block;
 
 #ifdef CONFIG_MODULES
 
+extern int modules_disabled; /* for sysctl */
 /* Get/put a kernel symbol (calls must be symmetric) */
 void *__symbol_get(const char *symbol);
 void *__symbol_get_gpl(const char *symbol);
index c4fa64b..dba35e4 100644 (file)
@@ -483,7 +483,7 @@ static inline int num_node_state(enum node_states state)
                        type *name = kmalloc(sizeof(*name), gfp_flags)
 #define NODEMASK_FREE(m)                       kfree(m)
 #else
-#define NODEMASK_ALLOC(type, name, gfp_flags)  type _name, *name = &_name
+#define NODEMASK_ALLOC(type, name, gfp_flags)  type _##name, *name = &_##name
 #define NODEMASK_FREE(m)                       do {} while (0)
 #endif
 
index b0e4eb1..30b0813 100644 (file)
@@ -118,6 +118,8 @@ static inline void __init page_cgroup_init_flatmem(void)
 #include <linux/swap.h>
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
+extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
+                                       unsigned short old, unsigned short new);
 extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
 extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
diff --git a/include/linux/pci-dma.h b/include/linux/pci-dma.h
new file mode 100644 (file)
index 0000000..549a041
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _LINUX_PCI_DMA_H
+#define _LINUX_PCI_DMA_H
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) DEFINE_DMA_UNMAP_ADDR(ADDR_NAME);
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)   DEFINE_DMA_UNMAP_LEN(LEN_NAME);
+#define pci_unmap_addr             dma_unmap_addr
+#define pci_unmap_addr_set         dma_unmap_addr_set
+#define pci_unmap_len              dma_unmap_len
+#define pci_unmap_len_set          dma_unmap_len_set
+
+#endif
index cd5809a..a788fa1 100644 (file)
@@ -769,8 +769,6 @@ int pci_try_set_mwi(struct pci_dev *dev);
 void pci_clear_mwi(struct pci_dev *dev);
 void pci_intx(struct pci_dev *dev, int enable);
 void pci_msi_off(struct pci_dev *dev);
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
 int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
 int pcix_get_max_mmrbc(struct pci_dev *dev);
@@ -904,6 +902,7 @@ int pci_set_vga_state(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, bool change_bridge);
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
+#include <linux/pci-dma.h>
 #include <linux/dmapool.h>
 
 #define        pci_pool dma_pool
index 71ff887..212da17 100644 (file)
@@ -21,7 +21,7 @@ struct platform_device {
        u32             num_resources;
        struct resource * resource;
 
-       struct platform_device_id       *id_entry;
+       const struct platform_device_id *id_entry;
 
        /* arch specific additions */
        struct pdev_archdata    archdata;
@@ -62,7 +62,7 @@ struct platform_driver {
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*resume)(struct platform_device *);
        struct device_driver driver;
-       struct platform_device_id *id_table;
+       const struct platform_device_id *id_table;
 };
 
 extern int platform_driver_register(struct platform_driver *);
@@ -77,6 +77,11 @@ extern int platform_driver_probe(struct platform_driver *driver,
 #define platform_get_drvdata(_dev)     dev_get_drvdata(&(_dev)->dev)
 #define platform_set_drvdata(_dev,data)        dev_set_drvdata(&(_dev)->dev, (data))
 
+extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
+                                       int (*probe)(struct platform_device *),
+                                       struct resource *res, unsigned int n_res,
+                                       const void *data, size_t size);
+
 /* early platform driver interface */
 struct early_platform_driver {
        const char *class_str;
index 6673743..600cc1f 100644 (file)
 #include <linux/wait.h>
 #include <linux/string.h>
 #include <linux/fs.h>
+#include <linux/sysctl.h>
 #include <asm/uaccess.h>
 
+extern struct ctl_table epoll_table[]; /* for sysctl */
 /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating
    additional memory. */
 #define MAX_STACK_ALLOC 832
index c5eab89..e1fb607 100644 (file)
@@ -264,6 +264,9 @@ static inline void user_enable_single_step(struct task_struct *task)
 static inline void user_disable_single_step(struct task_struct *task)
 {
 }
+#else
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
 #endif /* arch_has_single_step */
 
 #ifndef arch_has_block_step
@@ -291,6 +294,8 @@ static inline void user_enable_block_step(struct task_struct *task)
 {
        BUG();                  /* This can never be called.  */
 }
+#else
+extern void user_enable_block_step(struct task_struct *);
 #endif /* arch_has_block_step */
 
 #ifdef ARCH_HAS_USER_SINGLE_STEP_INFO
index c843736..a005cac 100644 (file)
 #include <linux/lockdep.h>
 #include <linux/completion.h>
 
+#ifdef CONFIG_RCU_TORTURE_TEST
+extern int rcutorture_runnable; /* for sysctl */
+#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
+
 /**
  * struct rcu_head - callback structure for use with RCU
  * @next: next update requests in a list
index 988e55f..3005d5a 100644 (file)
@@ -64,6 +64,7 @@ extern void kernel_restart(char *cmd);
 extern void kernel_halt(void);
 extern void kernel_power_off(void);
 
+extern int C_A_D; /* for sysctl */
 void ctrl_alt_del(void);
 
 #define POWEROFF_CMD_PATH_LEN  256
index 60f88a7..14dbc83 100644 (file)
@@ -238,6 +238,12 @@ static inline bool is_leap_year(unsigned int year)
        return (!(year % 4) && (year % 100)) || !(year % 400);
 }
 
+#ifdef CONFIG_RTC_HCTOSYS
+extern int rtc_hctosys_ret;
+#else
+#define rtc_hctosys_ret -ENODEV
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_RTC_H_ */
index 281d8fd..8d522ff 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/plist.h>
 #include <linux/spinlock_types.h>
 
+extern int max_lock_depth; /* for sysctl */
+
 /**
  * The rt_mutex structure
  *
index 46c6f8d..ca635c1 100644 (file)
@@ -2391,9 +2391,7 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times);
 
 static inline void thread_group_cputime_init(struct signal_struct *sig)
 {
-       sig->cputimer.cputime = INIT_CPUTIME;
        spin_lock_init(&sig->cputimer.lock);
-       sig->cputimer.running = 0;
 }
 
 static inline void thread_group_cputime_free(struct signal_struct *sig)
index 8c3dd36..78dd1e7 100644 (file)
@@ -491,9 +491,13 @@ uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
 {
        struct uart_state *state = uport->state;
        struct tty_port *port = &state->port;
+       struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
+       struct timespec ts;
 
-       uport->icount.dcd++;
+       if (ld && ld->ops->dcd_change)
+               getnstimeofday(&ts);
 
+       uport->icount.dcd++;
 #ifdef CONFIG_HARD_PPS
        if ((uport->flags & UPF_HARDPPS_CD) && status)
                hardpps();
@@ -505,6 +509,11 @@ uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
                else if (port->tty)
                        tty_hangup(port->tty);
        }
+
+       if (ld && ld->ops->dcd_change)
+               ld->ops->dcd_change(port->tty, status, &ts);
+       if (ld)
+               tty_ldisc_deref(ld);
 }
 
 /**
index ab9272c..fcd2b14 100644 (file)
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <linux/list.h>
 
+/* for sysctl */
+extern int print_fatal_signals;
 /*
  * Real Time signals may be queued.
  */
index a2602a8..1f59d93 100644 (file)
@@ -355,6 +355,7 @@ static inline void disable_swap_token(void)
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 extern void
 mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
+extern int mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep);
 #else
 static inline void
 mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
@@ -485,6 +486,14 @@ mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
 {
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+static inline int
+mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep)
+{
+       return 0;
+}
+#endif
+
 #endif /* CONFIG_SWAP */
 #endif /* __KERNEL__*/
 #endif /* _LINUX_SWAP_H */
index 8126f23..44f2ad0 100644 (file)
@@ -23,6 +23,7 @@ struct kexec_segment;
 struct linux_dirent;
 struct linux_dirent64;
 struct list_head;
+struct mmap_arg_struct;
 struct msgbuf;
 struct msghdr;
 struct mmsghdr;
@@ -30,10 +31,13 @@ struct msqid_ds;
 struct new_utsname;
 struct nfsctl_arg;
 struct __old_kernel_stat;
+struct oldold_utsname;
+struct old_utsname;
 struct pollfd;
 struct rlimit;
 struct rusage;
 struct sched_param;
+struct sel_arg_struct;
 struct semaphore;
 struct sembuf;
 struct shmid_ds;
@@ -638,6 +642,7 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                                long timeout);
 asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
                        fd_set __user *exp, struct timeval __user *tvp);
+asmlinkage long sys_old_select(struct sel_arg_struct __user *arg);
 asmlinkage long sys_epoll_create(int size);
 asmlinkage long sys_epoll_create1(int flags);
 asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
@@ -652,6 +657,8 @@ asmlinkage long sys_gethostname(char __user *name, int len);
 asmlinkage long sys_sethostname(char __user *name, int len);
 asmlinkage long sys_setdomainname(char __user *name, int len);
 asmlinkage long sys_newuname(struct new_utsname __user *name);
+asmlinkage long sys_uname(struct old_utsname __user *);
+asmlinkage long sys_olduname(struct oldold_utsname __user *);
 
 asmlinkage long sys_getrlimit(unsigned int resource,
                                struct rlimit __user *rlim);
@@ -681,6 +688,8 @@ asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg);
 asmlinkage long sys_shmget(key_t key, size_t size, int flag);
 asmlinkage long sys_shmdt(char __user *shmaddr);
 asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
+asmlinkage long sys_ipc(unsigned int call, int first, int second,
+               unsigned long third, void __user *ptr, long fifth);
 
 asmlinkage long sys_mq_open(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr);
 asmlinkage long sys_mq_unlink(const char __user *name);
@@ -836,4 +845,6 @@ asmlinkage long sys_perf_event_open(
 asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, unsigned long pgoff);
+asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
+
 #endif
index f395bb3..1154c29 100644 (file)
 
 
 struct sys_device;
+struct sysdev_class_attribute;
 
 struct sysdev_class {
        const char *name;
        struct list_head        drivers;
+       struct sysdev_class_attribute **attrs;
 
        /* Default operations for these types of devices */
        int     (*shutdown)(struct sys_device *);
@@ -41,8 +43,10 @@ struct sysdev_class {
 
 struct sysdev_class_attribute {
        struct attribute attr;
-       ssize_t (*show)(struct sysdev_class *, char *);
-       ssize_t (*store)(struct sysdev_class *, const char *, size_t);
+       ssize_t (*show)(struct sysdev_class *, struct sysdev_class_attribute *,
+                       char *);
+       ssize_t (*store)(struct sysdev_class *, struct sysdev_class_attribute *,
+                        const char *, size_t);
 };
 
 #define _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store)           \
@@ -119,6 +123,19 @@ struct sysdev_attribute {
 extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
 extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
 
+/* Create/remove NULL terminated attribute list */
+static inline int
+sysdev_create_files(struct sys_device *d, struct sysdev_attribute **a)
+{
+       return sysfs_create_files(&d->kobj, (const struct attribute **)a);
+}
+
+static inline void
+sysdev_remove_files(struct sys_device *d, struct sysdev_attribute **a)
+{
+       return sysfs_remove_files(&d->kobj, (const struct attribute **)a);
+}
+
 struct sysdev_ext_attribute {
        struct sysdev_attribute attr;
        void *var;
index cfa8308..f0496b3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/list.h>
+#include <linux/lockdep.h>
 #include <asm/atomic.h>
 
 struct kobject;
@@ -29,8 +30,33 @@ struct attribute {
        const char              *name;
        struct module           *owner;
        mode_t                  mode;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lock_class_key   *key;
+       struct lock_class_key   skey;
+#endif
 };
 
+/**
+ *     sysfs_attr_init - initialize a dynamically allocated sysfs attribute
+ *     @attr: struct attribute to initialize
+ *
+ *     Initialize a dynamically allocated struct attribute so we can
+ *     make lockdep happy.  This is a new requirement for attributes
+ *     and initially this is only needed when lockdep is enabled.
+ *     Lockdep gives a nice error when your attribute is added to
+ *     sysfs if you don't have this.
+ */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define sysfs_attr_init(attr)                          \
+do {                                                   \
+       static struct lock_class_key __key;             \
+                                                       \
+       (attr)->key = &__key;                           \
+} while(0)
+#else
+#define sysfs_attr_init(attr) do {} while(0)
+#endif
+
 struct attribute_group {
        const char              *name;
        mode_t                  (*is_visible)(struct kobject *,
@@ -74,6 +100,18 @@ struct bin_attribute {
                    struct vm_area_struct *vma);
 };
 
+/**
+ *     sysfs_bin_attr_init - initialize a dynamically allocated bin_attribute
+ *     @attr: struct bin_attribute to initialize
+ *
+ *     Initialize a dynamically allocated struct bin_attribute so we
+ *     can make lockdep happy.  This is a new requirement for
+ *     attributes and initially this is only needed when lockdep is
+ *     enabled.  Lockdep gives a nice error when your attribute is
+ *     added to sysfs if you don't have this.
+ */
+#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr)
+
 struct sysfs_ops {
        ssize_t (*show)(struct kobject *, struct attribute *,char *);
        ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
@@ -94,9 +132,12 @@ int __must_check sysfs_move_dir(struct kobject *kobj,
 
 int __must_check sysfs_create_file(struct kobject *kobj,
                                   const struct attribute *attr);
+int __must_check sysfs_create_files(struct kobject *kobj,
+                                  const struct attribute **attr);
 int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
                                  mode_t mode);
 void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
+void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
 
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
                                       const struct bin_attribute *attr);
@@ -110,6 +151,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj,
                                          const char *name);
 void sysfs_remove_link(struct kobject *kobj, const char *name);
 
+int sysfs_rename_link(struct kobject *kobj, struct kobject *target,
+                       const char *old_name, const char *new_name);
+
 int __must_check sysfs_create_group(struct kobject *kobj,
                                    const struct attribute_group *grp);
 int sysfs_update_group(struct kobject *kobj,
@@ -164,6 +208,12 @@ static inline int sysfs_create_file(struct kobject *kobj,
        return 0;
 }
 
+static inline int sysfs_create_files(struct kobject *kobj,
+                                   const struct attribute **attr)
+{
+       return 0;
+}
+
 static inline int sysfs_chmod_file(struct kobject *kobj,
                                   struct attribute *attr, mode_t mode)
 {
@@ -175,6 +225,11 @@ static inline void sysfs_remove_file(struct kobject *kobj,
 {
 }
 
+static inline void sysfs_remove_files(struct kobject *kobj,
+                                    const struct attribute **attr)
+{
+}
+
 static inline int sysfs_create_bin_file(struct kobject *kobj,
                                        const struct bin_attribute *attr)
 {
@@ -203,6 +258,12 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
 {
 }
 
+static inline int sysfs_rename_link(struct kobject *k, struct kobject *t,
+                                   const char *old_name, const char *new_name)
+{
+       return 0;
+}
+
 static inline int sysfs_create_group(struct kobject *kobj,
                                     const struct attribute_group *grp)
 {
index 3398f45..b6523c1 100644 (file)
 extern struct kmem_cache *taskstats_cache;
 extern struct mutex taskstats_exit_mutex;
 
-static inline void taskstats_tgid_init(struct signal_struct *sig)
-{
-       sig->stats = NULL;
-}
-
 static inline void taskstats_tgid_free(struct signal_struct *sig)
 {
        if (sig->stats)
@@ -30,8 +25,6 @@ extern void taskstats_init_early(void);
 #else
 static inline void taskstats_exit(struct task_struct *tsk, int group_dead)
 {}
-static inline void taskstats_tgid_init(struct signal_struct *sig)
-{}
 static inline void taskstats_tgid_free(struct signal_struct *sig)
 {}
 static inline void taskstats_init_early(void)
index d96e588..568369a 100644 (file)
@@ -514,6 +514,7 @@ extern void tty_ldisc_enable(struct tty_struct *tty);
 
 /* n_tty.c */
 extern struct tty_ldisc_ops tty_ldisc_N_TTY;
+extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
 
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
index 0c4ee9b..526d66f 100644 (file)
  *     cease I/O to the tty driver. Can sleep. The driver should
  *     seek to perform this action quickly but should wait until
  *     any pending driver I/O is completed.
+ *
+ * void (*dcd_change)(struct tty_struct *tty, unsigned int status,
+ *                     struct timespec *ts)
+ *
+ *     Tells the discipline that the DCD pin has changed its status and
+ *     the relative timestamp. Pointer ts can be NULL.
  */
 
 #include <linux/fs.h>
@@ -136,6 +142,8 @@ struct tty_ldisc_ops {
        void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,
                               char *fp, int count);
        void    (*write_wakeup)(struct tty_struct *);
+       void    (*dcd_change)(struct tty_struct *, unsigned int,
+                               struct timespec *);
 
        struct  module *owner;
        
index 3492abf..8c9f053 100644 (file)
@@ -512,9 +512,9 @@ extern struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
 
 /* USB device locking */
-#define usb_lock_device(udev)          down(&(udev)->dev.sem)
-#define usb_unlock_device(udev)                up(&(udev)->dev.sem)
-#define usb_trylock_device(udev)       down_trylock(&(udev)->dev.sem)
+#define usb_lock_device(udev)          device_lock(&(udev)->dev)
+#define usb_unlock_device(udev)                device_unlock(&(udev)->dev)
+#define usb_trylock_device(udev)       device_trylock(&(udev)->dev)
 extern int usb_lock_device_for_reset(struct usb_device *udev,
                                     const struct usb_interface *iface);
 
index 6bb2936..4d3e450 100644 (file)
@@ -269,8 +269,8 @@ struct uac_format_type_i_ext_descriptor {
        __u8 bLength;
        __u8 bDescriptorType;
        __u8 bDescriptorSubtype;
-       __u8 bSubslotSize;
        __u8 bFormatType;
+       __u8 bSubslotSize;
        __u8 bBitResolution;
        __u8 bHeaderLength;
        __u8 bControlSize;
index 82b7be4..bd10a79 100644 (file)
@@ -100,14 +100,9 @@ struct net {
 extern struct net init_net;
 
 #ifdef CONFIG_NET
-#define INIT_NET_NS(net_ns) .net_ns = &init_net,
-
 extern struct net *copy_net_ns(unsigned long flags, struct net *net_ns);
 
 #else /* CONFIG_NET */
-
-#define INIT_NET_NS(net_ns)
-
 static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns)
 {
        /* There is nothing to copy so this is a noop */
index 934ae38..a9f3c6f 100644 (file)
@@ -70,6 +70,9 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
  (for the lk 2.2 series).
 */
 
+#ifdef __KERNEL__
+extern int sg_big_buff; /* for sysctl */
+#endif
 
 /* New interface introduced in the 3.x SG drivers follows */
 
index 1f57bb9..0985955 100644 (file)
@@ -544,7 +544,7 @@ struct snd_rawmidi_status {
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 5)
+#define SNDRV_TIMER_VERSION            SNDRV_PROTOCOL_VERSION(2, 0, 6)
 
 enum {
        SNDRV_TIMER_CLASS_NONE = -1,
index a758534..548d28f 100644 (file)
 #define BS_CMD_UPD_FULL                0x33
 #define BS_CMD_UPD_GDRV_CLR    0x37
 
+/* Broadsheet register interface defines */
+#define BS_REG_REV             0x00
+#define BS_REG_PRC             0x02
+
 /* Broadsheet pin interface specific defines */
 #define BS_CS  0x01
 #define BS_DC  0x02
 #define BS_WR  0x03
 
+/* Broadsheet IO interface specific defines */
+#define BS_MMIO_CMD    0x01
+#define BS_MMIO_DATA   0x02
+
 /* struct used by broadsheet. board specific stuff comes from *board */
 struct broadsheetfb_par {
        struct fb_info *info;
@@ -41,6 +49,8 @@ struct broadsheetfb_par {
        void (*write_reg)(struct broadsheetfb_par *, u16 reg, u16 val);
        u16 (*read_reg)(struct broadsheetfb_par *, u16 reg);
        wait_queue_head_t waitq;
+       int panel_index;
+       struct mutex io_lock;
 };
 
 /* board specific routines */
@@ -48,12 +58,17 @@ struct broadsheet_board {
        struct module *owner;
        int (*init)(struct broadsheetfb_par *);
        int (*wait_for_rdy)(struct broadsheetfb_par *);
-       void (*set_ctl)(struct broadsheetfb_par *, unsigned char, u8);
-       void (*set_hdb)(struct broadsheetfb_par *, u16);
-       u16 (*get_hdb)(struct broadsheetfb_par *);
        void (*cleanup)(struct broadsheetfb_par *);
        int (*get_panel_type)(void);
        int (*setup_irq)(struct fb_info *);
-};
 
+       /* Functions for boards that use GPIO */
+       void (*set_ctl)(struct broadsheetfb_par *, unsigned char, u8);
+       void (*set_hdb)(struct broadsheetfb_par *, u16);
+       u16 (*get_hdb)(struct broadsheetfb_par *);
+
+       /* Functions for boards that have specialized MMIO */
+       void (*mmio_write)(struct broadsheetfb_par *, int type, u16);
+       u16 (*mmio_read)(struct broadsheetfb_par *);
+};
 #endif
index 089a230..eb77e8c 100644 (file)
@@ -463,6 +463,7 @@ config HAVE_UNSTABLE_SCHED_CLOCK
 
 menuconfig CGROUPS
        boolean "Control Group support"
+       depends on EVENTFD
        help
          This option adds support for grouping sets of processes together, for
          use with process control subsystems such as Cpusets, CFS, memory
index 4e1955e..9075e17 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
-obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o
+obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o syscall.o
 obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
 obj_mq-$(CONFIG_COMPAT) += compat_mq.o
 obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
index b6cb064..e4e3f04 100644 (file)
@@ -155,7 +155,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
                        spin_lock(&mq_lock);
                        if (u->mq_bytes + mq_bytes < u->mq_bytes ||
                            u->mq_bytes + mq_bytes >
-                           p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+                           task_rlimit(p, RLIMIT_MSGQUEUE)) {
                                spin_unlock(&mq_lock);
                                kfree(info->messages);
                                goto out_inode;
index 23256b8..1a314c8 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -764,8 +764,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                        if (euid != shp->shm_perm.uid &&
                            euid != shp->shm_perm.cuid)
                                goto out_unlock;
-                       if (cmd == SHM_LOCK &&
-                           !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+                       if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
                                goto out_unlock;
                }
 
diff --git a/ipc/syscall.c b/ipc/syscall.c
new file mode 100644 (file)
index 0000000..355a3da
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
+ *
+ * This is really horribly ugly, and new architectures should just wire up
+ * the individual syscalls instead.
+ */
+#include <linux/unistd.h>
+
+#ifdef __ARCH_WANT_SYS_IPC
+#include <linux/errno.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second,
+               unsigned long, third, void __user *, ptr, long, fifth)
+{
+       int version, ret;
+
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+
+       switch (call) {
+       case SEMOP:
+               return sys_semtimedop(first, (struct sembuf __user *)ptr,
+                                     second, NULL);
+       case SEMTIMEDOP:
+               return sys_semtimedop(first, (struct sembuf __user *)ptr,
+                                     second,
+                                     (const struct timespec __user *)fifth);
+
+       case SEMGET:
+               return sys_semget(first, second, third);
+       case SEMCTL: {
+               union semun fourth;
+               if (!ptr)
+                       return -EINVAL;
+               if (get_user(fourth.__pad, (void __user * __user *) ptr))
+                       return -EFAULT;
+               return sys_semctl(first, second, third, fourth);
+       }
+
+       case MSGSND:
+               return sys_msgsnd(first, (struct msgbuf __user *) ptr,
+                                 second, third);
+       case MSGRCV:
+               switch (version) {
+               case 0: {
+                       struct ipc_kludge tmp;
+                       if (!ptr)
+                               return -EINVAL;
+
+                       if (copy_from_user(&tmp,
+                                          (struct ipc_kludge __user *) ptr,
+                                          sizeof(tmp)))
+                               return -EFAULT;
+                       return sys_msgrcv(first, tmp.msgp, second,
+                                          tmp.msgtyp, third);
+               }
+               default:
+                       return sys_msgrcv(first,
+                                          (struct msgbuf __user *) ptr,
+                                          second, fifth, third);
+               }
+       case MSGGET:
+               return sys_msgget((key_t) first, second);
+       case MSGCTL:
+               return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
+
+       case SHMAT:
+               switch (version) {
+               default: {
+                       unsigned long raddr;
+                       ret = do_shmat(first, (char __user *)ptr,
+                                      second, &raddr);
+                       if (ret)
+                               return ret;
+                       return put_user(raddr, (unsigned long __user *) third);
+               }
+               case 1:
+                       /*
+                        * This was the entry point for kernel-originating calls
+                        * from iBCS2 in 2.2 days.
+                        */
+                       return -EINVAL;
+               }
+       case SHMDT:
+               return sys_shmdt((char __user *)ptr);
+       case SHMGET:
+               return sys_shmget(first, second, third);
+       case SHMCTL:
+               return sys_shmctl(first, second,
+                                  (struct shmid_ds __user *) ptr);
+       default:
+               return -ENOSYS;
+       }
+}
+#endif
index a6605ca..24f8c81 100644 (file)
@@ -587,16 +587,6 @@ out:
        revert_creds(orig_cred);
 }
 
-/**
- * acct_init_pacct - initialize a new pacct_struct
- * @pacct: per-process accounting info struct to initialize
- */
-void acct_init_pacct(struct pacct_struct *pacct)
-{
-       memset(pacct, 0, sizeof(struct pacct_struct));
-       pacct->ac_utime = pacct->ac_stime = cputime_zero;
-}
-
 /**
  * acct_collect - collect accounting information into pacct_struct
  * @exitcode: task exit code
index 4fd90e1..ef909a3 100644 (file)
@@ -4,6 +4,10 @@
  *  Based originally on the cpuset system, extracted by Paul Menage
  *  Copyright (C) 2006 Google, Inc
  *
+ *  Notifications support
+ *  Copyright (C) 2009 Nokia Corporation
+ *  Author: Kirill A. Shutemov
+ *
  *  Copyright notices from the original cpuset code:
  *  --------------------------------------------------
  *  Copyright (C) 2003 BULL SA.
@@ -44,6 +48,7 @@
 #include <linux/string.h>
 #include <linux/sort.h>
 #include <linux/kmod.h>
+#include <linux/module.h>
 #include <linux/delayacct.h>
 #include <linux/cgroupstats.h>
 #include <linux/hash.h>
 #include <linux/pid_namespace.h>
 #include <linux/idr.h>
 #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */
+#include <linux/eventfd.h>
+#include <linux/poll.h>
 
 #include <asm/atomic.h>
 
 static DEFINE_MUTEX(cgroup_mutex);
 
-/* Generate an array of cgroup subsystem pointers */
+/*
+ * Generate an array of cgroup subsystem pointers. At boot time, this is
+ * populated up to CGROUP_BUILTIN_SUBSYS_COUNT, and modular subsystems are
+ * registered after that. The mutable section of this array is protected by
+ * cgroup_mutex.
+ */
 #define SUBSYS(_x) &_x ## _subsys,
-
-static struct cgroup_subsys *subsys[] = {
+static struct cgroup_subsys *subsys[CGROUP_SUBSYS_COUNT] = {
 #include <linux/cgroup_subsys.h>
 };
 
@@ -147,6 +158,35 @@ struct css_id {
        unsigned short stack[0]; /* Array of Length (depth+1) */
 };
 
+/*
+ * cgroup_event represents events which userspace want to recieve.
+ */
+struct cgroup_event {
+       /*
+        * Cgroup which the event belongs to.
+        */
+       struct cgroup *cgrp;
+       /*
+        * Control file which the event associated.
+        */
+       struct cftype *cft;
+       /*
+        * eventfd to signal userspace about the event.
+        */
+       struct eventfd_ctx *eventfd;
+       /*
+        * Each of these stored in a list by the cgroup.
+        */
+       struct list_head list;
+       /*
+        * All fields below needed to unregister event when
+        * userspace closes eventfd.
+        */
+       poll_table pt;
+       wait_queue_head_t *wqh;
+       wait_queue_t wait;
+       struct work_struct remove;
+};
 
 /* The list of hierarchy roots */
 
@@ -250,7 +290,8 @@ struct cg_cgroup_link {
 static struct css_set init_css_set;
 static struct cg_cgroup_link init_css_set_link;
 
-static int cgroup_subsys_init_idr(struct cgroup_subsys *ss);
+static int cgroup_init_idr(struct cgroup_subsys *ss,
+                          struct cgroup_subsys_state *css);
 
 /* css_set_lock protects the list of css_set objects, and the
  * chain of tasks off each css_set.  Nests outside task->alloc_lock
@@ -448,8 +489,11 @@ static struct css_set *find_existing_css_set(
        struct hlist_node *node;
        struct css_set *cg;
 
-       /* Built the set of subsystem state objects that we want to
-        * see in the new css_set */
+       /*
+        * Build the set of subsystem state objects that we want to see in the
+        * new css_set. while subsystems can change globally, the entries here
+        * won't change, so no need for locking.
+        */
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                if (root->subsys_bits & (1UL << i)) {
                        /* Subsystem is in this hierarchy. So we want
@@ -696,6 +740,7 @@ void cgroup_lock(void)
 {
        mutex_lock(&cgroup_mutex);
 }
+EXPORT_SYMBOL_GPL(cgroup_lock);
 
 /**
  * cgroup_unlock - release lock on cgroup changes
@@ -706,6 +751,7 @@ void cgroup_unlock(void)
 {
        mutex_unlock(&cgroup_mutex);
 }
+EXPORT_SYMBOL_GPL(cgroup_unlock);
 
 /*
  * A couple of forward declarations required, due to cyclic reference loop:
@@ -757,6 +803,7 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp)
                        if (ret)
                                break;
                }
+
        return ret;
 }
 
@@ -884,7 +931,11 @@ void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css)
        css_put(css);
 }
 
-
+/*
+ * Call with cgroup_mutex held. Drops reference counts on modules, including
+ * any duplicate ones that parse_cgroupfs_options took. If this function
+ * returns an error, no reference counts are touched.
+ */
 static int rebind_subsystems(struct cgroupfs_root *root,
                              unsigned long final_bits)
 {
@@ -892,6 +943,8 @@ static int rebind_subsystems(struct cgroupfs_root *root,
        struct cgroup *cgrp = &root->top_cgroup;
        int i;
 
+       BUG_ON(!mutex_is_locked(&cgroup_mutex));
+
        removed_bits = root->actual_subsys_bits & ~final_bits;
        added_bits = final_bits & ~root->actual_subsys_bits;
        /* Check that any added subsystems are currently free */
@@ -900,6 +953,12 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                struct cgroup_subsys *ss = subsys[i];
                if (!(bit & added_bits))
                        continue;
+               /*
+                * Nobody should tell us to do a subsys that doesn't exist:
+                * parse_cgroupfs_options should catch that case and refcounts
+                * ensure that subsystems won't disappear once selected.
+                */
+               BUG_ON(ss == NULL);
                if (ss->root != &rootnode) {
                        /* Subsystem isn't free */
                        return -EBUSY;
@@ -919,6 +978,7 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                unsigned long bit = 1UL << i;
                if (bit & added_bits) {
                        /* We're binding this subsystem to this hierarchy */
+                       BUG_ON(ss == NULL);
                        BUG_ON(cgrp->subsys[i]);
                        BUG_ON(!dummytop->subsys[i]);
                        BUG_ON(dummytop->subsys[i]->cgroup != dummytop);
@@ -930,8 +990,10 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        if (ss->bind)
                                ss->bind(ss, cgrp);
                        mutex_unlock(&ss->hierarchy_mutex);
+                       /* refcount was already taken, and we're keeping it */
                } else if (bit & removed_bits) {
                        /* We're removing this subsystem */
+                       BUG_ON(ss == NULL);
                        BUG_ON(cgrp->subsys[i] != dummytop->subsys[i]);
                        BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
                        mutex_lock(&ss->hierarchy_mutex);
@@ -942,9 +1004,20 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        subsys[i]->root = &rootnode;
                        list_move(&ss->sibling, &rootnode.subsys_list);
                        mutex_unlock(&ss->hierarchy_mutex);
+                       /* subsystem is now free - drop reference on module */
+                       module_put(ss->module);
                } else if (bit & final_bits) {
                        /* Subsystem state should already exist */
+                       BUG_ON(ss == NULL);
                        BUG_ON(!cgrp->subsys[i]);
+                       /*
+                        * a refcount was taken, but we already had one, so
+                        * drop the extra reference.
+                        */
+                       module_put(ss->module);
+#ifdef CONFIG_MODULE_UNLOAD
+                       BUG_ON(ss->module && !module_refcount(ss->module));
+#endif
                } else {
                        /* Subsystem state shouldn't exist */
                        BUG_ON(cgrp->subsys[i]);
@@ -986,13 +1059,20 @@ struct cgroup_sb_opts {
 
 };
 
-/* Convert a hierarchy specifier into a bitmask of subsystems and
- * flags. */
-static int parse_cgroupfs_options(char *data,
-                                    struct cgroup_sb_opts *opts)
+/*
+ * Convert a hierarchy specifier into a bitmask of subsystems and flags. Call
+ * with cgroup_mutex held to protect the subsys[] array. This function takes
+ * refcounts on subsystems to be used, unless it returns error, in which case
+ * no refcounts are taken.
+ */
+static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
 {
        char *token, *o = data ?: "all";
        unsigned long mask = (unsigned long)-1;
+       int i;
+       bool module_pin_failed = false;
+
+       BUG_ON(!mutex_is_locked(&cgroup_mutex));
 
 #ifdef CONFIG_CPUSETS
        mask = ~(1UL << cpuset_subsys_id);
@@ -1005,10 +1085,11 @@ static int parse_cgroupfs_options(char *data,
                        return -EINVAL;
                if (!strcmp(token, "all")) {
                        /* Add all non-disabled subsystems */
-                       int i;
                        opts->subsys_bits = 0;
                        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                                struct cgroup_subsys *ss = subsys[i];
+                               if (ss == NULL)
+                                       continue;
                                if (!ss->disabled)
                                        opts->subsys_bits |= 1ul << i;
                        }
@@ -1026,7 +1107,6 @@ static int parse_cgroupfs_options(char *data,
                        if (!opts->release_agent)
                                return -ENOMEM;
                } else if (!strncmp(token, "name=", 5)) {
-                       int i;
                        const char *name = token + 5;
                        /* Can't specify an empty name */
                        if (!strlen(name))
@@ -1050,9 +1130,10 @@ static int parse_cgroupfs_options(char *data,
                                return -ENOMEM;
                } else {
                        struct cgroup_subsys *ss;
-                       int i;
                        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                                ss = subsys[i];
+                               if (ss == NULL)
+                                       continue;
                                if (!strcmp(token, ss->name)) {
                                        if (!ss->disabled)
                                                set_bit(i, &opts->subsys_bits);
@@ -1087,9 +1168,54 @@ static int parse_cgroupfs_options(char *data,
        if (!opts->subsys_bits && !opts->name)
                return -EINVAL;
 
+       /*
+        * Grab references on all the modules we'll need, so the subsystems
+        * don't dance around before rebind_subsystems attaches them. This may
+        * take duplicate reference counts on a subsystem that's already used,
+        * but rebind_subsystems handles this case.
+        */
+       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
+               unsigned long bit = 1UL << i;
+
+               if (!(bit & opts->subsys_bits))
+                       continue;
+               if (!try_module_get(subsys[i]->module)) {
+                       module_pin_failed = true;
+                       break;
+               }
+       }
+       if (module_pin_failed) {
+               /*
+                * oops, one of the modules was going away. this means that we
+                * raced with a module_delete call, and to the user this is
+                * essentially a "subsystem doesn't exist" case.
+                */
+               for (i--; i >= CGROUP_BUILTIN_SUBSYS_COUNT; i--) {
+                       /* drop refcounts only on the ones we took */
+                       unsigned long bit = 1UL << i;
+
+                       if (!(bit & opts->subsys_bits))
+                               continue;
+                       module_put(subsys[i]->module);
+               }
+               return -ENOENT;
+       }
+
        return 0;
 }
 
+static void drop_parsed_module_refcounts(unsigned long subsys_bits)
+{
+       int i;
+       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
+               unsigned long bit = 1UL << i;
+
+               if (!(bit & subsys_bits))
+                       continue;
+               module_put(subsys[i]->module);
+       }
+}
+
 static int cgroup_remount(struct super_block *sb, int *flags, char *data)
 {
        int ret = 0;
@@ -1106,21 +1232,19 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        if (ret)
                goto out_unlock;
 
-       /* Don't allow flags to change at remount */
-       if (opts.flags != root->flags) {
-               ret = -EINVAL;
-               goto out_unlock;
-       }
-
-       /* Don't allow name to change at remount */
-       if (opts.name && strcmp(opts.name, root->name)) {
+       /* Don't allow flags or name to change at remount */
+       if (opts.flags != root->flags ||
+           (opts.name && strcmp(opts.name, root->name))) {
                ret = -EINVAL;
+               drop_parsed_module_refcounts(opts.subsys_bits);
                goto out_unlock;
        }
 
        ret = rebind_subsystems(root, opts.subsys_bits);
-       if (ret)
+       if (ret) {
+               drop_parsed_module_refcounts(opts.subsys_bits);
                goto out_unlock;
+       }
 
        /* (re)populate subsystem files */
        cgroup_populate_dir(cgrp);
@@ -1151,6 +1275,8 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
        INIT_LIST_HEAD(&cgrp->release_list);
        INIT_LIST_HEAD(&cgrp->pidlists);
        mutex_init(&cgrp->pidlist_mutex);
+       INIT_LIST_HEAD(&cgrp->event_list);
+       spin_lock_init(&cgrp->event_list_lock);
 }
 
 static void init_cgroup_root(struct cgroupfs_root *root)
@@ -1306,7 +1432,9 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
        struct cgroupfs_root *new_root;
 
        /* First find the desired set of subsystems */
+       mutex_lock(&cgroup_mutex);
        ret = parse_cgroupfs_options(data, &opts);
+       mutex_unlock(&cgroup_mutex);
        if (ret)
                goto out_err;
 
@@ -1317,7 +1445,7 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
        new_root = cgroup_root_from_opts(&opts);
        if (IS_ERR(new_root)) {
                ret = PTR_ERR(new_root);
-               goto out_err;
+               goto drop_modules;
        }
        opts.new_root = new_root;
 
@@ -1326,7 +1454,7 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
                cgroup_drop_root(opts.new_root);
-               goto out_err;
+               goto drop_modules;
        }
 
        root = sb->s_fs_info;
@@ -1382,6 +1510,11 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
                        free_cg_links(&tmp_cg_links);
                        goto drop_new_super;
                }
+               /*
+                * There must be no failure case after here, since rebinding
+                * takes care of subsystems' refcounts, which are explicitly
+                * dropped in the failure exit path.
+                */
 
                /* EBUSY should be the only error here */
                BUG_ON(ret);
@@ -1420,6 +1553,8 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
                 * any) is not needed
                 */
                cgroup_drop_root(opts.new_root);
+               /* no subsys rebinding, so refcounts don't change */
+               drop_parsed_module_refcounts(opts.subsys_bits);
        }
 
        simple_set_mnt(mnt, sb);
@@ -1429,6 +1564,8 @@ static int cgroup_get_sb(struct file_system_type *fs_type,
 
  drop_new_super:
        deactivate_locked_super(sb);
+ drop_modules:
+       drop_parsed_module_refcounts(opts.subsys_bits);
  out_err:
        kfree(opts.release_agent);
        kfree(opts.name);
@@ -1542,6 +1679,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
        memmove(buf, start, buf + buflen - start);
        return 0;
 }
+EXPORT_SYMBOL_GPL(cgroup_path);
 
 /**
  * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp'
@@ -1554,7 +1692,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
 int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        int retval = 0;
-       struct cgroup_subsys *ss;
+       struct cgroup_subsys *ss, *failed_ss = NULL;
        struct cgroup *oldcgrp;
        struct css_set *cg;
        struct css_set *newcg;
@@ -1568,8 +1706,16 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        for_each_subsys(root, ss) {
                if (ss->can_attach) {
                        retval = ss->can_attach(ss, cgrp, tsk, false);
-                       if (retval)
-                               return retval;
+                       if (retval) {
+                               /*
+                                * Remember on which subsystem the can_attach()
+                                * failed, so that we only call cancel_attach()
+                                * against the subsystems whose can_attach()
+                                * succeeded. (See below)
+                                */
+                               failed_ss = ss;
+                               goto out;
+                       }
                }
        }
 
@@ -1583,14 +1729,17 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
         */
        newcg = find_css_set(cg, cgrp);
        put_css_set(cg);
-       if (!newcg)
-               return -ENOMEM;
+       if (!newcg) {
+               retval = -ENOMEM;
+               goto out;
+       }
 
        task_lock(tsk);
        if (tsk->flags & PF_EXITING) {
                task_unlock(tsk);
                put_css_set(newcg);
-               return -ESRCH;
+               retval = -ESRCH;
+               goto out;
        }
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);
@@ -1616,7 +1765,22 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
         * is no longer empty.
         */
        cgroup_wakeup_rmdir_waiter(cgrp);
-       return 0;
+out:
+       if (retval) {
+               for_each_subsys(root, ss) {
+                       if (ss == failed_ss)
+                               /*
+                                * This subsystem was the one that failed the
+                                * can_attach() check earlier, so we don't need
+                                * to call cancel_attach() against it or any
+                                * remaining subsystems.
+                                */
+                               break;
+                       if (ss->cancel_attach)
+                               ss->cancel_attach(ss, cgrp, tsk, false);
+               }
+       }
+       return retval;
 }
 
 /*
@@ -1682,6 +1846,7 @@ bool cgroup_lock_live_group(struct cgroup *cgrp)
        }
        return true;
 }
+EXPORT_SYMBOL_GPL(cgroup_lock_live_group);
 
 static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
                                      const char *buffer)
@@ -1950,6 +2115,16 @@ static const struct inode_operations cgroup_dir_inode_operations = {
        .rename = cgroup_rename,
 };
 
+/*
+ * Check if a file is a control file
+ */
+static inline struct cftype *__file_cft(struct file *file)
+{
+       if (file->f_dentry->d_inode->i_fop != &cgroup_file_operations)
+               return ERR_PTR(-EINVAL);
+       return __d_cft(file->f_dentry);
+}
+
 static int cgroup_create_file(struct dentry *dentry, mode_t mode,
                                struct super_block *sb)
 {
@@ -2069,6 +2244,7 @@ int cgroup_add_file(struct cgroup *cgrp,
                error = PTR_ERR(dentry);
        return error;
 }
+EXPORT_SYMBOL_GPL(cgroup_add_file);
 
 int cgroup_add_files(struct cgroup *cgrp,
                        struct cgroup_subsys *subsys,
@@ -2083,6 +2259,7 @@ int cgroup_add_files(struct cgroup *cgrp,
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(cgroup_add_files);
 
 /**
  * cgroup_task_count - count the number of tasks in a cgroup.
@@ -2468,7 +2645,8 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
 {
        struct cgroup_pidlist *l;
        /* don't need task_nsproxy() if we're looking at ourself */
-       struct pid_namespace *ns = get_pid_ns(current->nsproxy->pid_ns);
+       struct pid_namespace *ns = current->nsproxy->pid_ns;
+
        /*
         * We can't drop the pidlist_mutex before taking the l->mutex in case
         * the last ref-holder is trying to remove l from the list at the same
@@ -2478,8 +2656,6 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
        mutex_lock(&cgrp->pidlist_mutex);
        list_for_each_entry(l, &cgrp->pidlists, links) {
                if (l->key.type == type && l->key.ns == ns) {
-                       /* found a matching list - drop the extra refcount */
-                       put_pid_ns(ns);
                        /* make sure l doesn't vanish out from under us */
                        down_write(&l->mutex);
                        mutex_unlock(&cgrp->pidlist_mutex);
@@ -2490,13 +2666,12 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
        l = kmalloc(sizeof(struct cgroup_pidlist), GFP_KERNEL);
        if (!l) {
                mutex_unlock(&cgrp->pidlist_mutex);
-               put_pid_ns(ns);
                return l;
        }
        init_rwsem(&l->mutex);
        down_write(&l->mutex);
        l->key.type = type;
-       l->key.ns = ns;
+       l->key.ns = get_pid_ns(ns);
        l->use_count = 0; /* don't increment here */
        l->list = NULL;
        l->owner = cgrp;
@@ -2803,6 +2978,174 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp,
        return 0;
 }
 
+/*
+ * Unregister event and free resources.
+ *
+ * Gets called from workqueue.
+ */
+static void cgroup_event_remove(struct work_struct *work)
+{
+       struct cgroup_event *event = container_of(work, struct cgroup_event,
+                       remove);
+       struct cgroup *cgrp = event->cgrp;
+
+       /* TODO: check return code */
+       event->cft->unregister_event(cgrp, event->cft, event->eventfd);
+
+       eventfd_ctx_put(event->eventfd);
+       kfree(event);
+       dput(cgrp->dentry);
+}
+
+/*
+ * Gets called on POLLHUP on eventfd when user closes it.
+ *
+ * Called with wqh->lock held and interrupts disabled.
+ */
+static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
+               int sync, void *key)
+{
+       struct cgroup_event *event = container_of(wait,
+                       struct cgroup_event, wait);
+       struct cgroup *cgrp = event->cgrp;
+       unsigned long flags = (unsigned long)key;
+
+       if (flags & POLLHUP) {
+               remove_wait_queue_locked(event->wqh, &event->wait);
+               spin_lock(&cgrp->event_list_lock);
+               list_del(&event->list);
+               spin_unlock(&cgrp->event_list_lock);
+               /*
+                * We are in atomic context, but cgroup_event_remove() may
+                * sleep, so we have to call it in workqueue.
+                */
+               schedule_work(&event->remove);
+       }
+
+       return 0;
+}
+
+static void cgroup_event_ptable_queue_proc(struct file *file,
+               wait_queue_head_t *wqh, poll_table *pt)
+{
+       struct cgroup_event *event = container_of(pt,
+                       struct cgroup_event, pt);
+
+       event->wqh = wqh;
+       add_wait_queue(wqh, &event->wait);
+}
+
+/*
+ * Parse input and register new cgroup event handler.
+ *
+ * Input must be in format '<event_fd> <control_fd> <args>'.
+ * Interpretation of args is defined by control file implementation.
+ */
+static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
+                                     const char *buffer)
+{
+       struct cgroup_event *event = NULL;
+       unsigned int efd, cfd;
+       struct file *efile = NULL;
+       struct file *cfile = NULL;
+       char *endp;
+       int ret;
+
+       efd = simple_strtoul(buffer, &endp, 10);
+       if (*endp != ' ')
+               return -EINVAL;
+       buffer = endp + 1;
+
+       cfd = simple_strtoul(buffer, &endp, 10);
+       if ((*endp != ' ') && (*endp != '\0'))
+               return -EINVAL;
+       buffer = endp + 1;
+
+       event = kzalloc(sizeof(*event), GFP_KERNEL);
+       if (!event)
+               return -ENOMEM;
+       event->cgrp = cgrp;
+       INIT_LIST_HEAD(&event->list);
+       init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc);
+       init_waitqueue_func_entry(&event->wait, cgroup_event_wake);
+       INIT_WORK(&event->remove, cgroup_event_remove);
+
+       efile = eventfd_fget(efd);
+       if (IS_ERR(efile)) {
+               ret = PTR_ERR(efile);
+               goto fail;
+       }
+
+       event->eventfd = eventfd_ctx_fileget(efile);
+       if (IS_ERR(event->eventfd)) {
+               ret = PTR_ERR(event->eventfd);
+               goto fail;
+       }
+
+       cfile = fget(cfd);
+       if (!cfile) {
+               ret = -EBADF;
+               goto fail;
+       }
+
+       /* the process need read permission on control file */
+       ret = file_permission(cfile, MAY_READ);
+       if (ret < 0)
+               goto fail;
+
+       event->cft = __file_cft(cfile);
+       if (IS_ERR(event->cft)) {
+               ret = PTR_ERR(event->cft);
+               goto fail;
+       }
+
+       if (!event->cft->register_event || !event->cft->unregister_event) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ret = event->cft->register_event(cgrp, event->cft,
+                       event->eventfd, buffer);
+       if (ret)
+               goto fail;
+
+       if (efile->f_op->poll(efile, &event->pt) & POLLHUP) {
+               event->cft->unregister_event(cgrp, event->cft, event->eventfd);
+               ret = 0;
+               goto fail;
+       }
+
+       /*
+        * Events should be removed after rmdir of cgroup directory, but before
+        * destroying subsystem state objects. Let's take reference to cgroup
+        * directory dentry to do that.
+        */
+       dget(cgrp->dentry);
+
+       spin_lock(&cgrp->event_list_lock);
+       list_add(&event->list, &cgrp->event_list);
+       spin_unlock(&cgrp->event_list_lock);
+
+       fput(cfile);
+       fput(efile);
+
+       return 0;
+
+fail:
+       if (cfile)
+               fput(cfile);
+
+       if (event && event->eventfd && !IS_ERR(event->eventfd))
+               eventfd_ctx_put(event->eventfd);
+
+       if (!IS_ERR_OR_NULL(efile))
+               fput(efile);
+
+       kfree(event);
+
+       return ret;
+}
+
 /*
  * for the common functions, 'private' gives the type of file
  */
@@ -2828,6 +3171,11 @@ static struct cftype files[] = {
                .read_u64 = cgroup_read_notify_on_release,
                .write_u64 = cgroup_write_notify_on_release,
        },
+       {
+               .name = CGROUP_FILE_GENERIC_PREFIX "event_control",
+               .write_string = cgroup_write_event_control,
+               .mode = S_IWUGO,
+       },
 };
 
 static struct cftype cft_release_agent = {
@@ -2892,8 +3240,14 @@ static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
        /* We need to take each hierarchy_mutex in a consistent order */
        int i;
 
+       /*
+        * No worry about a race with rebind_subsystems that might mess up the
+        * locking order, since both parties are under cgroup_mutex.
+        */
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
+               if (ss == NULL)
+                       continue;
                if (ss->root == root)
                        mutex_lock(&ss->hierarchy_mutex);
        }
@@ -2905,6 +3259,8 @@ static void cgroup_unlock_hierarchy(struct cgroupfs_root *root)
 
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
+               if (ss == NULL)
+                       continue;
                if (ss->root == root)
                        mutex_unlock(&ss->hierarchy_mutex);
        }
@@ -3028,11 +3384,16 @@ static int cgroup_has_css_refs(struct cgroup *cgrp)
         * synchronization other than RCU, and the subsystem linked
         * list isn't RCU-safe */
        int i;
+       /*
+        * We won't need to lock the subsys array, because the subsystems
+        * we're concerned about aren't going anywhere since our cgroup root
+        * has a reference on them.
+        */
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
                struct cgroup_subsys_state *css;
-               /* Skip subsystems not in this hierarchy */
-               if (ss->root != cgrp->root)
+               /* Skip subsystems not present or not in this hierarchy */
+               if (ss == NULL || ss->root != cgrp->root)
                        continue;
                css = cgrp->subsys[ss->subsys_id];
                /* When called from check_for_release() it's possible
@@ -3106,6 +3467,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        struct dentry *d;
        struct cgroup *parent;
        DEFINE_WAIT(wait);
+       struct cgroup_event *event, *tmp;
        int ret;
 
        /* the vfs holds both inode->i_mutex already */
@@ -3189,6 +3551,20 @@ again:
        set_bit(CGRP_RELEASABLE, &parent->flags);
        check_for_release(parent);
 
+       /*
+        * Unregister events and notify userspace.
+        * Notify userspace about cgroup removing only after rmdir of cgroup
+        * directory to avoid race between userspace and kernelspace
+        */
+       spin_lock(&cgrp->event_list_lock);
+       list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
+               list_del(&event->list);
+               remove_wait_queue(event->wqh, &event->wait);
+               eventfd_signal(event->eventfd, 1);
+               schedule_work(&event->remove);
+       }
+       spin_unlock(&cgrp->event_list_lock);
+
        mutex_unlock(&cgroup_mutex);
        return 0;
 }
@@ -3223,7 +3599,196 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
        mutex_init(&ss->hierarchy_mutex);
        lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key);
        ss->active = 1;
+
+       /* this function shouldn't be used with modular subsystems, since they
+        * need to register a subsys_id, among other things */
+       BUG_ON(ss->module);
+}
+
+/**
+ * cgroup_load_subsys: load and register a modular subsystem at runtime
+ * @ss: the subsystem to load
+ *
+ * This function should be called in a modular subsystem's initcall. If the
+ * subsytem is built as a module, it will be assigned a new subsys_id and set
+ * up for use. If the subsystem is built-in anyway, work is delegated to the
+ * simpler cgroup_init_subsys.
+ */
+int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
+{
+       int i;
+       struct cgroup_subsys_state *css;
+
+       /* check name and function validity */
+       if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN ||
+           ss->create == NULL || ss->destroy == NULL)
+               return -EINVAL;
+
+       /*
+        * we don't support callbacks in modular subsystems. this check is
+        * before the ss->module check for consistency; a subsystem that could
+        * be a module should still have no callbacks even if the user isn't
+        * compiling it as one.
+        */
+       if (ss->fork || ss->exit)
+               return -EINVAL;
+
+       /*
+        * an optionally modular subsystem is built-in: we want to do nothing,
+        * since cgroup_init_subsys will have already taken care of it.
+        */
+       if (ss->module == NULL) {
+               /* a few sanity checks */
+               BUG_ON(ss->subsys_id >= CGROUP_BUILTIN_SUBSYS_COUNT);
+               BUG_ON(subsys[ss->subsys_id] != ss);
+               return 0;
+       }
+
+       /*
+        * need to register a subsys id before anything else - for example,
+        * init_cgroup_css needs it.
+        */
+       mutex_lock(&cgroup_mutex);
+       /* find the first empty slot in the array */
+       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
+               if (subsys[i] == NULL)
+                       break;
+       }
+       if (i == CGROUP_SUBSYS_COUNT) {
+               /* maximum number of subsystems already registered! */
+               mutex_unlock(&cgroup_mutex);
+               return -EBUSY;
+       }
+       /* assign ourselves the subsys_id */
+       ss->subsys_id = i;
+       subsys[i] = ss;
+
+       /*
+        * no ss->create seems to need anything important in the ss struct, so
+        * this can happen first (i.e. before the rootnode attachment).
+        */
+       css = ss->create(ss, dummytop);
+       if (IS_ERR(css)) {
+               /* failure case - need to deassign the subsys[] slot. */
+               subsys[i] = NULL;
+               mutex_unlock(&cgroup_mutex);
+               return PTR_ERR(css);
+       }
+
+       list_add(&ss->sibling, &rootnode.subsys_list);
+       ss->root = &rootnode;
+
+       /* our new subsystem will be attached to the dummy hierarchy. */
+       init_cgroup_css(css, ss, dummytop);
+       /* init_idr must be after init_cgroup_css because it sets css->id. */
+       if (ss->use_id) {
+               int ret = cgroup_init_idr(ss, css);
+               if (ret) {
+                       dummytop->subsys[ss->subsys_id] = NULL;
+                       ss->destroy(ss, dummytop);
+                       subsys[i] = NULL;
+                       mutex_unlock(&cgroup_mutex);
+                       return ret;
+               }
+       }
+
+       /*
+        * Now we need to entangle the css into the existing css_sets. unlike
+        * in cgroup_init_subsys, there are now multiple css_sets, so each one
+        * will need a new pointer to it; done by iterating the css_set_table.
+        * furthermore, modifying the existing css_sets will corrupt the hash
+        * table state, so each changed css_set will need its hash recomputed.
+        * this is all done under the css_set_lock.
+        */
+       write_lock(&css_set_lock);
+       for (i = 0; i < CSS_SET_TABLE_SIZE; i++) {
+               struct css_set *cg;
+               struct hlist_node *node, *tmp;
+               struct hlist_head *bucket = &css_set_table[i], *new_bucket;
+
+               hlist_for_each_entry_safe(cg, node, tmp, bucket, hlist) {
+                       /* skip entries that we already rehashed */
+                       if (cg->subsys[ss->subsys_id])
+                               continue;
+                       /* remove existing entry */
+                       hlist_del(&cg->hlist);
+                       /* set new value */
+                       cg->subsys[ss->subsys_id] = css;
+                       /* recompute hash and restore entry */
+                       new_bucket = css_set_hash(cg->subsys);
+                       hlist_add_head(&cg->hlist, new_bucket);
+               }
+       }
+       write_unlock(&css_set_lock);
+
+       mutex_init(&ss->hierarchy_mutex);
+       lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key);
+       ss->active = 1;
+
+       /* success! */
+       mutex_unlock(&cgroup_mutex);
+       return 0;
 }
+EXPORT_SYMBOL_GPL(cgroup_load_subsys);
+
+/**
+ * cgroup_unload_subsys: unload a modular subsystem
+ * @ss: the subsystem to unload
+ *
+ * This function should be called in a modular subsystem's exitcall. When this
+ * function is invoked, the refcount on the subsystem's module will be 0, so
+ * the subsystem will not be attached to any hierarchy.
+ */
+void cgroup_unload_subsys(struct cgroup_subsys *ss)
+{
+       struct cg_cgroup_link *link;
+       struct hlist_head *hhead;
+
+       BUG_ON(ss->module == NULL);
+
+       /*
+        * we shouldn't be called if the subsystem is in use, and the use of
+        * try_module_get in parse_cgroupfs_options should ensure that it
+        * doesn't start being used while we're killing it off.
+        */
+       BUG_ON(ss->root != &rootnode);
+
+       mutex_lock(&cgroup_mutex);
+       /* deassign the subsys_id */
+       BUG_ON(ss->subsys_id < CGROUP_BUILTIN_SUBSYS_COUNT);
+       subsys[ss->subsys_id] = NULL;
+
+       /* remove subsystem from rootnode's list of subsystems */
+       list_del(&ss->sibling);
+
+       /*
+        * disentangle the css from all css_sets attached to the dummytop. as
+        * in loading, we need to pay our respects to the hashtable gods.
+        */
+       write_lock(&css_set_lock);
+       list_for_each_entry(link, &dummytop->css_sets, cgrp_link_list) {
+               struct css_set *cg = link->cg;
+
+               hlist_del(&cg->hlist);
+               BUG_ON(!cg->subsys[ss->subsys_id]);
+               cg->subsys[ss->subsys_id] = NULL;
+               hhead = css_set_hash(cg->subsys);
+               hlist_add_head(&cg->hlist, hhead);
+       }
+       write_unlock(&css_set_lock);
+
+       /*
+        * remove subsystem's css from the dummytop and free it - need to free
+        * before marking as null because ss->destroy needs the cgrp->subsys
+        * pointer to find their state. note that this also takes care of
+        * freeing the css_id.
+        */
+       ss->destroy(ss, dummytop);
+       dummytop->subsys[ss->subsys_id] = NULL;
+
+       mutex_unlock(&cgroup_mutex);
+}
+EXPORT_SYMBOL_GPL(cgroup_unload_subsys);
 
 /**
  * cgroup_init_early - cgroup initialization at system boot
@@ -3253,7 +3818,8 @@ int __init cgroup_init_early(void)
        for (i = 0; i < CSS_SET_TABLE_SIZE; i++)
                INIT_HLIST_HEAD(&css_set_table[i]);
 
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+       /* at bootup time, we don't worry about modular subsystems */
+       for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
 
                BUG_ON(!ss->name);
@@ -3288,12 +3854,13 @@ int __init cgroup_init(void)
        if (err)
                return err;
 
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+       /* at bootup time, we don't worry about modular subsystems */
+       for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
                if (!ss->early_init)
                        cgroup_init_subsys(ss);
                if (ss->use_id)
-                       cgroup_subsys_init_idr(ss);
+                       cgroup_init_idr(ss, init_css_set.subsys[ss->subsys_id]);
        }
 
        /* Add init_css_set to the hash table */
@@ -3397,9 +3964,16 @@ static int proc_cgroupstats_show(struct seq_file *m, void *v)
        int i;
 
        seq_puts(m, "#subsys_name\thierarchy\tnum_cgroups\tenabled\n");
+       /*
+        * ideally we don't want subsystems moving around while we do this.
+        * cgroup_mutex is also necessary to guarantee an atomic snapshot of
+        * subsys/hierarchy state.
+        */
        mutex_lock(&cgroup_mutex);
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
+               if (ss == NULL)
+                       continue;
                seq_printf(m, "%s\t%d\t%d\t%d\n",
                           ss->name, ss->root->hierarchy_id,
                           ss->root->number_of_cgroups, !ss->disabled);
@@ -3457,7 +4031,12 @@ void cgroup_fork_callbacks(struct task_struct *child)
 {
        if (need_forkexit_callback) {
                int i;
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+               /*
+                * forkexit callbacks are only supported for builtin
+                * subsystems, and the builtin section of the subsys array is
+                * immutable, so we don't need to lock the subsys array here.
+                */
+               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
                        struct cgroup_subsys *ss = subsys[i];
                        if (ss->fork)
                                ss->fork(ss, child);
@@ -3526,7 +4105,11 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
        struct css_set *cg;
 
        if (run_callbacks && need_forkexit_callback) {
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+               /*
+                * modular subsystems can't use callbacks, so no need to lock
+                * the subsys array
+                */
+               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
                        struct cgroup_subsys *ss = subsys[i];
                        if (ss->exit)
                                ss->exit(ss, tsk);
@@ -3720,12 +4303,13 @@ static void check_for_release(struct cgroup *cgrp)
        }
 }
 
-void __css_put(struct cgroup_subsys_state *css)
+/* Caller must verify that the css is not for root cgroup */
+void __css_put(struct cgroup_subsys_state *css, int count)
 {
        struct cgroup *cgrp = css->cgroup;
        int val;
        rcu_read_lock();
-       val = atomic_dec_return(&css->refcnt);
+       val = atomic_sub_return(count, &css->refcnt);
        if (val == 1) {
                if (notify_on_release(cgrp)) {
                        set_bit(CGRP_RELEASABLE, &cgrp->flags);
@@ -3736,6 +4320,7 @@ void __css_put(struct cgroup_subsys_state *css)
        rcu_read_unlock();
        WARN_ON_ONCE(val < 1);
 }
+EXPORT_SYMBOL_GPL(__css_put);
 
 /*
  * Notify userspace when a cgroup is released, by running the
@@ -3817,8 +4402,11 @@ static int __init cgroup_disable(char *str)
        while ((token = strsep(&str, ",")) != NULL) {
                if (!*token)
                        continue;
-
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+               /*
+                * cgroup_disable, being at boot time, can't know about module
+                * subsystems, so we don't worry about them.
+                */
+               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
                        struct cgroup_subsys *ss = subsys[i];
 
                        if (!strcmp(token, ss->name)) {
@@ -3848,6 +4436,7 @@ unsigned short css_id(struct cgroup_subsys_state *css)
                return cssid->id;
        return 0;
 }
+EXPORT_SYMBOL_GPL(css_id);
 
 unsigned short css_depth(struct cgroup_subsys_state *css)
 {
@@ -3857,6 +4446,7 @@ unsigned short css_depth(struct cgroup_subsys_state *css)
                return cssid->depth;
        return 0;
 }
+EXPORT_SYMBOL_GPL(css_depth);
 
 bool css_is_ancestor(struct cgroup_subsys_state *child,
                    const struct cgroup_subsys_state *root)
@@ -3893,6 +4483,7 @@ void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
        spin_unlock(&ss->id_lock);
        call_rcu(&id->rcu_head, __free_css_id_cb);
 }
+EXPORT_SYMBOL_GPL(free_css_id);
 
 /*
  * This is called by init or create(). Then, calls to this function are
@@ -3942,15 +4533,14 @@ err_out:
 
 }
 
-static int __init cgroup_subsys_init_idr(struct cgroup_subsys *ss)
+static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss,
+                                           struct cgroup_subsys_state *rootcss)
 {
        struct css_id *newid;
-       struct cgroup_subsys_state *rootcss;
 
        spin_lock_init(&ss->id_lock);
        idr_init(&ss->idr);
 
-       rootcss = init_css_set.subsys[ss->subsys_id];
        newid = get_new_cssid(ss, 0);
        if (IS_ERR(newid))
                return PTR_ERR(newid);
@@ -4010,6 +4600,7 @@ struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id)
 
        return rcu_dereference(cssid->css);
 }
+EXPORT_SYMBOL_GPL(css_lookup);
 
 /**
  * css_get_next - lookup next cgroup under specified hierarchy.
index b0ec34a..1beb6c3 100644 (file)
@@ -833,17 +833,6 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig)
        /* Thread group counters. */
        thread_group_cputime_init(sig);
 
-       /* Expiration times and increments. */
-       sig->it[CPUCLOCK_PROF].expires = cputime_zero;
-       sig->it[CPUCLOCK_PROF].incr = cputime_zero;
-       sig->it[CPUCLOCK_VIRT].expires = cputime_zero;
-       sig->it[CPUCLOCK_VIRT].incr = cputime_zero;
-
-       /* Cached expiration times. */
-       sig->cputime_expires.prof_exp = cputime_zero;
-       sig->cputime_expires.virt_exp = cputime_zero;
-       sig->cputime_expires.sched_exp = 0;
-
        cpu_limit = ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur);
        if (cpu_limit != RLIM_INFINITY) {
                sig->cputime_expires.prof_exp = secs_to_cputime(cpu_limit);
@@ -863,7 +852,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        if (clone_flags & CLONE_THREAD)
                return 0;
 
-       sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
+       sig = kmem_cache_zalloc(signal_cachep, GFP_KERNEL);
        tsk->signal = sig;
        if (!sig)
                return -ENOMEM;
@@ -871,46 +860,21 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        atomic_set(&sig->count, 1);
        atomic_set(&sig->live, 1);
        init_waitqueue_head(&sig->wait_chldexit);
-       sig->flags = 0;
        if (clone_flags & CLONE_NEWPID)
                sig->flags |= SIGNAL_UNKILLABLE;
-       sig->group_exit_code = 0;
-       sig->group_exit_task = NULL;
-       sig->group_stop_count = 0;
        sig->curr_target = tsk;
        init_sigpending(&sig->shared_pending);
        INIT_LIST_HEAD(&sig->posix_timers);
 
        hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       sig->it_real_incr.tv64 = 0;
        sig->real_timer.function = it_real_fn;
 
-       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;
-       sig->cgtime = cputime_zero;
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-       sig->prev_utime = sig->prev_stime = cputime_zero;
-#endif
-       sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
-       sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
-       sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
-       sig->maxrss = sig->cmaxrss = 0;
-       task_io_accounting_init(&sig->ioac);
-       sig->sum_sched_runtime = 0;
-       taskstats_tgid_init(sig);
-
        task_lock(current->group_leader);
        memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
        task_unlock(current->group_leader);
 
        posix_cpu_timers_init_group(sig);
 
-       acct_init_pacct(&sig->pacct);
-
        tty_audit_fork(sig);
 
        sig->oom_adj = current->signal->oom_adj;
index e5538d5..c968d36 100644 (file)
@@ -1085,6 +1085,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
                if (sattr->name == NULL)
                        goto out;
                sect_attrs->nsections++;
+               sysfs_attr_init(&sattr->mattr.attr);
                sattr->mattr.show = module_sect_show;
                sattr->mattr.store = NULL;
                sattr->mattr.attr.name = sattr->name;
@@ -1180,6 +1181,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
                if (sect_empty(&sechdrs[i]))
                        continue;
                if (sechdrs[i].sh_type == SHT_NOTE) {
+                       sysfs_bin_attr_init(nattr);
                        nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
                        nattr->attr.mode = S_IRUGO;
                        nattr->size = sechdrs[i].sh_size;
@@ -1252,6 +1254,7 @@ int module_add_modinfo_attrs(struct module *mod)
                if (!attr->test ||
                    (attr->test && attr->test(mod))) {
                        memcpy(temp_attr, attr, sizeof(*temp_attr));
+                       sysfs_attr_init(&temp_attr->attr);
                        error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
                        ++temp_attr;
                }
index 09b4ff9..2ab6723 100644 (file)
 
 static struct kmem_cache *nsproxy_cachep;
 
-struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
+struct nsproxy init_nsproxy = {
+       .count  = ATOMIC_INIT(1),
+       .uts_ns = &init_uts_ns,
+#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
+       .ipc_ns = &init_ipc_ns,
+#endif
+       .mnt_ns = NULL,
+       .pid_ns = &init_pid_ns,
+#ifdef CONFIG_NET
+       .net_ns = &init_net,
+#endif
+};
 
 static inline struct nsproxy *create_nsproxy(void)
 {
index 8d95f54..d55a53e 100644 (file)
@@ -516,6 +516,7 @@ static __modinit int add_sysfs_param(struct module_kobject *mk,
        new->grp.attrs = attrs;
 
        /* Tack new one on the end. */
+       sysfs_attr_init(&new->attrs[num].mattr.attr);
        new->attrs[num].param = kp;
        new->attrs[num].mattr.show = param_attr_show;
        new->attrs[num].mattr.store = param_attr_store;
@@ -722,7 +723,7 @@ static ssize_t module_attr_store(struct kobject *kobj,
        return ret;
 }
 
-static struct sysfs_ops module_sysfs_ops = {
+static const struct sysfs_ops module_sysfs_ops = {
        .show = module_attr_show,
        .store = module_attr_store,
 };
@@ -736,7 +737,7 @@ static int uevent_filter(struct kset *kset, struct kobject *kobj)
        return 0;
 }
 
-static struct kset_uevent_ops module_uevent_ops = {
+static const struct kset_uevent_ops module_uevent_ops = {
        .filter = uevent_filter,
 };
 
index 8e352c7..f40560b 100644 (file)
@@ -5481,13 +5481,16 @@ void __init perf_event_init(void)
        register_cpu_notifier(&perf_cpu_nb);
 }
 
-static ssize_t perf_show_reserve_percpu(struct sysdev_class *class, char *buf)
+static ssize_t perf_show_reserve_percpu(struct sysdev_class *class,
+                                       struct sysdev_class_attribute *attr,
+                                       char *buf)
 {
        return sprintf(buf, "%d\n", perf_reserved_percpu);
 }
 
 static ssize_t
 perf_set_reserve_percpu(struct sysdev_class *class,
+                       struct sysdev_class_attribute *attr,
                        const char *buf,
                        size_t count)
 {
@@ -5516,13 +5519,17 @@ perf_set_reserve_percpu(struct sysdev_class *class,
        return count;
 }
 
-static ssize_t perf_show_overcommit(struct sysdev_class *class, char *buf)
+static ssize_t perf_show_overcommit(struct sysdev_class *class,
+                                   struct sysdev_class_attribute *attr,
+                                   char *buf)
 {
        return sprintf(buf, "%d\n", perf_overcommit);
 }
 
 static ssize_t
-perf_set_overcommit(struct sysdev_class *class, const char *buf, size_t count)
+perf_set_overcommit(struct sysdev_class *class,
+                   struct sysdev_class_attribute *attr,
+                   const char *buf, size_t count)
 {
        unsigned long val;
        int err;
index 86b3796..79aac93 100644 (file)
@@ -161,13 +161,12 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
                rcu_read_lock();
 
                /*
-                * Use force_sig() since it clears SIGNAL_UNKILLABLE ensuring
-                * any nested-container's init processes don't ignore the
-                * signal
+                * Any nested-container's init processes won't ignore the
+                * SEND_SIG_NOINFO signal, see send_signal()->si_fromuser().
                 */
                task = pid_task(find_vpid(nr), PIDTYPE_PID);
                if (task)
-                       force_sig(SIGKILL, task);
+                       send_sig_info(SIGKILL, SEND_SIG_NOINFO, task);
 
                rcu_read_unlock();
 
index b47ceee..150b698 100644 (file)
@@ -7406,11 +7406,13 @@ static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
 
 #ifdef CONFIG_SCHED_MC
 static ssize_t sched_mc_power_savings_show(struct sysdev_class *class,
+                                          struct sysdev_class_attribute *attr,
                                           char *page)
 {
        return sprintf(page, "%u\n", sched_mc_power_savings);
 }
 static ssize_t sched_mc_power_savings_store(struct sysdev_class *class,
+                                           struct sysdev_class_attribute *attr,
                                            const char *buf, size_t count)
 {
        return sched_power_savings_store(buf, count, 0);
@@ -7422,11 +7424,13 @@ static SYSDEV_CLASS_ATTR(sched_mc_power_savings, 0644,
 
 #ifdef CONFIG_SCHED_SMT
 static ssize_t sched_smt_power_savings_show(struct sysdev_class *dev,
+                                           struct sysdev_class_attribute *attr,
                                            char *page)
 {
        return sprintf(page, "%u\n", sched_smt_power_savings);
 }
 static ssize_t sched_smt_power_savings_store(struct sysdev_class *dev,
+                                            struct sysdev_class_attribute *attr,
                                             const char *buf, size_t count)
 {
        return sched_power_savings_store(buf, count, 1);
index 9814e43..8298878 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
+#include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/fs_struct.h>
 
@@ -1114,6 +1115,15 @@ out:
 
 DECLARE_RWSEM(uts_sem);
 
+#ifdef COMPAT_UTS_MACHINE
+#define override_architecture(name) \
+       (current->personality == PER_LINUX32 && \
+        copy_to_user(name->machine, COMPAT_UTS_MACHINE, \
+                     sizeof(COMPAT_UTS_MACHINE)))
+#else
+#define override_architecture(name)    0
+#endif
+
 SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
        int errno = 0;
@@ -1122,9 +1132,66 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
        if (copy_to_user(name, utsname(), sizeof *name))
                errno = -EFAULT;
        up_read(&uts_sem);
+
+       if (!errno && override_architecture(name))
+               errno = -EFAULT;
        return errno;
 }
 
+#ifdef __ARCH_WANT_SYS_OLD_UNAME
+/*
+ * Old cruft
+ */
+SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
+{
+       int error = 0;
+
+       if (!name)
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       if (copy_to_user(name, utsname(), sizeof(*name)))
+               error = -EFAULT;
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error;
+}
+
+SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
+{
+       int error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       error = __copy_to_user(&name->sysname, &utsname()->sysname,
+                              __OLD_UTS_LEN);
+       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->release, &utsname()->release,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->release + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->version, &utsname()->version,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->version + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->machine, &utsname()->machine,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error ? -EFAULT : 0;
+}
+#endif
+
 SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
 {
        int errno;
index 695384f..70f2ea7 100644 (file)
@@ -126,6 +126,7 @@ cond_syscall(sys_setreuid16);
 cond_syscall(sys_setuid16);
 cond_syscall(sys_vm86old);
 cond_syscall(sys_vm86);
+cond_syscall(sys_ipc);
 cond_syscall(compat_sys_ipc);
 cond_syscall(compat_sys_sysctl);
 cond_syscall(sys_flock);
index 0ef19c6..8686b0f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
+#include <linux/signal.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
 #include <linux/ctype.h>
 #include <asm/stacktrace.h>
 #include <asm/io.h>
 #endif
+#ifdef CONFIG_BSD_PROCESS_ACCT
+#include <linux/acct.h>
+#endif
+#ifdef CONFIG_RT_MUTEXES
+#include <linux/rtmutex.h>
+#endif
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_LOCK_STAT)
+#include <linux/lockdep.h>
+#endif
+#ifdef CONFIG_CHR_DEV_SG
+#include <scsi/sg.h>
+#endif
 
 
 #if defined(CONFIG_SYSCTL)
 
 /* External variables not in a header file. */
-extern int C_A_D;
-extern int print_fatal_signals;
 extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern int sysctl_panic_on_oom;
@@ -88,9 +99,6 @@ extern int sysctl_nr_open_min, sysctl_nr_open_max;
 #ifndef CONFIG_MMU
 extern int sysctl_nr_trim_pages;
 #endif
-#ifdef CONFIG_RCU_TORTURE_TEST
-extern int rcutorture_runnable;
-#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 #ifdef CONFIG_BLOCK
 extern int blk_iopoll_enabled;
 #endif
@@ -120,14 +128,6 @@ static int min_percpu_pagelist_fract = 8;
 
 static int ngroups_max = NGROUPS_MAX;
 
-#ifdef CONFIG_MODULES
-extern char modprobe_path[];
-extern int modules_disabled;
-#endif
-#ifdef CONFIG_CHR_DEV_SG
-extern int sg_big_buff;
-#endif
-
 #ifdef CONFIG_SPARC
 #include <asm/system.h>
 #endif
@@ -149,10 +149,6 @@ extern int sysctl_userprocess_debug;
 extern int spin_retry;
 #endif
 
-#ifdef CONFIG_BSD_PROCESS_ACCT
-extern int acct_parm[];
-#endif
-
 #ifdef CONFIG_IA64
 extern int no_unaligned_warning;
 extern int unaligned_dump_stack;
@@ -160,10 +156,6 @@ extern int unaligned_dump_stack;
 
 extern struct ratelimit_state printk_ratelimit_state;
 
-#ifdef CONFIG_RT_MUTEXES
-extern int max_lock_depth;
-#endif
-
 #ifdef CONFIG_PROC_SYSCTL
 static int proc_do_cad_pid(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -202,9 +194,6 @@ extern struct ctl_table epoll_table[];
 int sysctl_legacy_va_layout;
 #endif
 
-extern int prove_locking;
-extern int lock_stat;
-
 /* The default sysctl tables: */
 
 static struct ctl_table root_table[] = {
index b512b74..8115eb1 100644 (file)
@@ -700,7 +700,7 @@ static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
        return ret;
 }
 
-struct sysfs_ops kobj_sysfs_ops = {
+const struct sysfs_ops kobj_sysfs_ops = {
        .show   = kobj_attr_show,
        .store  = kobj_attr_store,
 };
@@ -789,7 +789,7 @@ static struct kobj_type kset_ktype = {
  * If the kset was not able to be created, NULL will be returned.
  */
 static struct kset *kset_create(const char *name,
-                               struct kset_uevent_ops *uevent_ops,
+                               const struct kset_uevent_ops *uevent_ops,
                                struct kobject *parent_kobj)
 {
        struct kset *kset;
@@ -832,7 +832,7 @@ static struct kset *kset_create(const char *name,
  * If the kset was not able to be created, NULL will be returned.
  */
 struct kset *kset_create_and_add(const char *name,
-                                struct kset_uevent_ops *uevent_ops,
+                                const struct kset_uevent_ops *uevent_ops,
                                 struct kobject *parent_kobj)
 {
        struct kset *kset;
index 920a3ca..c9d3a3e 100644 (file)
@@ -95,7 +95,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        const char *subsystem;
        struct kobject *top_kobj;
        struct kset *kset;
-       struct kset_uevent_ops *uevent_ops;
+       const struct kset_uevent_ops *uevent_ops;
        u64 seq;
        int i = 0;
        int retval = 0;
index 215447c..2c13ecc 100644 (file)
@@ -8,21 +8,6 @@
 #include "inflate.h"
 #include "inffast.h"
 
-/* Only do the unaligned "Faster" variant when
- * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set
- *
- * On powerpc, it won't be as we don't include autoconf.h
- * automatically for the boot wrapper, which is intended as
- * we run in an environment where we may not be able to deal
- * with (even rare) alignment faults. In addition, we do not
- * define __KERNEL__ for arch/powerpc/boot unlike x86
- */
-
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#endif
-
 #ifndef ASMINF
 
 /* Allow machine dependent optimization for post-increment or pre-increment.
    - Pentium III (Anderson)
    - M68060 (Nikl)
  */
+union uu {
+       unsigned short us;
+       unsigned char b[2];
+};
+
+/* Endian independed version */
+static inline unsigned short
+get_unaligned16(const unsigned short *p)
+{
+       union uu  mm;
+       unsigned char *b = (unsigned char *)p;
+
+       mm.b[0] = b[0];
+       mm.b[1] = b[1];
+       return mm.us;
+}
+
 #ifdef POSTINC
 #  define OFF 0
 #  define PUP(a) *(a)++
-#  define UP_UNALIGNED(a) get_unaligned((a)++)
+#  define UP_UNALIGNED(a) get_unaligned16((a)++)
 #else
 #  define OFF 1
 #  define PUP(a) *++(a)
-#  define UP_UNALIGNED(a) get_unaligned(++(a))
+#  define UP_UNALIGNED(a) get_unaligned16(++(a))
 #endif
 
 /*
@@ -256,7 +258,6 @@ void inflate_fast(z_streamp strm, unsigned start)
                     }
                 }
                 else {
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                    unsigned short *sout;
                    unsigned long loops;
 
@@ -274,22 +275,25 @@ void inflate_fast(z_streamp strm, unsigned start)
                        sfrom = (unsigned short *)(from - OFF);
                        loops = len >> 1;
                        do
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+                           PUP(sout) = PUP(sfrom);
+#else
                            PUP(sout) = UP_UNALIGNED(sfrom);
+#endif
                        while (--loops);
                        out = (unsigned char *)sout + OFF;
                        from = (unsigned char *)sfrom + OFF;
                    } else { /* dist == 1 or dist == 2 */
                        unsigned short pat16;
 
-                       pat16 = *(sout-2+2*OFF);
-                       if (dist == 1)
-#if defined(__BIG_ENDIAN)
-                           pat16 = (pat16 & 0xff) | ((pat16 & 0xff) << 8);
-#elif defined(__LITTLE_ENDIAN)
-                           pat16 = (pat16 & 0xff00) | ((pat16 & 0xff00) >> 8);
-#else
-#error __BIG_ENDIAN nor __LITTLE_ENDIAN is defined
-#endif
+                       pat16 = *(sout-1+OFF);
+                       if (dist == 1) {
+                               union uu mm;
+                               /* copy one char pattern to both bytes */
+                               mm.us = pat16;
+                               mm.b[0] = mm.b[1];
+                               pat16 = mm.us;
+                       }
                        loops = len >> 1;
                        do
                            PUP(sout) = pat16;
@@ -298,20 +302,6 @@ void inflate_fast(z_streamp strm, unsigned start)
                    }
                    if (len & 1)
                        PUP(out) = PUP(from);
-#else /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
-                    from = out - dist;          /* copy direct from output */
-                    do {                        /* minimum length is three */
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        len -= 3;
-                    } while (len > 2);
-                    if (len) {
-                        PUP(out) = PUP(from);
-                        if (len > 1)
-                            PUP(out) = PUP(from);
-                    }
-#endif /* !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
                 }
             }
             else if ((op & 64) == 0) {          /* 2nd level distance code */
index d813823..7973b52 100644 (file)
@@ -6,6 +6,10 @@
  * Copyright 2007 OpenVZ SWsoft Inc
  * Author: Pavel Emelianov <xemul@openvz.org>
  *
+ * Memory thresholds
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Kirill A. Shutemov
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,6 +25,7 @@
 #include <linux/memcontrol.h>
 #include <linux/cgroup.h>
 #include <linux/mm.h>
+#include <linux/hugetlb.h>
 #include <linux/pagemap.h>
 #include <linux/smp.h>
 #include <linux/page-flags.h>
 #include <linux/rbtree.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
+#include <linux/swapops.h>
 #include <linux/spinlock.h>
+#include <linux/eventfd.h>
+#include <linux/sort.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/vmalloc.h>
@@ -55,7 +63,15 @@ static int really_do_swap_account __initdata = 1; /* for remember boot option*/
 #define do_swap_account                (0)
 #endif
 
-#define SOFTLIMIT_EVENTS_THRESH (1000)
+/*
+ * Per memcg event counter is incremented at every pagein/pageout. This counter
+ * is used for trigger some periodic events. This is straightforward and better
+ * than using jiffies etc. to handle periodic memcg event.
+ *
+ * These values will be used as !((event) & ((1 <<(thresh)) - 1))
+ */
+#define THRESHOLDS_EVENTS_THRESH (7) /* once in 128 */
+#define SOFTLIMIT_EVENTS_THRESH (10) /* once in 1024 */
 
 /*
  * Statistics for memory cgroup.
@@ -69,62 +85,16 @@ enum mem_cgroup_stat_index {
        MEM_CGROUP_STAT_FILE_MAPPED,  /* # of pages charged as file rss */
        MEM_CGROUP_STAT_PGPGIN_COUNT,   /* # of pages paged in */
        MEM_CGROUP_STAT_PGPGOUT_COUNT,  /* # of pages paged out */
-       MEM_CGROUP_STAT_EVENTS, /* sum of pagein + pageout for internal use */
        MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
+       MEM_CGROUP_EVENTS,      /* incremented at every  pagein/pageout */
 
        MEM_CGROUP_STAT_NSTATS,
 };
 
 struct mem_cgroup_stat_cpu {
        s64 count[MEM_CGROUP_STAT_NSTATS];
-} ____cacheline_aligned_in_smp;
-
-struct mem_cgroup_stat {
-       struct mem_cgroup_stat_cpu cpustat[0];
 };
 
-static inline void
-__mem_cgroup_stat_reset_safe(struct mem_cgroup_stat_cpu *stat,
-                               enum mem_cgroup_stat_index idx)
-{
-       stat->count[idx] = 0;
-}
-
-static inline s64
-__mem_cgroup_stat_read_local(struct mem_cgroup_stat_cpu *stat,
-                               enum mem_cgroup_stat_index idx)
-{
-       return stat->count[idx];
-}
-
-/*
- * For accounting under irq disable, no need for increment preempt count.
- */
-static inline void __mem_cgroup_stat_add_safe(struct mem_cgroup_stat_cpu *stat,
-               enum mem_cgroup_stat_index idx, int val)
-{
-       stat->count[idx] += val;
-}
-
-static s64 mem_cgroup_read_stat(struct mem_cgroup_stat *stat,
-               enum mem_cgroup_stat_index idx)
-{
-       int cpu;
-       s64 ret = 0;
-       for_each_possible_cpu(cpu)
-               ret += stat->cpustat[cpu].count[idx];
-       return ret;
-}
-
-static s64 mem_cgroup_local_usage(struct mem_cgroup_stat *stat)
-{
-       s64 ret;
-
-       ret = mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_CACHE);
-       ret += mem_cgroup_read_stat(stat, MEM_CGROUP_STAT_RSS);
-       return ret;
-}
-
 /*
  * per-zone information in memory controller.
  */
@@ -174,6 +144,22 @@ struct mem_cgroup_tree {
 
 static struct mem_cgroup_tree soft_limit_tree __read_mostly;
 
+struct mem_cgroup_threshold {
+       struct eventfd_ctx *eventfd;
+       u64 threshold;
+};
+
+struct mem_cgroup_threshold_ary {
+       /* An array index points to threshold just below usage. */
+       atomic_t current_threshold;
+       /* Size of entries[] */
+       unsigned int size;
+       /* Array of thresholds */
+       struct mem_cgroup_threshold entries[0];
+};
+
+static void mem_cgroup_threshold(struct mem_cgroup *mem);
+
 /*
  * The memory controller data structure. The memory controller controls both
  * page cache and RSS per cgroup. We would eventually like to provide
@@ -217,7 +203,7 @@ struct mem_cgroup {
         * Should the accounting and control be hierarchical, per subtree?
         */
        bool use_hierarchy;
-       unsigned long   last_oom_jiffies;
+       atomic_t        oom_lock;
        atomic_t        refcnt;
 
        unsigned int    swappiness;
@@ -225,10 +211,48 @@ struct mem_cgroup {
        /* set when res.limit == memsw.limit */
        bool            memsw_is_minimum;
 
+       /* protect arrays of thresholds */
+       struct mutex thresholds_lock;
+
+       /* thresholds for memory usage. RCU-protected */
+       struct mem_cgroup_threshold_ary *thresholds;
+
+       /* thresholds for mem+swap usage. RCU-protected */
+       struct mem_cgroup_threshold_ary *memsw_thresholds;
+
        /*
-        * statistics. This must be placed at the end of memcg.
+        * Should we move charges of a task when a task is moved into this
+        * mem_cgroup ? And what type of charges should we move ?
         */
-       struct mem_cgroup_stat stat;
+       unsigned long   move_charge_at_immigrate;
+
+       /*
+        * percpu counter.
+        */
+       struct mem_cgroup_stat_cpu *stat;
+};
+
+/* Stuffs for move charges at task migration. */
+/*
+ * Types of charges to be moved. "move_charge_at_immitgrate" is treated as a
+ * left-shifted bitmap of these types.
+ */
+enum move_type {
+       MOVE_CHARGE_TYPE_ANON,  /* private anonymous page and swap of it */
+       NR_MOVE_TYPE,
+};
+
+/* "mc" and its members are protected by cgroup_mutex */
+static struct move_charge_struct {
+       struct mem_cgroup *from;
+       struct mem_cgroup *to;
+       unsigned long precharge;
+       unsigned long moved_charge;
+       unsigned long moved_swap;
+       struct task_struct *moving_task;        /* a task moving charges */
+       wait_queue_head_t waitq;                /* a waitq for other context */
+} mc = {
+       .waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq),
 };
 
 /*
@@ -371,23 +395,6 @@ mem_cgroup_remove_exceeded(struct mem_cgroup *mem,
        spin_unlock(&mctz->lock);
 }
 
-static bool mem_cgroup_soft_limit_check(struct mem_cgroup *mem)
-{
-       bool ret = false;
-       int cpu;
-       s64 val;
-       struct mem_cgroup_stat_cpu *cpustat;
-
-       cpu = get_cpu();
-       cpustat = &mem->stat.cpustat[cpu];
-       val = __mem_cgroup_stat_read_local(cpustat, MEM_CGROUP_STAT_EVENTS);
-       if (unlikely(val > SOFTLIMIT_EVENTS_THRESH)) {
-               __mem_cgroup_stat_reset_safe(cpustat, MEM_CGROUP_STAT_EVENTS);
-               ret = true;
-       }
-       put_cpu();
-       return ret;
-}
 
 static void mem_cgroup_update_tree(struct mem_cgroup *mem, struct page *page)
 {
@@ -481,17 +488,31 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
        return mz;
 }
 
+static s64 mem_cgroup_read_stat(struct mem_cgroup *mem,
+               enum mem_cgroup_stat_index idx)
+{
+       int cpu;
+       s64 val = 0;
+
+       for_each_possible_cpu(cpu)
+               val += per_cpu(mem->stat->count[idx], cpu);
+       return val;
+}
+
+static s64 mem_cgroup_local_usage(struct mem_cgroup *mem)
+{
+       s64 ret;
+
+       ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS);
+       ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE);
+       return ret;
+}
+
 static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
                                         bool charge)
 {
        int val = (charge) ? 1 : -1;
-       struct mem_cgroup_stat *stat = &mem->stat;
-       struct mem_cgroup_stat_cpu *cpustat;
-       int cpu = get_cpu();
-
-       cpustat = &stat->cpustat[cpu];
-       __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_SWAPOUT, val);
-       put_cpu();
+       this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
 }
 
 static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
@@ -499,24 +520,21 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
                                         bool charge)
 {
        int val = (charge) ? 1 : -1;
-       struct mem_cgroup_stat *stat = &mem->stat;
-       struct mem_cgroup_stat_cpu *cpustat;
-       int cpu = get_cpu();
 
-       cpustat = &stat->cpustat[cpu];
+       preempt_disable();
+
        if (PageCgroupCache(pc))
-               __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_CACHE, val);
+               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_CACHE], val);
        else
-               __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_RSS, val);
+               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_RSS], val);
 
        if (charge)
-               __mem_cgroup_stat_add_safe(cpustat,
-                               MEM_CGROUP_STAT_PGPGIN_COUNT, 1);
+               __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
        else
-               __mem_cgroup_stat_add_safe(cpustat,
-                               MEM_CGROUP_STAT_PGPGOUT_COUNT, 1);
-       __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_EVENTS, 1);
-       put_cpu();
+               __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
+       __this_cpu_inc(mem->stat->count[MEM_CGROUP_EVENTS]);
+
+       preempt_enable();
 }
 
 static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
@@ -534,6 +552,29 @@ static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
        return total;
 }
 
+static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift)
+{
+       s64 val;
+
+       val = this_cpu_read(mem->stat->count[MEM_CGROUP_EVENTS]);
+
+       return !(val & ((1 << event_mask_shift) - 1));
+}
+
+/*
+ * Check events in order.
+ *
+ */
+static void memcg_check_events(struct mem_cgroup *mem, struct page *page)
+{
+       /* threshold event is triggered in finer grain than soft limit */
+       if (unlikely(__memcg_event_check(mem, THRESHOLDS_EVENTS_THRESH))) {
+               mem_cgroup_threshold(mem);
+               if (unlikely(__memcg_event_check(mem, SOFTLIMIT_EVENTS_THRESH)))
+                       mem_cgroup_update_tree(mem, page);
+       }
+}
+
 static struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont)
 {
        return container_of(cgroup_subsys_state(cont,
@@ -1000,7 +1041,7 @@ static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data)
 }
 
 /**
- * mem_cgroup_print_mem_info: Called from OOM with tasklist_lock held in read mode.
+ * mem_cgroup_print_oom_info: Called from OOM with tasklist_lock held in read mode.
  * @memcg: The memory cgroup that went over limit
  * @p: Task that is going to be killed
  *
@@ -1174,7 +1215,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
                                }
                        }
                }
-               if (!mem_cgroup_local_usage(&victim->stat)) {
+               if (!mem_cgroup_local_usage(victim)) {
                        /* this cgroup's local usage == 0 */
                        css_put(&victim->css);
                        continue;
@@ -1205,32 +1246,102 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
        return total;
 }
 
-bool mem_cgroup_oom_called(struct task_struct *task)
+static int mem_cgroup_oom_lock_cb(struct mem_cgroup *mem, void *data)
 {
-       bool ret = false;
-       struct mem_cgroup *mem;
-       struct mm_struct *mm;
+       int *val = (int *)data;
+       int x;
+       /*
+        * Logically, we can stop scanning immediately when we find
+        * a memcg is already locked. But condidering unlock ops and
+        * creation/removal of memcg, scan-all is simple operation.
+        */
+       x = atomic_inc_return(&mem->oom_lock);
+       *val = max(x, *val);
+       return 0;
+}
+/*
+ * Check OOM-Killer is already running under our hierarchy.
+ * If someone is running, return false.
+ */
+static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
+{
+       int lock_count = 0;
 
-       rcu_read_lock();
-       mm = task->mm;
-       if (!mm)
-               mm = &init_mm;
-       mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
-       if (mem && time_before(jiffies, mem->last_oom_jiffies + HZ/10))
-               ret = true;
-       rcu_read_unlock();
-       return ret;
+       mem_cgroup_walk_tree(mem, &lock_count, mem_cgroup_oom_lock_cb);
+
+       if (lock_count == 1)
+               return true;
+       return false;
 }
 
-static int record_last_oom_cb(struct mem_cgroup *mem, void *data)
+static int mem_cgroup_oom_unlock_cb(struct mem_cgroup *mem, void *data)
 {
-       mem->last_oom_jiffies = jiffies;
+       /*
+        * When a new child is created while the hierarchy is under oom,
+        * mem_cgroup_oom_lock() may not be called. We have to use
+        * atomic_add_unless() here.
+        */
+       atomic_add_unless(&mem->oom_lock, -1, 0);
        return 0;
 }
 
-static void record_last_oom(struct mem_cgroup *mem)
+static void mem_cgroup_oom_unlock(struct mem_cgroup *mem)
 {
-       mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb);
+       mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_unlock_cb);
+}
+
+static DEFINE_MUTEX(memcg_oom_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
+
+/*
+ * try to call OOM killer. returns false if we should exit memory-reclaim loop.
+ */
+bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
+{
+       DEFINE_WAIT(wait);
+       bool locked;
+
+       /* At first, try to OOM lock hierarchy under mem.*/
+       mutex_lock(&memcg_oom_mutex);
+       locked = mem_cgroup_oom_lock(mem);
+       /*
+        * Even if signal_pending(), we can't quit charge() loop without
+        * accounting. So, UNINTERRUPTIBLE is appropriate. But SIGKILL
+        * under OOM is always welcomed, use TASK_KILLABLE here.
+        */
+       if (!locked)
+               prepare_to_wait(&memcg_oom_waitq, &wait, TASK_KILLABLE);
+       mutex_unlock(&memcg_oom_mutex);
+
+       if (locked)
+               mem_cgroup_out_of_memory(mem, mask);
+       else {
+               schedule();
+               finish_wait(&memcg_oom_waitq, &wait);
+       }
+       mutex_lock(&memcg_oom_mutex);
+       mem_cgroup_oom_unlock(mem);
+       /*
+        * Here, we use global waitq .....more fine grained waitq ?
+        * Assume following hierarchy.
+        * A/
+        *   01
+        *   02
+        * assume OOM happens both in A and 01 at the same time. Tthey are
+        * mutually exclusive by lock. (kill in 01 helps A.)
+        * When we use per memcg waitq, we have to wake up waiters on A and 02
+        * in addtion to waiters on 01. We use global waitq for avoiding mess.
+        * It will not be a big problem.
+        * (And a task may be moved to other groups while it's waiting for OOM.)
+        */
+       wake_up_all(&memcg_oom_waitq);
+       mutex_unlock(&memcg_oom_mutex);
+
+       if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
+               return false;
+       /* Give chance to dying process */
+       schedule_timeout(1);
+       return true;
 }
 
 /*
@@ -1240,9 +1351,6 @@ static void record_last_oom(struct mem_cgroup *mem)
 void mem_cgroup_update_file_mapped(struct page *page, int val)
 {
        struct mem_cgroup *mem;
-       struct mem_cgroup_stat *stat;
-       struct mem_cgroup_stat_cpu *cpustat;
-       int cpu;
        struct page_cgroup *pc;
 
        pc = lookup_page_cgroup(page);
@@ -1258,13 +1366,10 @@ void mem_cgroup_update_file_mapped(struct page *page, int val)
                goto done;
 
        /*
-        * Preemption is already disabled, we don't need get_cpu()
+        * Preemption is already disabled. We can use __this_cpu_xxx
         */
-       cpu = smp_processor_id();
-       stat = &mem->stat;
-       cpustat = &stat->cpustat[cpu];
+       __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_FILE_MAPPED], val);
 
-       __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED, val);
 done:
        unlock_page_cgroup(pc);
 }
@@ -1401,19 +1506,21 @@ static int __cpuinit memcg_stock_cpu_callback(struct notifier_block *nb,
  * oom-killer can be invoked.
  */
 static int __mem_cgroup_try_charge(struct mm_struct *mm,
-                       gfp_t gfp_mask, struct mem_cgroup **memcg,
-                       bool oom, struct page *page)
+                       gfp_t gfp_mask, struct mem_cgroup **memcg, bool oom)
 {
        struct mem_cgroup *mem, *mem_over_limit;
        int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
        struct res_counter *fail_res;
        int csize = CHARGE_SIZE;
 
-       if (unlikely(test_thread_flag(TIF_MEMDIE))) {
-               /* Don't account this! */
-               *memcg = NULL;
-               return 0;
-       }
+       /*
+        * Unlike gloval-vm's OOM-kill, we're not in memory shortage
+        * in system level. So, allow to go ahead dying process in addition to
+        * MEMDIE process.
+        */
+       if (unlikely(test_thread_flag(TIF_MEMDIE)
+                    || fatal_signal_pending(current)))
+               goto bypass;
 
        /*
         * We always charge the cgroup the mm_struct belongs to.
@@ -1440,7 +1547,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                unsigned long flags = 0;
 
                if (consume_stock(mem))
-                       goto charged;
+                       goto done;
 
                ret = res_counter_charge(&mem->res, csize, &fail_res);
                if (likely(!ret)) {
@@ -1483,28 +1590,70 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                if (mem_cgroup_check_under_limit(mem_over_limit))
                        continue;
 
+               /* try to avoid oom while someone is moving charge */
+               if (mc.moving_task && current != mc.moving_task) {
+                       struct mem_cgroup *from, *to;
+                       bool do_continue = false;
+                       /*
+                        * There is a small race that "from" or "to" can be
+                        * freed by rmdir, so we use css_tryget().
+                        */
+                       rcu_read_lock();
+                       from = mc.from;
+                       to = mc.to;
+                       if (from && css_tryget(&from->css)) {
+                               if (mem_over_limit->use_hierarchy)
+                                       do_continue = css_is_ancestor(
+                                                       &from->css,
+                                                       &mem_over_limit->css);
+                               else
+                                       do_continue = (from == mem_over_limit);
+                               css_put(&from->css);
+                       }
+                       if (!do_continue && to && css_tryget(&to->css)) {
+                               if (mem_over_limit->use_hierarchy)
+                                       do_continue = css_is_ancestor(
+                                                       &to->css,
+                                                       &mem_over_limit->css);
+                               else
+                                       do_continue = (to == mem_over_limit);
+                               css_put(&to->css);
+                       }
+                       rcu_read_unlock();
+                       if (do_continue) {
+                               DEFINE_WAIT(wait);
+                               prepare_to_wait(&mc.waitq, &wait,
+                                                       TASK_INTERRUPTIBLE);
+                               /* moving charge context might have finished. */
+                               if (mc.moving_task)
+                                       schedule();
+                               finish_wait(&mc.waitq, &wait);
+                               continue;
+                       }
+               }
+
                if (!nr_retries--) {
-                       if (oom) {
-                               mem_cgroup_out_of_memory(mem_over_limit, gfp_mask);
-                               record_last_oom(mem_over_limit);
+                       if (!oom)
+                               goto nomem;
+                       if (mem_cgroup_handle_oom(mem_over_limit, gfp_mask)) {
+                               nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
+                               continue;
                        }
-                       goto nomem;
+                       /* When we reach here, current task is dying .*/
+                       css_put(&mem->css);
+                       goto bypass;
                }
        }
        if (csize > PAGE_SIZE)
                refill_stock(mem, csize - PAGE_SIZE);
-charged:
-       /*
-        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
-        * if they exceeds softlimit.
-        */
-       if (mem_cgroup_soft_limit_check(mem))
-               mem_cgroup_update_tree(mem, page);
 done:
        return 0;
 nomem:
        css_put(&mem->css);
        return -ENOMEM;
+bypass:
+       *memcg = NULL;
+       return 0;
 }
 
 /*
@@ -1512,14 +1661,23 @@ nomem:
  * This function is for that and do uncharge, put css's refcnt.
  * gotten by try_charge().
  */
-static void mem_cgroup_cancel_charge(struct mem_cgroup *mem)
+static void __mem_cgroup_cancel_charge(struct mem_cgroup *mem,
+                                                       unsigned long count)
 {
        if (!mem_cgroup_is_root(mem)) {
-               res_counter_uncharge(&mem->res, PAGE_SIZE);
+               res_counter_uncharge(&mem->res, PAGE_SIZE * count);
                if (do_swap_account)
-                       res_counter_uncharge(&mem->memsw, PAGE_SIZE);
+                       res_counter_uncharge(&mem->memsw, PAGE_SIZE * count);
+               VM_BUG_ON(test_bit(CSS_ROOT, &mem->css.flags));
+               WARN_ON_ONCE(count > INT_MAX);
+               __css_put(&mem->css, (int)count);
        }
-       css_put(&mem->css);
+       /* we don't need css_put for root */
+}
+
+static void mem_cgroup_cancel_charge(struct mem_cgroup *mem)
+{
+       __mem_cgroup_cancel_charge(mem, 1);
 }
 
 /*
@@ -1615,6 +1773,12 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
        mem_cgroup_charge_statistics(mem, pc, true);
 
        unlock_page_cgroup(pc);
+       /*
+        * "charge_statistics" updated event counter. Then, check it.
+        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
+        * if they exceeds softlimit.
+        */
+       memcg_check_events(mem, pc->page);
 }
 
 /**
@@ -1622,22 +1786,22 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
  * @pc:        page_cgroup of the page.
  * @from: mem_cgroup which the page is moved from.
  * @to:        mem_cgroup which the page is moved to. @from != @to.
+ * @uncharge: whether we should call uncharge and css_put against @from.
  *
  * The caller must confirm following.
  * - page is not on LRU (isolate_page() is useful.)
  * - the pc is locked, used, and ->mem_cgroup points to @from.
  *
- * This function does "uncharge" from old cgroup but doesn't do "charge" to
- * new cgroup. It should be done by a caller.
+ * This function doesn't do "charge" nor css_get to new cgroup. It should be
+ * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is
+ * true, this function does "uncharge" from old cgroup, but it doesn't if
+ * @uncharge is false, so a caller should do "uncharge".
  */
 
 static void __mem_cgroup_move_account(struct page_cgroup *pc,
-       struct mem_cgroup *from, struct mem_cgroup *to)
+       struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
 {
        struct page *page;
-       int cpu;
-       struct mem_cgroup_stat *stat;
-       struct mem_cgroup_stat_cpu *cpustat;
 
        VM_BUG_ON(from == to);
        VM_BUG_ON(PageLRU(pc->page));
@@ -1645,38 +1809,28 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
        VM_BUG_ON(!PageCgroupUsed(pc));
        VM_BUG_ON(pc->mem_cgroup != from);
 
-       if (!mem_cgroup_is_root(from))
-               res_counter_uncharge(&from->res, PAGE_SIZE);
-       mem_cgroup_charge_statistics(from, pc, false);
-
        page = pc->page;
        if (page_mapped(page) && !PageAnon(page)) {
-               cpu = smp_processor_id();
-               /* Update mapped_file data for mem_cgroup "from" */
-               stat = &from->stat;
-               cpustat = &stat->cpustat[cpu];
-               __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED,
-                                               -1);
-
-               /* Update mapped_file data for mem_cgroup "to" */
-               stat = &to->stat;
-               cpustat = &stat->cpustat[cpu];
-               __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED,
-                                               1);
+               /* Update mapped_file data for mem_cgroup */
+               preempt_disable();
+               __this_cpu_dec(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
+               __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
+               preempt_enable();
        }
+       mem_cgroup_charge_statistics(from, pc, false);
+       if (uncharge)
+               /* This is not "cancel", but cancel_charge does all we need. */
+               mem_cgroup_cancel_charge(from);
 
-       if (do_swap_account && !mem_cgroup_is_root(from))
-               res_counter_uncharge(&from->memsw, PAGE_SIZE);
-       css_put(&from->css);
-
-       css_get(&to->css);
+       /* caller should have done css_get */
        pc->mem_cgroup = to;
        mem_cgroup_charge_statistics(to, pc, true);
        /*
         * We charges against "to" which may not have any tasks. Then, "to"
         * can be under rmdir(). But in current implementation, caller of
-        * this function is just force_empty() and it's garanteed that
-        * "to" is never removed. So, we don't check rmdir status here.
+        * this function is just force_empty() and move charge, so it's
+        * garanteed that "to" is never removed. So, we don't check rmdir
+        * status here.
         */
 }
 
@@ -1685,15 +1839,20 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
  * __mem_cgroup_move_account()
  */
 static int mem_cgroup_move_account(struct page_cgroup *pc,
-                               struct mem_cgroup *from, struct mem_cgroup *to)
+               struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
 {
        int ret = -EINVAL;
        lock_page_cgroup(pc);
        if (PageCgroupUsed(pc) && pc->mem_cgroup == from) {
-               __mem_cgroup_move_account(pc, from, to);
+               __mem_cgroup_move_account(pc, from, to, uncharge);
                ret = 0;
        }
        unlock_page_cgroup(pc);
+       /*
+        * check events
+        */
+       memcg_check_events(to, pc->page);
+       memcg_check_events(from, pc->page);
        return ret;
 }
 
@@ -1722,15 +1881,13 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
                goto put;
 
        parent = mem_cgroup_from_cont(pcg);
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false, page);
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false);
        if (ret || !parent)
                goto put_back;
 
-       ret = mem_cgroup_move_account(pc, child, parent);
-       if (!ret)
-               css_put(&parent->css);  /* drop extra refcnt by try_charge() */
-       else
-               mem_cgroup_cancel_charge(parent);       /* does css_put */
+       ret = mem_cgroup_move_account(pc, child, parent, true);
+       if (ret)
+               mem_cgroup_cancel_charge(parent);
 put_back:
        putback_lru_page(page);
 put:
@@ -1760,7 +1917,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
        prefetchw(pc);
 
        mem = memcg;
-       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true, page);
+       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true);
        if (ret || !mem)
                return ret;
 
@@ -1880,14 +2037,14 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
        if (!mem)
                goto charge_cur_mm;
        *ptr = mem;
-       ret = __mem_cgroup_try_charge(NULL, mask, ptr, true, page);
+       ret = __mem_cgroup_try_charge(NULL, mask, ptr, true);
        /* drop extra refcnt from tryget */
        css_put(&mem->css);
        return ret;
 charge_cur_mm:
        if (unlikely(!mm))
                mm = &init_mm;
-       return __mem_cgroup_try_charge(mm, mask, ptr, true, page);
+       return __mem_cgroup_try_charge(mm, mask, ptr, true);
 }
 
 static void
@@ -2064,8 +2221,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
        mz = page_cgroup_zoneinfo(pc);
        unlock_page_cgroup(pc);
 
-       if (mem_cgroup_soft_limit_check(mem))
-               mem_cgroup_update_tree(mem, page);
+       memcg_check_events(mem, page);
        /* at swapout, this memcg will be accessed to record to swap */
        if (ctype != MEM_CGROUP_CHARGE_TYPE_SWAPOUT)
                css_put(&mem->css);
@@ -2192,6 +2348,64 @@ void mem_cgroup_uncharge_swap(swp_entry_t ent)
        }
        rcu_read_unlock();
 }
+
+/**
+ * mem_cgroup_move_swap_account - move swap charge and swap_cgroup's record.
+ * @entry: swap entry to be moved
+ * @from:  mem_cgroup which the entry is moved from
+ * @to:  mem_cgroup which the entry is moved to
+ * @need_fixup: whether we should fixup res_counters and refcounts.
+ *
+ * It succeeds only when the swap_cgroup's record for this entry is the same
+ * as the mem_cgroup's id of @from.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ *
+ * The caller must have charged to @to, IOW, called res_counter_charge() about
+ * both res and memsw, and called css_get().
+ */
+static int mem_cgroup_move_swap_account(swp_entry_t entry,
+               struct mem_cgroup *from, struct mem_cgroup *to, bool need_fixup)
+{
+       unsigned short old_id, new_id;
+
+       old_id = css_id(&from->css);
+       new_id = css_id(&to->css);
+
+       if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
+               mem_cgroup_swap_statistics(from, false);
+               mem_cgroup_swap_statistics(to, true);
+               /*
+                * This function is only called from task migration context now.
+                * It postpones res_counter and refcount handling till the end
+                * of task migration(mem_cgroup_clear_mc()) for performance
+                * improvement. But we cannot postpone mem_cgroup_get(to)
+                * because if the process that has been moved to @to does
+                * swap-in, the refcount of @to might be decreased to 0.
+                */
+               mem_cgroup_get(to);
+               if (need_fixup) {
+                       if (!mem_cgroup_is_root(from))
+                               res_counter_uncharge(&from->memsw, PAGE_SIZE);
+                       mem_cgroup_put(from);
+                       /*
+                        * we charged both to->res and to->memsw, so we should
+                        * uncharge to->res.
+                        */
+                       if (!mem_cgroup_is_root(to))
+                               res_counter_uncharge(&to->res, PAGE_SIZE);
+                       css_put(&to->css);
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+#else
+static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
+               struct mem_cgroup *from, struct mem_cgroup *to, bool need_fixup)
+{
+       return -EINVAL;
+}
 #endif
 
 /*
@@ -2216,8 +2430,7 @@ int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
        unlock_page_cgroup(pc);
 
        if (mem) {
-               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false,
-                                               page);
+               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false);
                css_put(&mem->css);
        }
        *ptr = mem;
@@ -2704,7 +2917,7 @@ static int
 mem_cgroup_get_idx_stat(struct mem_cgroup *mem, void *data)
 {
        struct mem_cgroup_idx_data *d = data;
-       d->val += mem_cgroup_read_stat(&mem->stat, d->idx);
+       d->val += mem_cgroup_read_stat(mem, d->idx);
        return 0;
 }
 
@@ -2719,40 +2932,50 @@ mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem,
        *val = d.val;
 }
 
+static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap)
+{
+       u64 idx_val, val;
+
+       if (!mem_cgroup_is_root(mem)) {
+               if (!swap)
+                       return res_counter_read_u64(&mem->res, RES_USAGE);
+               else
+                       return res_counter_read_u64(&mem->memsw, RES_USAGE);
+       }
+
+       mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE, &idx_val);
+       val = idx_val;
+       mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS, &idx_val);
+       val += idx_val;
+
+       if (swap) {
+               mem_cgroup_get_recursive_idx_stat(mem,
+                               MEM_CGROUP_STAT_SWAPOUT, &idx_val);
+               val += idx_val;
+       }
+
+       return val << PAGE_SHIFT;
+}
+
 static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
-       u64 idx_val, val;
+       u64 val;
        int type, name;
 
        type = MEMFILE_TYPE(cft->private);
        name = MEMFILE_ATTR(cft->private);
        switch (type) {
        case _MEM:
-               if (name == RES_USAGE && mem_cgroup_is_root(mem)) {
-                       mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_CACHE, &idx_val);
-                       val = idx_val;
-                       mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_RSS, &idx_val);
-                       val += idx_val;
-                       val <<= PAGE_SHIFT;
-               } else
+               if (name == RES_USAGE)
+                       val = mem_cgroup_usage(mem, false);
+               else
                        val = res_counter_read_u64(&mem->res, name);
                break;
        case _MEMSWAP:
-               if (name == RES_USAGE && mem_cgroup_is_root(mem)) {
-                       mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_CACHE, &idx_val);
-                       val = idx_val;
-                       mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_RSS, &idx_val);
-                       val += idx_val;
-                       mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_SWAPOUT, &idx_val);
-                       val += idx_val;
-                       val <<= PAGE_SHIFT;
-               } else
+               if (name == RES_USAGE)
+                       val = mem_cgroup_usage(mem, true);
+               else
                        val = res_counter_read_u64(&mem->memsw, name);
                break;
        default:
@@ -2865,6 +3088,39 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
        return 0;
 }
 
+static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp,
+                                       struct cftype *cft)
+{
+       return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate;
+}
+
+#ifdef CONFIG_MMU
+static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
+                                       struct cftype *cft, u64 val)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+
+       if (val >= (1 << NR_MOVE_TYPE))
+               return -EINVAL;
+       /*
+        * We check this value several times in both in can_attach() and
+        * attach(), so we need cgroup lock to prevent this value from being
+        * inconsistent.
+        */
+       cgroup_lock();
+       mem->move_charge_at_immigrate = val;
+       cgroup_unlock();
+
+       return 0;
+}
+#else
+static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
+                                       struct cftype *cft, u64 val)
+{
+       return -ENOSYS;
+}
+#endif
+
 
 /* For read statistics */
 enum {
@@ -2910,18 +3166,18 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
        s64 val;
 
        /* per cpu stat */
-       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_CACHE);
+       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE);
        s->stat[MCS_CACHE] += val * PAGE_SIZE;
-       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
+       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS);
        s->stat[MCS_RSS] += val * PAGE_SIZE;
-       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_FILE_MAPPED);
+       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_MAPPED);
        s->stat[MCS_FILE_MAPPED] += val * PAGE_SIZE;
-       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
+       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGIN_COUNT);
        s->stat[MCS_PGPGIN] += val;
-       val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);
+       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGOUT_COUNT);
        s->stat[MCS_PGPGOUT] += val;
        if (do_swap_account) {
-               val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_SWAPOUT);
+               val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_SWAPOUT);
                s->stat[MCS_SWAP] += val * PAGE_SIZE;
        }
 
@@ -3049,12 +3305,249 @@ static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft,
        return 0;
 }
 
+static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
+{
+       struct mem_cgroup_threshold_ary *t;
+       u64 usage;
+       int i;
+
+       rcu_read_lock();
+       if (!swap)
+               t = rcu_dereference(memcg->thresholds);
+       else
+               t = rcu_dereference(memcg->memsw_thresholds);
+
+       if (!t)
+               goto unlock;
+
+       usage = mem_cgroup_usage(memcg, swap);
+
+       /*
+        * current_threshold points to threshold just below usage.
+        * If it's not true, a threshold was crossed after last
+        * call of __mem_cgroup_threshold().
+        */
+       i = atomic_read(&t->current_threshold);
+
+       /*
+        * Iterate backward over array of thresholds starting from
+        * current_threshold and check if a threshold is crossed.
+        * If none of thresholds below usage is crossed, we read
+        * only one element of the array here.
+        */
+       for (; i >= 0 && unlikely(t->entries[i].threshold > usage); i--)
+               eventfd_signal(t->entries[i].eventfd, 1);
+
+       /* i = current_threshold + 1 */
+       i++;
+
+       /*
+        * Iterate forward over array of thresholds starting from
+        * current_threshold+1 and check if a threshold is crossed.
+        * If none of thresholds above usage is crossed, we read
+        * only one element of the array here.
+        */
+       for (; i < t->size && unlikely(t->entries[i].threshold <= usage); i++)
+               eventfd_signal(t->entries[i].eventfd, 1);
+
+       /* Update current_threshold */
+       atomic_set(&t->current_threshold, i - 1);
+unlock:
+       rcu_read_unlock();
+}
+
+static void mem_cgroup_threshold(struct mem_cgroup *memcg)
+{
+       __mem_cgroup_threshold(memcg, false);
+       if (do_swap_account)
+               __mem_cgroup_threshold(memcg, true);
+}
+
+static int compare_thresholds(const void *a, const void *b)
+{
+       const struct mem_cgroup_threshold *_a = a;
+       const struct mem_cgroup_threshold *_b = b;
+
+       return _a->threshold - _b->threshold;
+}
+
+static int mem_cgroup_register_event(struct cgroup *cgrp, struct cftype *cft,
+               struct eventfd_ctx *eventfd, const char *args)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       int type = MEMFILE_TYPE(cft->private);
+       u64 threshold, usage;
+       int size;
+       int i, ret;
+
+       ret = res_counter_memparse_write_strategy(args, &threshold);
+       if (ret)
+               return ret;
+
+       mutex_lock(&memcg->thresholds_lock);
+       if (type == _MEM)
+               thresholds = memcg->thresholds;
+       else if (type == _MEMSWAP)
+               thresholds = memcg->memsw_thresholds;
+       else
+               BUG();
+
+       usage = mem_cgroup_usage(memcg, type == _MEMSWAP);
+
+       /* Check if a threshold crossed before adding a new one */
+       if (thresholds)
+               __mem_cgroup_threshold(memcg, type == _MEMSWAP);
+
+       if (thresholds)
+               size = thresholds->size + 1;
+       else
+               size = 1;
+
+       /* Allocate memory for new array of thresholds */
+       thresholds_new = kmalloc(sizeof(*thresholds_new) +
+                       size * sizeof(struct mem_cgroup_threshold),
+                       GFP_KERNEL);
+       if (!thresholds_new) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+       thresholds_new->size = size;
+
+       /* Copy thresholds (if any) to new array */
+       if (thresholds)
+               memcpy(thresholds_new->entries, thresholds->entries,
+                               thresholds->size *
+                               sizeof(struct mem_cgroup_threshold));
+       /* Add new threshold */
+       thresholds_new->entries[size - 1].eventfd = eventfd;
+       thresholds_new->entries[size - 1].threshold = threshold;
+
+       /* Sort thresholds. Registering of new threshold isn't time-critical */
+       sort(thresholds_new->entries, size,
+                       sizeof(struct mem_cgroup_threshold),
+                       compare_thresholds, NULL);
+
+       /* Find current threshold */
+       atomic_set(&thresholds_new->current_threshold, -1);
+       for (i = 0; i < size; i++) {
+               if (thresholds_new->entries[i].threshold < usage) {
+                       /*
+                        * thresholds_new->current_threshold will not be used
+                        * until rcu_assign_pointer(), so it's safe to increment
+                        * it here.
+                        */
+                       atomic_inc(&thresholds_new->current_threshold);
+               }
+       }
+
+       if (type == _MEM)
+               rcu_assign_pointer(memcg->thresholds, thresholds_new);
+       else
+               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+
+       /* To be sure that nobody uses thresholds before freeing it */
+       synchronize_rcu();
+
+       kfree(thresholds);
+unlock:
+       mutex_unlock(&memcg->thresholds_lock);
+
+       return ret;
+}
+
+static int mem_cgroup_unregister_event(struct cgroup *cgrp, struct cftype *cft,
+               struct eventfd_ctx *eventfd)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       int type = MEMFILE_TYPE(cft->private);
+       u64 usage;
+       int size = 0;
+       int i, j, ret;
+
+       mutex_lock(&memcg->thresholds_lock);
+       if (type == _MEM)
+               thresholds = memcg->thresholds;
+       else if (type == _MEMSWAP)
+               thresholds = memcg->memsw_thresholds;
+       else
+               BUG();
+
+       /*
+        * Something went wrong if we trying to unregister a threshold
+        * if we don't have thresholds
+        */
+       BUG_ON(!thresholds);
+
+       usage = mem_cgroup_usage(memcg, type == _MEMSWAP);
+
+       /* Check if a threshold crossed before removing */
+       __mem_cgroup_threshold(memcg, type == _MEMSWAP);
+
+       /* Calculate new number of threshold */
+       for (i = 0; i < thresholds->size; i++) {
+               if (thresholds->entries[i].eventfd != eventfd)
+                       size++;
+       }
+
+       /* Set thresholds array to NULL if we don't have thresholds */
+       if (!size) {
+               thresholds_new = NULL;
+               goto assign;
+       }
+
+       /* Allocate memory for new array of thresholds */
+       thresholds_new = kmalloc(sizeof(*thresholds_new) +
+                       size * sizeof(struct mem_cgroup_threshold),
+                       GFP_KERNEL);
+       if (!thresholds_new) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+       thresholds_new->size = size;
+
+       /* Copy thresholds and find current threshold */
+       atomic_set(&thresholds_new->current_threshold, -1);
+       for (i = 0, j = 0; i < thresholds->size; i++) {
+               if (thresholds->entries[i].eventfd == eventfd)
+                       continue;
+
+               thresholds_new->entries[j] = thresholds->entries[i];
+               if (thresholds_new->entries[j].threshold < usage) {
+                       /*
+                        * thresholds_new->current_threshold will not be used
+                        * until rcu_assign_pointer(), so it's safe to increment
+                        * it here.
+                        */
+                       atomic_inc(&thresholds_new->current_threshold);
+               }
+               j++;
+       }
+
+assign:
+       if (type == _MEM)
+               rcu_assign_pointer(memcg->thresholds, thresholds_new);
+       else
+               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+
+       /* To be sure that nobody uses thresholds before freeing it */
+       synchronize_rcu();
+
+       kfree(thresholds);
+unlock:
+       mutex_unlock(&memcg->thresholds_lock);
+
+       return ret;
+}
 
 static struct cftype mem_cgroup_files[] = {
        {
                .name = "usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
                .read_u64 = mem_cgroup_read,
+               .register_event = mem_cgroup_register_event,
+               .unregister_event = mem_cgroup_unregister_event,
        },
        {
                .name = "max_usage_in_bytes",
@@ -3098,6 +3591,11 @@ static struct cftype mem_cgroup_files[] = {
                .read_u64 = mem_cgroup_swappiness_read,
                .write_u64 = mem_cgroup_swappiness_write,
        },
+       {
+               .name = "move_charge_at_immigrate",
+               .read_u64 = mem_cgroup_move_charge_read,
+               .write_u64 = mem_cgroup_move_charge_write,
+       },
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -3106,6 +3604,8 @@ static struct cftype memsw_cgroup_files[] = {
                .name = "memsw.usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
                .read_u64 = mem_cgroup_read,
+               .register_event = mem_cgroup_register_event,
+               .unregister_event = mem_cgroup_unregister_event,
        },
        {
                .name = "memsw.max_usage_in_bytes",
@@ -3180,17 +3680,12 @@ static void free_mem_cgroup_per_zone_info(struct mem_cgroup *mem, int node)
        kfree(mem->info.nodeinfo[node]);
 }
 
-static int mem_cgroup_size(void)
-{
-       int cpustat_size = nr_cpu_ids * sizeof(struct mem_cgroup_stat_cpu);
-       return sizeof(struct mem_cgroup) + cpustat_size;
-}
-
 static struct mem_cgroup *mem_cgroup_alloc(void)
 {
        struct mem_cgroup *mem;
-       int size = mem_cgroup_size();
+       int size = sizeof(struct mem_cgroup);
 
+       /* Can be very big if MAX_NUMNODES is very big */
        if (size < PAGE_SIZE)
                mem = kmalloc(size, GFP_KERNEL);
        else
@@ -3198,6 +3693,14 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
 
        if (mem)
                memset(mem, 0, size);
+       mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
+       if (!mem->stat) {
+               if (size < PAGE_SIZE)
+                       kfree(mem);
+               else
+                       vfree(mem);
+               mem = NULL;
+       }
        return mem;
 }
 
@@ -3222,7 +3725,8 @@ static void __mem_cgroup_free(struct mem_cgroup *mem)
        for_each_node_state(node, N_POSSIBLE)
                free_mem_cgroup_per_zone_info(mem, node);
 
-       if (mem_cgroup_size() < PAGE_SIZE)
+       free_percpu(mem->stat);
+       if (sizeof(struct mem_cgroup) < PAGE_SIZE)
                kfree(mem);
        else
                vfree(mem);
@@ -3233,9 +3737,9 @@ static void mem_cgroup_get(struct mem_cgroup *mem)
        atomic_inc(&mem->refcnt);
 }
 
-static void mem_cgroup_put(struct mem_cgroup *mem)
+static void __mem_cgroup_put(struct mem_cgroup *mem, int count)
 {
-       if (atomic_dec_and_test(&mem->refcnt)) {
+       if (atomic_sub_and_test(count, &mem->refcnt)) {
                struct mem_cgroup *parent = parent_mem_cgroup(mem);
                __mem_cgroup_free(mem);
                if (parent)
@@ -3243,6 +3747,11 @@ static void mem_cgroup_put(struct mem_cgroup *mem)
        }
 }
 
+static void mem_cgroup_put(struct mem_cgroup *mem)
+{
+       __mem_cgroup_put(mem, 1);
+}
+
 /*
  * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled.
  */
@@ -3319,7 +3828,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                        INIT_WORK(&stock->work, drain_local_stock);
                }
                hotcpu_notifier(memcg_stock_cpu_callback, 0);
-
        } else {
                parent = mem_cgroup_from_cont(cont->parent);
                mem->use_hierarchy = parent->use_hierarchy;
@@ -3345,6 +3853,8 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        if (parent)
                mem->swappiness = get_swappiness(parent);
        atomic_set(&mem->refcnt, 1);
+       mem->move_charge_at_immigrate = 0;
+       mutex_init(&mem->thresholds_lock);
        return &mem->css;
 free_out:
        __mem_cgroup_free(mem);
@@ -3381,16 +3891,444 @@ static int mem_cgroup_populate(struct cgroup_subsys *ss,
        return ret;
 }
 
+#ifdef CONFIG_MMU
+/* Handlers for move charge at task migration. */
+#define PRECHARGE_COUNT_AT_ONCE        256
+static int mem_cgroup_do_precharge(unsigned long count)
+{
+       int ret = 0;
+       int batch_count = PRECHARGE_COUNT_AT_ONCE;
+       struct mem_cgroup *mem = mc.to;
+
+       if (mem_cgroup_is_root(mem)) {
+               mc.precharge += count;
+               /* we don't need css_get for root */
+               return ret;
+       }
+       /* try to charge at once */
+       if (count > 1) {
+               struct res_counter *dummy;
+               /*
+                * "mem" cannot be under rmdir() because we've already checked
+                * by cgroup_lock_live_cgroup() that it is not removed and we
+                * are still under the same cgroup_mutex. So we can postpone
+                * css_get().
+                */
+               if (res_counter_charge(&mem->res, PAGE_SIZE * count, &dummy))
+                       goto one_by_one;
+               if (do_swap_account && res_counter_charge(&mem->memsw,
+                                               PAGE_SIZE * count, &dummy)) {
+                       res_counter_uncharge(&mem->res, PAGE_SIZE * count);
+                       goto one_by_one;
+               }
+               mc.precharge += count;
+               VM_BUG_ON(test_bit(CSS_ROOT, &mem->css.flags));
+               WARN_ON_ONCE(count > INT_MAX);
+               __css_get(&mem->css, (int)count);
+               return ret;
+       }
+one_by_one:
+       /* fall back to one by one charge */
+       while (count--) {
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               if (!batch_count--) {
+                       batch_count = PRECHARGE_COUNT_AT_ONCE;
+                       cond_resched();
+               }
+               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false);
+               if (ret || !mem)
+                       /* mem_cgroup_clear_mc() will do uncharge later */
+                       return -ENOMEM;
+               mc.precharge++;
+       }
+       return ret;
+}
+#else  /* !CONFIG_MMU */
+static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+       return 0;
+}
+static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+}
 static void mem_cgroup_move_task(struct cgroup_subsys *ss,
                                struct cgroup *cont,
                                struct cgroup *old_cont,
                                struct task_struct *p,
                                bool threadgroup)
 {
+}
+#endif
+
+/**
+ * is_target_pte_for_mc - check a pte whether it is valid for move charge
+ * @vma: the vma the pte to be checked belongs
+ * @addr: the address corresponding to the pte to be checked
+ * @ptent: the pte to be checked
+ * @target: the pointer the target page or swap ent will be stored(can be NULL)
+ *
+ * Returns
+ *   0(MC_TARGET_NONE): if the pte is not a target for move charge.
+ *   1(MC_TARGET_PAGE): if the page corresponding to this pte is a target for
+ *     move charge. if @target is not NULL, the page is stored in target->page
+ *     with extra refcnt got(Callers should handle it).
+ *   2(MC_TARGET_SWAP): if the swap entry corresponding to this pte is a
+ *     target for charge migration. if @target is not NULL, the entry is stored
+ *     in target->ent.
+ *
+ * Called with pte lock held.
+ */
+union mc_target {
+       struct page     *page;
+       swp_entry_t     ent;
+};
+
+enum mc_target_type {
+       MC_TARGET_NONE, /* not used */
+       MC_TARGET_PAGE,
+       MC_TARGET_SWAP,
+};
+
+static int is_target_pte_for_mc(struct vm_area_struct *vma,
+               unsigned long addr, pte_t ptent, union mc_target *target)
+{
+       struct page *page = NULL;
+       struct page_cgroup *pc;
+       int ret = 0;
+       swp_entry_t ent = { .val = 0 };
+       int usage_count = 0;
+       bool move_anon = test_bit(MOVE_CHARGE_TYPE_ANON,
+                                       &mc.to->move_charge_at_immigrate);
+
+       if (!pte_present(ptent)) {
+               /* TODO: handle swap of shmes/tmpfs */
+               if (pte_none(ptent) || pte_file(ptent))
+                       return 0;
+               else if (is_swap_pte(ptent)) {
+                       ent = pte_to_swp_entry(ptent);
+                       if (!move_anon || non_swap_entry(ent))
+                               return 0;
+                       usage_count = mem_cgroup_count_swap_user(ent, &page);
+               }
+       } else {
+               page = vm_normal_page(vma, addr, ptent);
+               if (!page || !page_mapped(page))
+                       return 0;
+               /*
+                * TODO: We don't move charges of file(including shmem/tmpfs)
+                * pages for now.
+                */
+               if (!move_anon || !PageAnon(page))
+                       return 0;
+               if (!get_page_unless_zero(page))
+                       return 0;
+               usage_count = page_mapcount(page);
+       }
+       if (usage_count > 1) {
+               /*
+                * TODO: We don't move charges of shared(used by multiple
+                * processes) pages for now.
+                */
+               if (page)
+                       put_page(page);
+               return 0;
+       }
+       if (page) {
+               pc = lookup_page_cgroup(page);
+               /*
+                * Do only loose check w/o page_cgroup lock.
+                * mem_cgroup_move_account() checks the pc is valid or not under
+                * the lock.
+                */
+               if (PageCgroupUsed(pc) && pc->mem_cgroup == mc.from) {
+                       ret = MC_TARGET_PAGE;
+                       if (target)
+                               target->page = page;
+               }
+               if (!ret || !target)
+                       put_page(page);
+       }
+       /* throught */
+       if (ent.val && do_swap_account && !ret &&
+                       css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
+               ret = MC_TARGET_SWAP;
+               if (target)
+                       target->ent = ent;
+       }
+       return ret;
+}
+
+static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
+                                       unsigned long addr, unsigned long end,
+                                       struct mm_walk *walk)
+{
+       struct vm_area_struct *vma = walk->private;
+       pte_t *pte;
+       spinlock_t *ptl;
+
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       for (; addr != end; pte++, addr += PAGE_SIZE)
+               if (is_target_pte_for_mc(vma, addr, *pte, NULL))
+                       mc.precharge++; /* increment precharge temporarily */
+       pte_unmap_unlock(pte - 1, ptl);
+       cond_resched();
+
+       return 0;
+}
+
+static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
+{
+       unsigned long precharge;
+       struct vm_area_struct *vma;
+
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               struct mm_walk mem_cgroup_count_precharge_walk = {
+                       .pmd_entry = mem_cgroup_count_precharge_pte_range,
+                       .mm = mm,
+                       .private = vma,
+               };
+               if (is_vm_hugetlb_page(vma))
+                       continue;
+               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
+               if (vma->vm_flags & VM_SHARED)
+                       continue;
+               walk_page_range(vma->vm_start, vma->vm_end,
+                                       &mem_cgroup_count_precharge_walk);
+       }
+       up_read(&mm->mmap_sem);
+
+       precharge = mc.precharge;
+       mc.precharge = 0;
+
+       return precharge;
+}
+
+static int mem_cgroup_precharge_mc(struct mm_struct *mm)
+{
+       return mem_cgroup_do_precharge(mem_cgroup_count_precharge(mm));
+}
+
+static void mem_cgroup_clear_mc(void)
+{
+       /* we must uncharge all the leftover precharges from mc.to */
+       if (mc.precharge) {
+               __mem_cgroup_cancel_charge(mc.to, mc.precharge);
+               mc.precharge = 0;
+       }
        /*
-        * FIXME: It's better to move charges of this process from old
-        * memcg to new memcg. But it's just on TODO-List now.
+        * we didn't uncharge from mc.from at mem_cgroup_move_account(), so
+        * we must uncharge here.
         */
+       if (mc.moved_charge) {
+               __mem_cgroup_cancel_charge(mc.from, mc.moved_charge);
+               mc.moved_charge = 0;
+       }
+       /* we must fixup refcnts and charges */
+       if (mc.moved_swap) {
+               WARN_ON_ONCE(mc.moved_swap > INT_MAX);
+               /* uncharge swap account from the old cgroup */
+               if (!mem_cgroup_is_root(mc.from))
+                       res_counter_uncharge(&mc.from->memsw,
+                                               PAGE_SIZE * mc.moved_swap);
+               __mem_cgroup_put(mc.from, mc.moved_swap);
+
+               if (!mem_cgroup_is_root(mc.to)) {
+                       /*
+                        * we charged both to->res and to->memsw, so we should
+                        * uncharge to->res.
+                        */
+                       res_counter_uncharge(&mc.to->res,
+                                               PAGE_SIZE * mc.moved_swap);
+                       VM_BUG_ON(test_bit(CSS_ROOT, &mc.to->css.flags));
+                       __css_put(&mc.to->css, mc.moved_swap);
+               }
+               /* we've already done mem_cgroup_get(mc.to) */
+
+               mc.moved_swap = 0;
+       }
+       mc.from = NULL;
+       mc.to = NULL;
+       mc.moving_task = NULL;
+       wake_up_all(&mc.waitq);
+}
+
+static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+       int ret = 0;
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgroup);
+
+       if (mem->move_charge_at_immigrate) {
+               struct mm_struct *mm;
+               struct mem_cgroup *from = mem_cgroup_from_task(p);
+
+               VM_BUG_ON(from == mem);
+
+               mm = get_task_mm(p);
+               if (!mm)
+                       return 0;
+               /* We move charges only when we move a owner of the mm */
+               if (mm->owner == p) {
+                       VM_BUG_ON(mc.from);
+                       VM_BUG_ON(mc.to);
+                       VM_BUG_ON(mc.precharge);
+                       VM_BUG_ON(mc.moved_charge);
+                       VM_BUG_ON(mc.moved_swap);
+                       VM_BUG_ON(mc.moving_task);
+                       mc.from = from;
+                       mc.to = mem;
+                       mc.precharge = 0;
+                       mc.moved_charge = 0;
+                       mc.moved_swap = 0;
+                       mc.moving_task = current;
+
+                       ret = mem_cgroup_precharge_mc(mm);
+                       if (ret)
+                               mem_cgroup_clear_mc();
+               }
+               mmput(mm);
+       }
+       return ret;
+}
+
+static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
+                               struct cgroup *cgroup,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+       mem_cgroup_clear_mc();
+}
+
+static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
+                               unsigned long addr, unsigned long end,
+                               struct mm_walk *walk)
+{
+       int ret = 0;
+       struct vm_area_struct *vma = walk->private;
+       pte_t *pte;
+       spinlock_t *ptl;
+
+retry:
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       for (; addr != end; addr += PAGE_SIZE) {
+               pte_t ptent = *(pte++);
+               union mc_target target;
+               int type;
+               struct page *page;
+               struct page_cgroup *pc;
+               swp_entry_t ent;
+
+               if (!mc.precharge)
+                       break;
+
+               type = is_target_pte_for_mc(vma, addr, ptent, &target);
+               switch (type) {
+               case MC_TARGET_PAGE:
+                       page = target.page;
+                       if (isolate_lru_page(page))
+                               goto put;
+                       pc = lookup_page_cgroup(page);
+                       if (!mem_cgroup_move_account(pc,
+                                               mc.from, mc.to, false)) {
+                               mc.precharge--;
+                               /* we uncharge from mc.from later. */
+                               mc.moved_charge++;
+                       }
+                       putback_lru_page(page);
+put:                   /* is_target_pte_for_mc() gets the page */
+                       put_page(page);
+                       break;
+               case MC_TARGET_SWAP:
+                       ent = target.ent;
+                       if (!mem_cgroup_move_swap_account(ent,
+                                               mc.from, mc.to, false)) {
+                               mc.precharge--;
+                               /* we fixup refcnts and charges later. */
+                               mc.moved_swap++;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       pte_unmap_unlock(pte - 1, ptl);
+       cond_resched();
+
+       if (addr != end) {
+               /*
+                * We have consumed all precharges we got in can_attach().
+                * We try charge one by one, but don't do any additional
+                * charges to mc.to if we have failed in charge once in attach()
+                * phase.
+                */
+               ret = mem_cgroup_do_precharge(1);
+               if (!ret)
+                       goto retry;
+       }
+
+       return ret;
+}
+
+static void mem_cgroup_move_charge(struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+
+       lru_add_drain_all();
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               int ret;
+               struct mm_walk mem_cgroup_move_charge_walk = {
+                       .pmd_entry = mem_cgroup_move_charge_pte_range,
+                       .mm = mm,
+                       .private = vma,
+               };
+               if (is_vm_hugetlb_page(vma))
+                       continue;
+               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
+               if (vma->vm_flags & VM_SHARED)
+                       continue;
+               ret = walk_page_range(vma->vm_start, vma->vm_end,
+                                               &mem_cgroup_move_charge_walk);
+               if (ret)
+                       /*
+                        * means we have consumed all precharges and failed in
+                        * doing additional charge. Just abandon here.
+                        */
+                       break;
+       }
+       up_read(&mm->mmap_sem);
+}
+
+static void mem_cgroup_move_task(struct cgroup_subsys *ss,
+                               struct cgroup *cont,
+                               struct cgroup *old_cont,
+                               struct task_struct *p,
+                               bool threadgroup)
+{
+       struct mm_struct *mm;
+
+       if (!mc.to)
+               /* no need to move charge */
+               return;
+
+       mm = get_task_mm(p);
+       if (mm) {
+               mem_cgroup_move_charge(mm);
+               mmput(mm);
+       }
+       mem_cgroup_clear_mc();
 }
 
 struct cgroup_subsys mem_cgroup_subsys = {
@@ -3400,6 +4338,8 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .pre_destroy = mem_cgroup_pre_destroy,
        .destroy = mem_cgroup_destroy,
        .populate = mem_cgroup_populate,
+       .can_attach = mem_cgroup_can_attach,
+       .cancel_attach = mem_cgroup_cancel_attach,
        .attach = mem_cgroup_move_task,
        .early_init = 0,
        .use_id = 1,
index d1153e3..5b7f200 100644 (file)
@@ -190,9 +190,6 @@ static void check_sync_rss_stat(struct task_struct *task)
 {
 }
 
-void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
-{
-}
 #endif
 
 /*
@@ -512,12 +509,8 @@ static void print_bad_pte(struct vm_area_struct *vma, unsigned long addr,
                "BUG: Bad page map in process %s  pte:%08llx pmd:%08llx\n",
                current->comm,
                (long long)pte_val(pte), (long long)pmd_val(*pmd));
-       if (page) {
-               printk(KERN_ALERT
-               "page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n",
-               page, (void *)page->flags, page_count(page),
-               page_mapcount(page), page->mapping, page->index);
-       }
+       if (page)
+               dump_page(page);
        printk(KERN_ALERT
                "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n",
                (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);
index 78e34e6..be211a5 100644 (file)
@@ -688,9 +688,9 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        if (page_count(page))
                                not_managed++;
 #ifdef CONFIG_DEBUG_VM
-                       printk(KERN_INFO "removing from LRU failed"
-                                        " %lx/%d/%lx\n",
-                               pfn, page_count(page), page->flags);
+                       printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
+                              pfn);
+                       dump_page(page);
 #endif
                }
        }
index f1b4448..75557c6 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1088,6 +1088,30 @@ out:
        return retval;
 }
 
+#ifdef __ARCH_WANT_SYS_OLD_MMAP
+struct mmap_arg_struct {
+       unsigned long addr;
+       unsigned long len;
+       unsigned long prot;
+       unsigned long flags;
+       unsigned long fd;
+       unsigned long offset;
+};
+
+SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg)
+{
+       struct mmap_arg_struct a;
+
+       if (copy_from_user(&a, arg, sizeof(a)))
+               return -EFAULT;
+       if (a.offset & ~PAGE_MASK)
+               return -EINVAL;
+
+       return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                             a.offset >> PAGE_SHIFT);
+}
+#endif /* __ARCH_WANT_SYS_OLD_MMAP */
+
 /*
  * Some shared mappigns will want the pages marked read-only
  * to track write events. If so, we'll downgrade vm_page_prot
index b9b5cce..605ace8 100644 (file)
@@ -1428,6 +1428,30 @@ out:
        return retval;
 }
 
+#ifdef __ARCH_WANT_SYS_OLD_MMAP
+struct mmap_arg_struct {
+       unsigned long addr;
+       unsigned long len;
+       unsigned long prot;
+       unsigned long flags;
+       unsigned long fd;
+       unsigned long offset;
+};
+
+SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg)
+{
+       struct mmap_arg_struct a;
+
+       if (copy_from_user(&a, arg, sizeof(a)))
+               return -EFAULT;
+       if (a.offset & ~PAGE_MASK)
+               return -EINVAL;
+
+       return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                             a.offset >> PAGE_SHIFT);
+}
+#endif /* __ARCH_WANT_SYS_OLD_MMAP */
+
 /*
  * split a vma into two pieces at address 'addr', a new vma is allocated either
  * for the first part or the tail.
index 35755a4..9b223af 100644 (file)
@@ -473,6 +473,8 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        unsigned long points = 0;
        struct task_struct *p;
 
+       if (sysctl_panic_on_oom == 2)
+               panic("out of memory(memcg). panic_on_oom is selected.\n");
        read_lock(&tasklist_lock);
 retry:
        p = select_bad_process(&points, mem);
@@ -601,13 +603,6 @@ void pagefault_out_of_memory(void)
                /* Got some memory back in the last second. */
                return;
 
-       /*
-        * If this is from memcg, oom-killer is already invoked.
-        * and not worth to go system-wide-oom.
-        */
-       if (mem_cgroup_oom_called(current))
-               goto rest_and_return;
-
        if (sysctl_panic_on_oom)
                panic("out of memory from page fault. panic_on_oom is selected.\n");
 
@@ -619,7 +614,6 @@ void pagefault_out_of_memory(void)
         * Give "p" a good chance of killing itself before we
         * retry to allocate memory.
         */
-rest_and_return:
        if (!test_thread_flag(TIF_MEMDIE))
                schedule_timeout_uninterruptible(1);
 }
index a8182c8..d03c946 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/kmemleak.h>
 #include <linux/memory.h>
 #include <trace/events/kmem.h>
+#include <linux/ftrace_event.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -288,10 +289,7 @@ static void bad_page(struct page *page)
 
        printk(KERN_ALERT "BUG: Bad page state in process %s  pfn:%05lx\n",
                current->comm, page_to_pfn(page));
-       printk(KERN_ALERT
-               "page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n",
-               page, (void *)page->flags, page_count(page),
-               page_mapcount(page), page->mapping, page->index);
+       dump_page(page);
 
        dump_stack();
 out:
@@ -3224,7 +3222,7 @@ static int __zone_pcp_update(void *data)
        int cpu;
        unsigned long batch = zone_batchsize(zone), flags;
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+       for_each_possible_cpu(cpu) {
                struct per_cpu_pageset *pset;
                struct per_cpu_pages *pcp;
 
@@ -5183,3 +5181,80 @@ bool is_free_buddy_page(struct page *page)
        return order < MAX_ORDER;
 }
 #endif
+
+static struct trace_print_flags pageflag_names[] = {
+       {1UL << PG_locked,              "locked"        },
+       {1UL << PG_error,               "error"         },
+       {1UL << PG_referenced,          "referenced"    },
+       {1UL << PG_uptodate,            "uptodate"      },
+       {1UL << PG_dirty,               "dirty"         },
+       {1UL << PG_lru,                 "lru"           },
+       {1UL << PG_active,              "active"        },
+       {1UL << PG_slab,                "slab"          },
+       {1UL << PG_owner_priv_1,        "owner_priv_1"  },
+       {1UL << PG_arch_1,              "arch_1"        },
+       {1UL << PG_reserved,            "reserved"      },
+       {1UL << PG_private,             "private"       },
+       {1UL << PG_private_2,           "private_2"     },
+       {1UL << PG_writeback,           "writeback"     },
+#ifdef CONFIG_PAGEFLAGS_EXTENDED
+       {1UL << PG_head,                "head"          },
+       {1UL << PG_tail,                "tail"          },
+#else
+       {1UL << PG_compound,            "compound"      },
+#endif
+       {1UL << PG_swapcache,           "swapcache"     },
+       {1UL << PG_mappedtodisk,        "mappedtodisk"  },
+       {1UL << PG_reclaim,             "reclaim"       },
+       {1UL << PG_buddy,               "buddy"         },
+       {1UL << PG_swapbacked,          "swapbacked"    },
+       {1UL << PG_unevictable,         "unevictable"   },
+#ifdef CONFIG_MMU
+       {1UL << PG_mlocked,             "mlocked"       },
+#endif
+#ifdef CONFIG_ARCH_USES_PG_UNCACHED
+       {1UL << PG_uncached,            "uncached"      },
+#endif
+#ifdef CONFIG_MEMORY_FAILURE
+       {1UL << PG_hwpoison,            "hwpoison"      },
+#endif
+       {-1UL,                          NULL            },
+};
+
+static void dump_page_flags(unsigned long flags)
+{
+       const char *delim = "";
+       unsigned long mask;
+       int i;
+
+       printk(KERN_ALERT "page flags: %#lx(", flags);
+
+       /* remove zone id */
+       flags &= (1UL << NR_PAGEFLAGS) - 1;
+
+       for (i = 0; pageflag_names[i].name && flags; i++) {
+
+               mask = pageflag_names[i].mask;
+               if ((flags & mask) != mask)
+                       continue;
+
+               flags &= ~mask;
+               printk("%s%s", delim, pageflag_names[i].name);
+               delim = "|";
+       }
+
+       /* check for left over flags */
+       if (flags)
+               printk("%s%#lx", delim, flags);
+
+       printk(")\n");
+}
+
+void dump_page(struct page *page)
+{
+       printk(KERN_ALERT
+              "page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
+               page, page_count(page), page_mapcount(page),
+               page->mapping, page->index);
+       dump_page_flags(page->flags);
+}
index 3d535d5..3dd8853 100644 (file)
@@ -334,6 +334,37 @@ not_enough_page:
        return -ENOMEM;
 }
 
+/**
+ * swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
+ * @end: swap entry to be cmpxchged
+ * @old: old id
+ * @new: new id
+ *
+ * Returns old id at success, 0 at failure.
+ * (There is no mem_cgroup useing 0 as its id)
+ */
+unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
+                                       unsigned short old, unsigned short new)
+{
+       int type = swp_type(ent);
+       unsigned long offset = swp_offset(ent);
+       unsigned long idx = offset / SC_PER_PAGE;
+       unsigned long pos = offset & SC_POS_MASK;
+       struct swap_cgroup_ctrl *ctrl;
+       struct page *mappage;
+       struct swap_cgroup *sc;
+
+       ctrl = &swap_cgroup_ctrl[type];
+
+       mappage = ctrl->map[idx];
+       sc = page_address(mappage);
+       sc += pos;
+       if (cmpxchg(&sc->id, old, new) == old)
+               return old;
+       else
+               return 0;
+}
+
 /**
  * swap_cgroup_record - record mem_cgroup for this swp_entry.
  * @ent: swap entry to be recorded into
@@ -358,8 +389,7 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
        mappage = ctrl->map[idx];
        sc = page_address(mappage);
        sc += pos;
-       old = sc->id;
-       sc->id = id;
+       old = xchg(&sc->id, id);
 
        return old;
 }
index 0bfd386..a2b8969 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4390,7 +4390,7 @@ static void kmem_cache_release(struct kobject *kobj)
        kfree(s);
 }
 
-static struct sysfs_ops slab_sysfs_ops = {
+static const struct sysfs_ops slab_sysfs_ops = {
        .show = slab_attr_show,
        .store = slab_attr_store,
 };
@@ -4409,7 +4409,7 @@ static int uevent_filter(struct kset *kset, struct kobject *kobj)
        return 0;
 }
 
-static struct kset_uevent_ops slab_uevent_ops = {
+static const struct kset_uevent_ops slab_uevent_ops = {
        .filter = uevent_filter,
 };
 
index 84374d8..6cd0a8f 100644 (file)
@@ -723,6 +723,37 @@ int free_swap_and_cache(swp_entry_t entry)
        return p != NULL;
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/**
+ * mem_cgroup_count_swap_user - count the user of a swap entry
+ * @ent: the swap entry to be checked
+ * @pagep: the pointer for the swap cache page of the entry to be stored
+ *
+ * Returns the number of the user of the swap entry. The number is valid only
+ * for swaps of anonymous pages.
+ * If the entry is found on swap cache, the page is stored to pagep with
+ * refcount of it being incremented.
+ */
+int mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep)
+{
+       struct page *page;
+       struct swap_info_struct *p;
+       int count = 0;
+
+       page = find_get_page(&swapper_space, ent.val);
+       if (page)
+               count += page_mapcount(page);
+       p = swap_info_get(ent);
+       if (p) {
+               count += swap_count(p->swap_map[swp_offset(ent)]);
+               spin_unlock(&swap_lock);
+       }
+
+       *pagep = page;
+       return count;
+}
+#endif
+
 #ifdef CONFIG_HIBERNATION
 /*
  * Find the swap type that corresponds to given device (if any).
index 400efa2..4db7ae2 100644 (file)
@@ -3937,7 +3937,9 @@ drop:
        return 0;
 }
 
-static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
+static ssize_t l2cap_sysfs_show(struct class *dev,
+                               struct class_attribute *attr,
+                               char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
index 89f4a59..db8a68e 100644 (file)
@@ -2098,7 +2098,9 @@ static struct hci_cb rfcomm_cb = {
        .security_cfm   = rfcomm_security_cfm
 };
 
-static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
+static ssize_t rfcomm_dlc_sysfs_show(struct class *dev,
+                                    struct class_attribute *attr,
+                                    char *buf)
 {
        struct rfcomm_session *s;
        struct list_head *pp, *p;
index 4b5968d..ca87d6a 100644 (file)
@@ -1061,7 +1061,9 @@ done:
        return result;
 }
 
-static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
+static ssize_t rfcomm_sock_sysfs_show(struct class *dev,
+                                     struct class_attribute *attr,
+                                     char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
index dd8f6ec..f93b939 100644 (file)
@@ -953,7 +953,9 @@ drop:
        return 0;
 }
 
-static ssize_t sco_sysfs_show(struct class *dev, char *buf)
+static ssize_t sco_sysfs_show(struct class *dev,
+                               struct class_attribute *attr,
+                               char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
index 1cf2cef..fef0384 100644 (file)
@@ -423,7 +423,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
 
 #ifdef CONFIG_SYSFS
 /* br_sysfs_if.c */
-extern struct sysfs_ops brport_sysfs_ops;
+extern const struct sysfs_ops brport_sysfs_ops;
 extern int br_sysfs_addif(struct net_bridge_port *p);
 
 /* br_sysfs_br.c */
index 696596c..0b99164 100644 (file)
@@ -238,7 +238,7 @@ static ssize_t brport_store(struct kobject * kobj,
        return ret;
 }
 
-struct sysfs_ops brport_sysfs_ops = {
+const struct sysfs_ops brport_sysfs_ops = {
        .show = brport_show,
        .store = brport_store,
 };
index 8d9b55a..86ea0c3 100644 (file)
@@ -44,7 +44,7 @@ static struct kobj_attribute foo_attribute =
        __ATTR(foo, 0666, foo_show, foo_store);
 
 /*
- * More complex function where we determine which varible is being accessed by
+ * More complex function where we determine which variable is being accessed by
  * looking at the attribute for the "baz" and "bar" files.
  */
 static ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -79,7 +79,7 @@ static struct kobj_attribute bar_attribute =
 
 
 /*
- * Create a group of attributes so that we can create and destory them all
+ * Create a group of attributes so that we can create and destroy them all
  * at once.
  */
 static struct attribute *attrs[] = {
index 45b7d56..3b126d1 100644 (file)
@@ -87,7 +87,7 @@ static ssize_t foo_attr_store(struct kobject *kobj,
 }
 
 /* Our custom sysfs_ops that we will associate with our ktype later on */
-static struct sysfs_ops foo_sysfs_ops = {
+static const struct sysfs_ops foo_sysfs_ops = {
        .show = foo_attr_show,
        .store = foo_attr_store,
 };
@@ -127,7 +127,7 @@ static struct foo_attribute foo_attribute =
        __ATTR(foo, 0666, foo_show, foo_store);
 
 /*
- * More complex function where we determine which varible is being accessed by
+ * More complex function where we determine which variable is being accessed by
  * looking at the attribute for the "baz" and "bar" files.
  */
 static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
@@ -161,7 +161,7 @@ static struct foo_attribute bar_attribute =
        __ATTR(bar, 0666, b_show, b_store);
 
 /*
- * Create a group of attributes so that we can create and destory them all
+ * Create a group of attributes so that we can create and destroy them all
  * at once.
  */
 static struct attribute *foo_default_attrs[] = {
index 208ad3b..c7865c3 100755 (executable)
@@ -2103,7 +2103,7 @@ sub process_file($) {
                $section = $newsection;
            } elsif (/$doc_end/) {
 
-               if ($contents ne "") {
+               if (($contents ne "") && ($contents ne "\n")) {
                    dump_section($file, $section, xml_escape($contents));
                    $section = $section_default;
                    $contents = "";
index 8f8b17a..7394365 100644 (file)
@@ -393,7 +393,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
            event == SNDRV_TIMER_EVENT_CONTINUE)
                resolution = snd_timer_resolution(ti);
        if (ti->ccallback)
-               ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
+               ti->ccallback(ti, event, &tstamp, resolution);
        if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
                return;
        timer = ti->timer;
index b865e45..5913717 100644 (file)
@@ -1558,7 +1558,7 @@ static int __devinit snd_card_miro_pnp(struct snd_miro *chip,
 
        err = pnp_activate_dev(devmc);
        if (err < 0) {
-               snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n",
+               snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
                                    err);
                return err;
        }
index a4af53b..becd90d 100644 (file)
@@ -144,12 +144,8 @@ struct snd_opti9xx {
 
        spinlock_t lock;
 
+       long wss_base;
        int irq;
-
-#ifdef CONFIG_PNP
-       struct pnp_dev *dev;
-       struct pnp_dev *devmpu;
-#endif /* CONFIG_PNP */
 };
 
 static int snd_opti9xx_pnp_is_probed;
@@ -159,12 +155,17 @@ static int snd_opti9xx_pnp_is_probed;
 static struct pnp_card_device_id snd_opti9xx_pnpids[] = {
 #ifndef OPTi93X
        /* OPTi 82C924 */
-       { .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 },
+       { .id = "OPT0924",
+         .devs = { { "OPT0000" }, { "OPT0002" }, { "OPT0005" } },
+         .driver_data = 0x0924 },
        /* OPTi 82C925 */
-       { .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 },
+       { .id = "OPT0925",
+         .devs = { { "OPT9250" }, { "OPT0002" }, { "OPT0005" } },
+         .driver_data = 0x0925 },
 #else
        /* OPTi 82C931/3 */
-       { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 },
+       { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } },
+         .driver_data = 0x0931 },
 #endif /* OPTi93X */
        { .id = "" }
 };
@@ -207,24 +208,34 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
        chip->hardware = hardware;
        strcpy(chip->name, snd_opti9xx_names[hardware]);
 
-       chip->mc_base_size = opti9xx_mc_size[hardware];  
-
        spin_lock_init(&chip->lock);
 
        chip->irq = -1;
 
+#ifndef OPTi93X
+#ifdef CONFIG_PNP
+       if (isapnp && chip->mc_base)
+               /* PnP resource gives the least 10 bits */
+               chip->mc_base |= 0xc00;
+#endif /* CONFIG_PNP */
+       else {
+               chip->mc_base = 0xf8c;
+               chip->mc_base_size = opti9xx_mc_size[hardware];
+       }
+#else
+               chip->mc_base_size = opti9xx_mc_size[hardware];
+#endif
+
        switch (hardware) {
 #ifndef OPTi93X
        case OPTi9XX_HW_82C928:
        case OPTi9XX_HW_82C929:
-               chip->mc_base = 0xf8c;
                chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3;
                chip->pwd_reg = 3;
                break;
 
        case OPTi9XX_HW_82C924:
        case OPTi9XX_HW_82C925:
-               chip->mc_base = 0xf8c;
                chip->password = 0xe5;
                chip->pwd_reg = 3;
                break;
@@ -292,7 +303,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
        spin_unlock_irqrestore(&chip->lock, flags);
        return retval;
 }
-       
+
 static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
                              unsigned char value)
 {
@@ -341,7 +352,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
 
 
 static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
-                                          long wss_base,
+                                          long port,
                                           int irq, int dma1, int dma2,
                                           long mpu_port, int mpu_irq)
 {
@@ -354,16 +365,23 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
        switch (chip->hardware) {
 #ifndef OPTi93X
        case OPTi9XX_HW_82C924:
+               /* opti 929 mode (?), OPL3 clock output, audio enable */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
+               /* enable wave audio */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
 
        case OPTi9XX_HW_82C925:
+               /* enable WSS mode */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+               /* OPL3 FM synthesis */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
+               /* disable Sound Blaster IRQ and DMA */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
 #ifdef CS4231
+               /* cs4231/4248 fix enabled */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
 #else
+               /* cs4231/4248 fix disabled */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
 #endif /* CS4231 */
                break;
@@ -411,21 +429,26 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
                return -EINVAL;
        }
 
-       switch (wss_base) {
-       case 0x530:
+       /* PnP resource says it decodes only 10 bits of address */
+       switch (port & 0x3ff) {
+       case 0x130:
+               chip->wss_base = 0x530;
                wss_base_bits = 0x00;
                break;
-       case 0x604:
+       case 0x204:
+               chip->wss_base = 0x604;
                wss_base_bits = 0x03;
                break;
-       case 0xe80:
+       case 0x280:
+               chip->wss_base = 0xe80;
                wss_base_bits = 0x01;
                break;
-       case 0xf40:
+       case 0x340:
+               chip->wss_base = 0xf40;
                wss_base_bits = 0x02;
                break;
        default:
-               snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
+               snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port);
                goto __skip_base;
        }
        snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -487,7 +510,7 @@ __skip_base:
 #endif /* CS4231 || OPTi93X */
 
 #ifndef OPTi93X
-        outb(irq_bits << 3 | dma_bits, wss_base);
+        outb(irq_bits << 3 | dma_bits, chip->wss_base);
 #else /* OPTi93X */
        snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
 #endif /* OPTi93X */
@@ -729,15 +752,15 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
 {
        struct pnp_dev *pdev;
        int err;
+       struct pnp_dev *devmpu;
+#ifndef OPTi93X
+       struct pnp_dev *devmc;
+#endif
 
-       chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
-       if (chip->dev == NULL)
+       pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+       if (pdev == NULL)
                return -EBUSY;
 
-       chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
-
-       pdev = chip->dev;
-
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
@@ -750,9 +773,24 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
        chip->mc_indir_index = pnp_port_start(pdev, 3) + 2;
        chip->mc_indir_size = pnp_port_len(pdev, 3) - 2;
 #else
-       if (pid->driver_data != 0x0924)
-               port = pnp_port_start(pdev, 1);
+       devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
+       if (devmc == NULL)
+               return -EBUSY;
+
+       err = pnp_activate_dev(devmc);
+       if (err < 0) {
+               snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err);
+               return err;
+       }
+
+       port = pnp_port_start(pdev, 1);
        fm_port = pnp_port_start(pdev, 2) + 8;
+       /*
+        * The MC(0) is never accessed and card does not
+        * include it in the PnP resource range. OPTI93x include it.
+        */
+       chip->mc_base = pnp_port_start(devmc, 0) - 1;
+       chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
 #endif /* OPTi93X */
        irq = pnp_irq(pdev, 0);
        dma1 = pnp_dma(pdev, 0);
@@ -760,16 +798,16 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
        dma2 = pnp_dma(pdev, 1);
 #endif /* CS4231 || OPTi93X */
 
-       pdev = chip->devmpu;
-       if (pdev && mpu_port > 0) {
-               err = pnp_activate_dev(pdev);
+       devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
+
+       if (devmpu && mpu_port > 0) {
+               err = pnp_activate_dev(devmpu);
                if (err < 0) {
-                       snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
+                       snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
                        mpu_port = -1;
-                       chip->devmpu = NULL;
                } else {
-                       mpu_port = pnp_port_start(pdev, 0);
-                       mpu_irq = pnp_irq(pdev, 0);
+                       mpu_port = pnp_port_start(devmpu, 0);
+                       mpu_irq = pnp_irq(devmpu, 0);
                }
        }
        return pid->driver_data;
@@ -824,7 +862,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        if (error)
                return error;
 
-       error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
+       error = snd_wss_create(card, chip->wss_base + 4, -1, irq, dma1, xdma2,
 #ifdef OPTi93X
                               WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
 #else
@@ -865,10 +903,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        sprintf(card->shortname, "OPTi %s", card->driver);
 #if defined(CS4231) || defined(OPTi93X)
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
-               card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
+               card->shortname, pcm->name,
+               chip->wss_base + 4, irq, dma1, xdma2);
 #else
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
-               card->shortname, pcm->name, port + 4, irq, dma1);
+               card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
 #endif /* CS4231 || OPTi93X */
 
        if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
@@ -1062,9 +1101,6 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
                snd_card_free(card);
                return error;
        }
-       if (hw <= OPTi9XX_HW_82C930)
-               chip->mc_base -= 0x80;
-
        error = snd_opti9xx_read_check(chip);
        if (error) {
                snd_printk(KERN_ERR "OPTI chip not found\n");
index 8d21a3f..8ccbcdd 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/delay.h>
 #include <asm/dma.h>
 #include <linux/isa.h>
 #include <sound/core.h>
index 7306346..7bec21b 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- * Coprocessor access types 
+ * Coprocessor access types
  */
 #define COPR_CUSTOM            0x0001  /* Custom applications */
 #define COPR_MIDI              0x0002  /* MIDI (MPU-401) emulation */
index 1b86cb4..08e2185 100644 (file)
@@ -2,9 +2,9 @@ typedef struct vmidi_devc {
           int dev;
 
        /* State variables */
-          int opened;
+          int opened;
           spinlock_t lock;
-       
+
        /* MIDI fields */
           int my_mididev;
           int pair_mididev;
@@ -12,4 +12,3 @@ typedef struct vmidi_devc {
           int intr_active;
           void (*midi_input_intr) (int dev, unsigned char data);
        } vmidi_devc;
-
index 556cff9..567348b 100644 (file)
@@ -157,7 +157,7 @@ config SND_HDA_CODEC_INTELHDMI
 
 config SND_HDA_ELD
        def_bool y
-       depends on SND_HDA_CODEC_INTELHDMI
+       depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
 
 config SND_HDA_CODEC_CIRRUS
        bool "Build Cirrus Logic codec support"
index 315a1c4..24bc195 100644 (file)
@@ -3,7 +3,7 @@ snd-hda-intel-objs := hda_intel.o
 snd-hda-codec-y := hda_codec.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
+snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
@@ -18,7 +18,7 @@ snd-hda-codec-ca0110-objs :=  patch_ca0110.o
 snd-hda-codec-conexant-objs := patch_conexant.o
 snd-hda-codec-via-objs :=      patch_via.o
 snd-hda-codec-nvhdmi-objs :=   patch_nvhdmi.o
-snd-hda-codec-intelhdmi-objs :=        patch_intelhdmi.o hda_eld.o
+snd-hda-codec-intelhdmi-objs :=        patch_intelhdmi.o
 
 # common driver
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
index 76d3c4c..5bd7cf4 100644 (file)
@@ -978,8 +978,9 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
  *
  * Returns 0 if successful, or a negative error code.
  */
-int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-                                   struct hda_codec **codecp)
+int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
+                               unsigned int codec_addr,
+                               struct hda_codec **codecp)
 {
        struct hda_codec *codec;
        char component[31];
@@ -1186,7 +1187,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
  */
 
 /* FIXME: more better hash key? */
-#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
+#define HDA_HASH_KEY(nid, dir, idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
 #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
 #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
 #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
@@ -1356,7 +1357,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
        if (!codec->no_trigger_sense) {
                pincap = snd_hda_query_pin_caps(codec, nid);
                if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
-                       snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+                       snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_SET_PIN_SENSE, 0);
        }
        return snd_hda_codec_read(codec, nid, 0,
                                  AC_VERB_GET_PIN_SENSE, 0);
@@ -1372,8 +1374,8 @@ EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
  */
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
 {
-        u32 sense = snd_hda_pin_sense(codec, nid);
-        return !!(sense & AC_PINSENSE_PRESENCE);
+       u32 sense = snd_hda_pin_sense(codec, nid);
+       return !!(sense & AC_PINSENSE_PRESENCE);
 }
 EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
 
@@ -1952,7 +1954,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        err = snd_hda_ctl_add(codec, 0, kctl);
        if (err < 0)
                return err;
-       
+
        for (s = slaves; *s; s++) {
                struct snd_kcontrol *sctl;
                int i = 0;
@@ -2439,27 +2441,27 @@ static struct snd_kcontrol_new dig_mixes[] = {
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
                .info = snd_hda_spdif_mask_info,
                .get = snd_hda_spdif_cmask_get,
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
                .info = snd_hda_spdif_mask_info,
                .get = snd_hda_spdif_pmask_get,
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
                .info = snd_hda_spdif_mask_info,
                .get = snd_hda_spdif_default_get,
                .put = snd_hda_spdif_default_put,
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
                .info = snd_hda_spdif_out_switch_info,
                .get = snd_hda_spdif_out_switch_get,
                .put = snd_hda_spdif_out_switch_put,
@@ -2610,7 +2612,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol,
 static struct snd_kcontrol_new dig_in_ctls[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
                .info = snd_hda_spdif_in_switch_info,
                .get = snd_hda_spdif_in_switch_get,
                .put = snd_hda_spdif_in_switch_put,
@@ -2618,7 +2620,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = {
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
                .info = snd_hda_spdif_mask_info,
                .get = snd_hda_spdif_in_status_get,
        },
@@ -2883,7 +2885,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
                int err = snd_hda_codec_build_controls(codec);
                if (err < 0) {
                        printk(KERN_ERR "hda_codec: cannot build controls"
-                              "for #%d (error %d)\n", codec->addr, err); 
+                              "for #%d (error %d)\n", codec->addr, err);
                        err = snd_hda_codec_reset(codec);
                        if (err < 0) {
                                printk(KERN_ERR
@@ -2979,8 +2981,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
        val |= channels - 1;
 
        switch (snd_pcm_format_width(format)) {
-       case 8:  val |= 0x00; break;
-       case 16: val |= 0x10; break;
+       case 8:
+               val |= 0x00;
+               break;
+       case 16:
+               val |= 0x10;
+               break;
        case 20:
        case 24:
        case 32:
@@ -3298,7 +3304,8 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
                        return audio_idx[type][i];
 
-       snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]);
+       snd_printk(KERN_WARNING "Too many %s devices\n",
+               snd_hda_pcm_type_name[type]);
        return -EAGAIN;
 }
 
@@ -3336,7 +3343,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
                err = codec->patch_ops.build_pcms(codec);
                if (err < 0) {
                        printk(KERN_ERR "hda_codec: cannot build PCMs"
-                              "for #%d (error %d)\n", codec->addr, err); 
+                              "for #%d (error %d)\n", codec->addr, err);
                        err = snd_hda_codec_reset(codec);
                        if (err < 0) {
                                printk(KERN_ERR
@@ -3466,8 +3473,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
 
 /**
  * snd_hda_check_board_codec_sid_config - compare the current codec
-                                         subsystem ID with the
-                                         config table
+                                       subsystem ID with the
+                                       config table
 
           This is important for Gateway notebooks with SB450 HDA Audio
           where the vendor ID of the PCI device is:
@@ -3607,7 +3614,7 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
  *
  * Increment the power-up counter and power up the hardware really when
  * not turned on yet.
- */ 
+ */
 void snd_hda_power_up(struct hda_codec *codec)
 {
        struct hda_bus *bus = codec->bus;
@@ -3636,7 +3643,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
  *
  * Decrement the power-up counter and schedules the power-off work if
  * the counter rearches to zero.
- */ 
+ */
 void snd_hda_power_down(struct hda_codec *codec)
 {
        --codec->power_count;
@@ -3662,7 +3669,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_down);
  *
  * This function is supposed to be set or called from the check_power_status
  * patch ops.
- */ 
+ */
 int snd_hda_check_amp_list_power(struct hda_codec *codec,
                                 struct hda_loopback_check *check,
                                 hda_nid_t nid)
@@ -3830,7 +3837,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
 {
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
        if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-               set_dig_out_convert(codec, nid, 
+               set_dig_out_convert(codec, nid,
                                    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
                                    -1);
        snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
@@ -4089,13 +4096,13 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
 /*
  * Sort an associated group of pins according to their sequence numbers.
  */
-static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences,
+static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
                                  int num_pins)
 {
        int i, j;
        short seq;
        hda_nid_t nid;
-       
+
        for (i = 0; i < num_pins; i++) {
                for (j = i + 1; j < num_pins; j++) {
                        if (sequences[i] > sequences[j]) {
@@ -4123,7 +4130,7 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences,
  * is detected, one of speaker of HP pins is assigned as the primary
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * if any analog output exists.
- * 
+ *
  * The analog input pins are assigned to input_pins array.
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
@@ -4186,9 +4193,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                case AC_JACK_SPEAKER:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
-                       if (! assoc)
+                       if (!assoc)
                                continue;
-                       if (! assoc_speaker)
+                       if (!assoc_speaker)
                                assoc_speaker = assoc;
                        else if (assoc_speaker != assoc)
                                continue;
@@ -4286,7 +4293,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                              cfg->speaker_outs);
        sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
                              cfg->hp_outs);
-       
+
        /* if we have only one mic, make it AUTO_PIN_MIC */
        if (!cfg->input_pins[AUTO_PIN_MIC] &&
            cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
@@ -4436,7 +4443,7 @@ EXPORT_SYMBOL_HDA(snd_hda_resume);
 /**
  * snd_array_new - get a new element from the given array
  * @array: the array object
- * 
+ *
  * Get a new element from the given array.  If it exceeds the
  * pre-allocated array size, re-allocate the array.
  *
index 4228f2f..dcd2244 100644 (file)
@@ -331,6 +331,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
        return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
                                                 AC_DIPSIZE_ELD_BUF);
 }
+EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
 
 int snd_hdmi_get_eld(struct hdmi_eld *eld,
                     struct hda_codec *codec, hda_nid_t nid)
@@ -366,6 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        kfree(buf);
        return ret;
 }
+EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
 
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 {
@@ -404,6 +406,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
        }
        buf[j] = '\0';  /* necessary when j == 0 */
 }
+EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
 
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 {
@@ -422,6 +425,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
        for (i = 0; i < e->sad_count; i++)
                hdmi_show_short_audio_desc(e->sad + i);
 }
+EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
 
 #ifdef CONFIG_PROC_FS
 
@@ -580,6 +584,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
 
        return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
 
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 {
@@ -588,5 +593,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
                eld->proc_entry = NULL;
        }
 }
+EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
 
 #endif /* CONFIG_PROC_FS */
index d5c93ad..43b7cfb 100644 (file)
@@ -267,7 +267,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define RIRB_INT_MASK          0x05
 
 /* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS         4
+#define AZX_MAX_CODECS         8
+#define AZX_DEFAULT_CODECS     4
 #define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
 
 /* SD_CTL bits */
@@ -1367,6 +1368,7 @@ static void azx_bus_reset(struct hda_bus *bus)
 
 /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
 static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
+       [AZX_DRIVER_NVIDIA] = 8,
        [AZX_DRIVER_TERA] = 1,
 };
 
@@ -1399,7 +1401,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        codecs = 0;
        max_slots = azx_max_codecs[chip->driver_type];
        if (!max_slots)
-               max_slots = AZX_MAX_CODECS;
+               max_slots = AZX_DEFAULT_CODECS;
 
        /* First try to probe all given codec slots */
        for (c = 0; c < max_slots; c++) {
@@ -2263,10 +2265,12 @@ static int azx_dev_free(struct snd_device *device)
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
        {}
 };
 
@@ -2354,6 +2358,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
 static struct snd_pci_quirk msi_black_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
        SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
+       SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
        {}
 };
 
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
new file mode 100644 (file)
index 0000000..2c2bafb
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ *
+ *  patch_hdmi.c - routines for HDMI/DisplayPort codecs
+ *
+ *  Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ *  Authors:
+ *                     Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  Maintained by:
+ *                     Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+struct hdmi_spec {
+       int num_cvts;
+       int num_pins;
+       hda_nid_t cvt[MAX_HDMI_CVTS+1];  /* audio sources */
+       hda_nid_t pin[MAX_HDMI_PINS+1];  /* audio sinks */
+
+       /*
+        * source connection for each pin
+        */
+       hda_nid_t pin_cvt[MAX_HDMI_PINS+1];
+
+       /*
+        * HDMI sink attached to each pin
+        */
+       struct hdmi_eld sink_eld[MAX_HDMI_PINS];
+
+       /*
+        * export one pcm per pipe
+        */
+       struct hda_pcm  pcm_rec[MAX_HDMI_CVTS];
+
+       /*
+        * nvhdmi specific
+        */
+       struct hda_multi_out multiout;
+       unsigned int codec_type;
+};
+
+
+struct hdmi_audio_infoframe {
+       u8 type; /* 0x84 */
+       u8 ver;  /* 0x01 */
+       u8 len;  /* 0x0a */
+
+       u8 checksum;    /* PB0 */
+       u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
+       u8 SS01_SF24;
+       u8 CXT04;
+       u8 CA;
+       u8 LFEPBL01_LSV36_DM_INH7;
+       u8 reserved[5]; /* PB6 - PB10 */
+};
+
+/*
+ * CEA speaker placement:
+ *
+ *        FLH       FCH        FRH
+ *  FLW    FL  FLC   FC   FRC   FR   FRW
+ *
+ *                                  LFE
+ *                     TC
+ *
+ *          RL  RLC   RC   RRC   RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
+ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+       FL  = (1 <<  0),        /* Front Left           */
+       FC  = (1 <<  1),        /* Front Center         */
+       FR  = (1 <<  2),        /* Front Right          */
+       FLC = (1 <<  3),        /* Front Left Center    */
+       FRC = (1 <<  4),        /* Front Right Center   */
+       RL  = (1 <<  5),        /* Rear Left            */
+       RC  = (1 <<  6),        /* Rear Center          */
+       RR  = (1 <<  7),        /* Rear Right           */
+       RLC = (1 <<  8),        /* Rear Left Center     */
+       RRC = (1 <<  9),        /* Rear Right Center    */
+       LFE = (1 << 10),        /* Low Frequency Effect */
+       FLW = (1 << 11),        /* Front Left Wide      */
+       FRW = (1 << 12),        /* Front Right Wide     */
+       FLH = (1 << 13),        /* Front Left High      */
+       FCH = (1 << 14),        /* Front Center High    */
+       FRH = (1 << 15),        /* Front Right High     */
+       TC  = (1 << 16),        /* Top Center           */
+};
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static int eld_speaker_allocation_bits[] = {
+       [0] = FL | FR,
+       [1] = LFE,
+       [2] = FC,
+       [3] = RL | RR,
+       [4] = RC,
+       [5] = FLC | FRC,
+       [6] = RLC | RRC,
+       /* the following are not defined in ELD yet */
+       [7] = FLW | FRW,
+       [8] = FLH | FRH,
+       [9] = TC,
+       [10] = FCH,
+};
+
+struct cea_channel_speaker_allocation {
+       int ca_index;
+       int speakers[8];
+
+       /* derived values, just for convenience */
+       int channels;
+       int spk_mask;
+};
+
+/*
+ * ALSA sequence is:
+ *
+ *       surround40   surround41   surround50   surround51   surround71
+ * ch0   front left   =            =            =            =
+ * ch1   front right  =            =            =            =
+ * ch2   rear left    =            =            =            =
+ * ch3   rear right   =            =            =            =
+ * ch4                LFE          center       center       center
+ * ch5                                          LFE          LFE
+ * ch6                                                       side left
+ * ch7                                                       side right
+ *
+ * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
+ */
+static int hdmi_channel_mapping[0x32][8] = {
+       /* stereo */
+       [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
+       /* 2.1 */
+       [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
+       /* Dolby Surround */
+       [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 },
+       /* surround40 */
+       [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 },
+       /* 4ch */
+       [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
+       /* surround41 */
+       [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
+       /* surround50 */
+       [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
+       /* surround51 */
+       [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 },
+       /* 7.1 */
+       [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 },
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_setup_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/*                       channel:   7     6    5    4    3     2    1    0  */
+{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
+                                /* 2.1 */
+{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
+                                /* Dolby Surround */
+{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
+                                /* surround40 */
+{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
+                                /* surround41 */
+{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
+                                /* surround50 */
+{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+                                /* surround51 */
+{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+                                /* 6.1 */
+{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+                                /* surround71 */
+{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+
+{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
+{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x20,  .speakers = {   0,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x21,  .speakers = {   0,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x22,  .speakers = {  TC,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x23,  .speakers = {  TC,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x24,  .speakers = { FRH,  FLH,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x25,  .speakers = { FRH,  FLH,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x26,  .speakers = { FRW,  FLW,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x27,  .speakers = { FRW,  FLW,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x28,  .speakers = {  TC,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x29,  .speakers = {  TC,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2a,  .speakers = { FCH,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2b,  .speakers = { FCH,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2c,  .speakers = {  TC,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2d,  .speakers = {  TC,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2e,  .speakers = { FRH,  FLH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2f,  .speakers = { FRH,  FLH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x30,  .speakers = { FRW,  FLW,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
+};
+
+
+/*
+ * HDMI routines
+ */
+
+static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
+{
+       int i;
+
+       for (i = 0; nids[i]; i++)
+               if (nids[i] == nid)
+                       return i;
+
+       snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
+       return -EINVAL;
+}
+
+static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
+                             struct hdmi_eld *eld)
+{
+       if (!snd_hdmi_get_eld(eld, codec, pin_nid))
+               snd_hdmi_show_eld(eld);
+}
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+                               int *packet_index, int *byte_index)
+{
+       int val;
+
+       val = snd_hda_codec_read(codec, pin_nid, 0,
+                                AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+       *packet_index = val >> 5;
+       *byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+                               int packet_index, int byte_index)
+{
+       int val;
+
+       val = (packet_index << 5) | (byte_index & 0x1f);
+
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
+                               unsigned char val)
+{
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       /* Unmute */
+       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, pin_nid, 0,
+                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+       /* Enable pin out */
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+}
+
+static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
+{
+       return 1 + snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_GET_CVT_CHAN_COUNT, 0);
+}
+
+static void hdmi_set_channel_count(struct hda_codec *codec,
+                                  hda_nid_t nid, int chs)
+{
+       if (chs != hdmi_get_channel_count(codec, nid))
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
+}
+
+
+/*
+ * Channel mapping routines
+ */
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+       int i, j;
+       struct cea_channel_speaker_allocation *p;
+
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               p = channel_allocations + i;
+               p->channels = 0;
+               p->spk_mask = 0;
+               for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+                       if (p->speakers[j]) {
+                               p->channels++;
+                               p->spk_mask |= p->speakers[j];
+                       }
+       }
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ *     eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ *           spk_mask => (channel_allocations[])         => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+*/
+static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
+                                        struct hdmi_audio_infoframe *ai)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_eld *eld;
+       int i;
+       int spk_mask = 0;
+       int channels = 1 + (ai->CC02_CT47 & 0x7);
+       char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+
+       /*
+        * CA defaults to 0 for basic stereo audio
+        */
+       if (channels <= 2)
+               return 0;
+
+       i = hda_node_index(spec->pin_cvt, nid);
+       if (i < 0)
+               return 0;
+       eld = &spec->sink_eld[i];
+
+       /*
+        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+        * in console or for audio devices. Assume the highest speakers
+        * configuration, to _not_ prohibit multi-channel audio playback.
+        */
+       if (!eld->spk_alloc)
+               eld->spk_alloc = 0xffff;
+
+       /*
+        * expand ELD's speaker allocation mask
+        *
+        * ELD tells the speaker mask in a compact(paired) form,
+        * expand ELD's notions to match the ones used by Audio InfoFrame.
+        */
+       for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+               if (eld->spk_alloc & (1 << i))
+                       spk_mask |= eld_speaker_allocation_bits[i];
+       }
+
+       /* search for the first working match in the CA table */
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               if (channels == channel_allocations[i].channels &&
+                   (spk_mask & channel_allocations[i].spk_mask) ==
+                               channel_allocations[i].spk_mask) {
+                       ai->CA = channel_allocations[i].ca_index;
+                       break;
+               }
+       }
+
+       snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
+       snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
+                   ai->CA, channels, buf);
+
+       return ai->CA;
+}
+
+static void hdmi_debug_channel_mapping(struct hda_codec *codec,
+                                      hda_nid_t pin_nid)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       int i;
+       int slot;
+
+       for (i = 0; i < 8; i++) {
+               slot = snd_hda_codec_read(codec, pin_nid, 0,
+                                               AC_VERB_GET_HDMI_CHAN_SLOT, i);
+               printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+                                               slot >> 4, slot & 0xf);
+       }
+#endif
+}
+
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+                                      hda_nid_t pin_nid,
+                                      struct hdmi_audio_infoframe *ai)
+{
+       int i;
+       int ca = ai->CA;
+       int err;
+
+       if (hdmi_channel_mapping[ca][1] == 0) {
+               for (i = 0; i < channel_allocations[ca].channels; i++)
+                       hdmi_channel_mapping[ca][i] = i | (i << 4);
+               for (; i < 8; i++)
+                       hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
+       }
+
+       for (i = 0; i < 8; i++) {
+               err = snd_hda_codec_write(codec, pin_nid, 0,
+                                         AC_VERB_SET_HDMI_CHAN_SLOT,
+                                         hdmi_channel_mapping[ca][i]);
+               if (err) {
+                       snd_printdd(KERN_NOTICE
+                                   "HDMI: channel mapping failed\n");
+                       break;
+               }
+       }
+
+       hdmi_debug_channel_mapping(codec, pin_nid);
+}
+
+
+/*
+ * Audio InfoFrame routines
+ */
+
+/*
+ * Enable Audio InfoFrame Transmission
+ */
+static void hdmi_start_infoframe_trans(struct hda_codec *codec,
+                                      hda_nid_t pin_nid)
+{
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+                                               AC_DIPXMIT_BEST);
+}
+
+/*
+ * Disable Audio InfoFrame Transmission
+ */
+static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
+                                     hda_nid_t pin_nid)
+{
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+                                               AC_DIPXMIT_DISABLE);
+}
+
+static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       int i;
+       int size;
+
+       size = snd_hdmi_get_eld_size(codec, pin_nid);
+       printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+
+       for (i = 0; i < 8; i++) {
+               size = snd_hda_codec_read(codec, pin_nid, 0,
+                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
+               printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+       }
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef BE_PARANOID
+       int i, j;
+       int size;
+       int pi, bi;
+       for (i = 0; i < 8; i++) {
+               size = snd_hda_codec_read(codec, pin_nid, 0,
+                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
+               if (size == 0)
+                       continue;
+
+               hdmi_set_dip_index(codec, pin_nid, i, 0x0);
+               for (j = 1; j < 1000; j++) {
+                       hdmi_write_dip_byte(codec, pin_nid, 0x0);
+                       hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
+                       if (pi != i)
+                               snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+                                               bi, pi, i);
+                       if (bi == 0) /* byte index wrapped around */
+                               break;
+               }
+               snd_printd(KERN_INFO
+                       "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+                       i, size, j);
+       }
+#endif
+}
+
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
+{
+       u8 *bytes = (u8 *)ai;
+       u8 sum = 0;
+       int i;
+
+       ai->checksum = 0;
+
+       for (i = 0; i < sizeof(*ai); i++)
+               sum += bytes[i];
+
+       ai->checksum = -sum;
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+                                     hda_nid_t pin_nid,
+                                     struct hdmi_audio_infoframe *ai)
+{
+       u8 *bytes = (u8 *)ai;
+       int i;
+
+       hdmi_debug_dip_size(codec, pin_nid);
+       hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
+
+       hdmi_checksum_audio_infoframe(ai);
+
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       for (i = 0; i < sizeof(*ai); i++)
+               hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
+}
+
+static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
+                                   struct hdmi_audio_infoframe *ai)
+{
+       u8 *bytes = (u8 *)ai;
+       u8 val;
+       int i;
+
+       if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
+                                                           != AC_DIPXMIT_BEST)
+               return false;
+
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       for (i = 0; i < sizeof(*ai); i++) {
+               val = snd_hda_codec_read(codec, pin_nid, 0,
+                                        AC_VERB_GET_HDMI_DIP_DATA, 0);
+               if (val != bytes[i])
+                       return false;
+       }
+
+       return true;
+}
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
+                                       struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       hda_nid_t pin_nid;
+       int i;
+       struct hdmi_audio_infoframe ai = {
+               .type           = 0x84,
+               .ver            = 0x01,
+               .len            = 0x0a,
+               .CC02_CT47      = substream->runtime->channels - 1,
+       };
+
+       hdmi_setup_channel_allocation(codec, nid, &ai);
+
+       for (i = 0; i < spec->num_pins; i++) {
+               if (spec->pin_cvt[i] != nid)
+                       continue;
+               if (!spec->sink_eld[i].monitor_present)
+                       continue;
+
+               pin_nid = spec->pin[i];
+               if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
+                       snd_printdd("hdmi_setup_audio_infoframe: "
+                                   "cvt=%d pin=%d channels=%d\n",
+                                   nid, pin_nid,
+                                   substream->runtime->channels);
+                       hdmi_setup_channel_mapping(codec, pin_nid, &ai);
+                       hdmi_stop_infoframe_trans(codec, pin_nid);
+                       hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
+                       hdmi_start_infoframe_trans(codec, pin_nid);
+               }
+       }
+}
+
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int pind = !!(res & AC_UNSOL_RES_PD);
+       int eldv = !!(res & AC_UNSOL_RES_ELDV);
+       int index;
+
+       printk(KERN_INFO
+               "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+               tag, pind, eldv);
+
+       index = hda_node_index(spec->pin, tag);
+       if (index < 0)
+               return;
+
+       spec->sink_eld[index].monitor_present = pind;
+       spec->sink_eld[index].eld_valid = eldv;
+
+       if (pind && eldv) {
+               hdmi_get_show_eld(codec, spec->pin[index],
+                                 &spec->sink_eld[index]);
+               /* TODO: do real things about ELD */
+       }
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+       int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+       int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+       printk(KERN_INFO
+               "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               tag,
+               subtag,
+               cp_state,
+               cp_ready);
+
+       /* TODO */
+       if (cp_state)
+               ;
+       if (cp_ready)
+               ;
+}
+
+
+static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+
+       if (hda_node_index(spec->pin, tag) < 0) {
+               snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+               return;
+       }
+
+       if (subtag == 0)
+               hdmi_intrinsic_event(codec, res);
+       else
+               hdmi_non_intrinsic_event(codec, res);
+}
+
+/*
+ * Callbacks
+ */
+
+static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
+                             u32 stream_tag, int format)
+{
+       int tag;
+       int fmt;
+
+       tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
+       fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
+
+       snd_printdd("hdmi_setup_stream: "
+                   "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n",
+                   nid,
+                   tag == stream_tag ? "" : "new-",
+                   stream_tag,
+                   fmt == format ? "" : "new-",
+                   format);
+
+       if (tag != stream_tag)
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CHANNEL_STREAMID,
+                                   stream_tag << 4);
+       if (fmt != format)
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_STREAM_FORMAT, format);
+}
+
+/*
+ * HDA/HDMI auto parsing
+ */
+
+static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int conn_len, curr;
+       int index;
+
+       if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
+               snd_printk(KERN_WARNING
+                          "HDMI: pin %d wcaps %#x "
+                          "does not support connection list\n",
+                          pin_nid, get_wcaps(codec, pin_nid));
+               return -EINVAL;
+       }
+
+       conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
+                                          HDA_MAX_CONNECTIONS);
+       if (conn_len > 1)
+               curr = snd_hda_codec_read(codec, pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+       else
+               curr = 0;
+
+       index = hda_node_index(spec->pin, pin_nid);
+       if (index < 0)
+               return -EINVAL;
+
+       spec->pin_cvt[index] = conn_list[curr];
+
+       return 0;
+}
+
+static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
+                              struct hdmi_eld *eld)
+{
+       int present = snd_hda_pin_sense(codec, pin_nid);
+
+       eld->monitor_present    = !!(present & AC_PINSENSE_PRESENCE);
+       eld->eld_valid          = !!(present & AC_PINSENSE_ELDV);
+
+       if (present & AC_PINSENSE_ELDV)
+               hdmi_get_show_eld(codec, pin_nid, eld);
+}
+
+static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec->num_pins >= MAX_HDMI_PINS) {
+               snd_printk(KERN_WARNING
+                          "HDMI: no space for pin %d\n", pin_nid);
+               return -EINVAL;
+       }
+
+       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
+
+       spec->pin[spec->num_pins] = pin_nid;
+       spec->num_pins++;
+
+       /*
+        * It is assumed that converter nodes come first in the node list and
+        * hence have been registered and usable now.
+        */
+       return hdmi_read_pin_conn(codec, pin_nid);
+}
+
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec->num_cvts >= MAX_HDMI_CVTS) {
+               snd_printk(KERN_WARNING
+                          "HDMI: no space for converter %d\n", nid);
+               return -EINVAL;
+       }
+
+       spec->cvt[spec->num_cvts] = nid;
+       spec->num_cvts++;
+
+       return 0;
+}
+
+static int hdmi_parse_codec(struct hda_codec *codec)
+{
+       hda_nid_t nid;
+       int i, nodes;
+
+       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+       if (!nid || nodes < 0) {
+               snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < nodes; i++, nid++) {
+               unsigned int caps;
+               unsigned int type;
+
+               caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+               type = get_wcaps_type(caps);
+
+               if (!(caps & AC_WCAP_DIGITAL))
+                       continue;
+
+               switch (type) {
+               case AC_WID_AUD_OUT:
+                       if (hdmi_add_cvt(codec, nid) < 0)
+                               return -EINVAL;
+                       break;
+               case AC_WID_PIN:
+                       caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+                               continue;
+                       if (hdmi_add_pin(codec, nid) < 0)
+                               return -EINVAL;
+                       break;
+               }
+       }
+
+       /*
+        * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
+        * can be lost and presence sense verb will become inaccurate if the
+        * HDA link is powered off at hot plug or hw initialization time.
+        */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
+             AC_PWRST_EPSS))
+               codec->bus->power_keep_link_on = 1;
+#endif
+
+       return 0;
+}
+
index 918f403..88d0351 100644 (file)
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
-#define INTEL_HDMI_CVTS        2
-#define INTEL_HDMI_PINS        3
+#define MAX_HDMI_CVTS  2
+#define MAX_HDMI_PINS  3
 
-static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = {
+#include "patch_hdmi.c"
+
+static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
        "INTEL HDMI 0",
        "INTEL HDMI 1",
 };
 
-struct intel_hdmi_spec {
-       int num_cvts;
-       int num_pins;
-       hda_nid_t cvt[INTEL_HDMI_CVTS+1];  /* audio sources */
-       hda_nid_t pin[INTEL_HDMI_PINS+1];  /* audio sinks */
-
-       /*
-        * source connection for each pin
-        */
-       hda_nid_t pin_cvt[INTEL_HDMI_PINS+1];
-
-       /*
-        * HDMI sink attached to each pin
-        */
-       struct hdmi_eld sink_eld[INTEL_HDMI_PINS];
-
-       /*
-        * export one pcm per pipe
-        */
-       struct hda_pcm  pcm_rec[INTEL_HDMI_CVTS];
-};
-
-struct hdmi_audio_infoframe {
-       u8 type; /* 0x84 */
-       u8 ver;  /* 0x01 */
-       u8 len;  /* 0x0a */
-
-       u8 checksum;    /* PB0 */
-       u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
-       u8 SS01_SF24;
-       u8 CXT04;
-       u8 CA;
-       u8 LFEPBL01_LSV36_DM_INH7;
-       u8 reserved[5]; /* PB6 - PB10 */
-};
-
-/*
- * CEA speaker placement:
- *
- *        FLH       FCH        FRH
- *  FLW    FL  FLC   FC   FRC   FR   FRW
- *
- *                                  LFE
- *                     TC
- *
- *          RL  RLC   RC   RRC   RR
- *
- * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
- * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
- */
-enum cea_speaker_placement {
-       FL  = (1 <<  0),        /* Front Left           */
-       FC  = (1 <<  1),        /* Front Center         */
-       FR  = (1 <<  2),        /* Front Right          */
-       FLC = (1 <<  3),        /* Front Left Center    */
-       FRC = (1 <<  4),        /* Front Right Center   */
-       RL  = (1 <<  5),        /* Rear Left            */
-       RC  = (1 <<  6),        /* Rear Center          */
-       RR  = (1 <<  7),        /* Rear Right           */
-       RLC = (1 <<  8),        /* Rear Left Center     */
-       RRC = (1 <<  9),        /* Rear Right Center    */
-       LFE = (1 << 10),        /* Low Frequency Effect */
-       FLW = (1 << 11),        /* Front Left Wide      */
-       FRW = (1 << 12),        /* Front Right Wide     */
-       FLH = (1 << 13),        /* Front Left High      */
-       FCH = (1 << 14),        /* Front Center High    */
-       FRH = (1 << 15),        /* Front Right High     */
-       TC  = (1 << 16),        /* Top Center           */
-};
-
-/*
- * ELD SA bits in the CEA Speaker Allocation data block
- */
-static int eld_speaker_allocation_bits[] = {
-       [0] = FL | FR,
-       [1] = LFE,
-       [2] = FC,
-       [3] = RL | RR,
-       [4] = RC,
-       [5] = FLC | FRC,
-       [6] = RLC | RRC,
-       /* the following are not defined in ELD yet */
-       [7] = FLW | FRW,
-       [8] = FLH | FRH,
-       [9] = TC,
-       [10] = FCH,
-};
-
-struct cea_channel_speaker_allocation {
-       int ca_index;
-       int speakers[8];
-
-       /* derived values, just for convenience */
-       int channels;
-       int spk_mask;
-};
-
-/*
- * ALSA sequence is:
- *
- *       surround40   surround41   surround50   surround51   surround71
- * ch0   front left   =            =            =            =
- * ch1   front right  =            =            =            =
- * ch2   rear left    =            =            =            =
- * ch3   rear right   =            =            =            =
- * ch4                LFE          center       center       center
- * ch5                                          LFE          LFE
- * ch6                                                       side left
- * ch7                                                       side right
- *
- * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
- */
-static int hdmi_channel_mapping[0x32][8] = {
-       /* stereo */
-       [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
-       /* 2.1 */
-       [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
-       /* Dolby Surround */
-       [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 },
-       /* surround40 */
-       [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 },
-       /* 4ch */
-       [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
-       /* surround41 */
-       [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
-       /* surround50 */
-       [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
-       /* surround51 */
-       [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 },
-       /* 7.1 */
-       [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 },
-};
-
-/*
- * This is an ordered list!
- *
- * The preceding ones have better chances to be selected by
- * hdmi_setup_channel_allocation().
- */
-static struct cea_channel_speaker_allocation channel_allocations[] = {
-/*                       channel:   7     6    5    4    3     2    1    0  */
-{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
-                                /* 2.1 */
-{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
-                                /* Dolby Surround */
-{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
-                                /* surround40 */
-{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
-                                /* surround41 */
-{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
-                                /* surround50 */
-{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
-                                /* surround51 */
-{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
-                                /* 6.1 */
-{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-                                /* surround71 */
-{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-
-{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
-{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
-{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
-{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x20,  .speakers = {   0,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x21,  .speakers = {   0,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x22,  .speakers = {  TC,    0,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x23,  .speakers = {  TC,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x24,  .speakers = { FRH,  FLH,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x25,  .speakers = { FRH,  FLH,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x26,  .speakers = { FRW,  FLW,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x27,  .speakers = { FRW,  FLW,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x28,  .speakers = {  TC,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x29,  .speakers = {  TC,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x2a,  .speakers = { FCH,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x2b,  .speakers = { FCH,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x2c,  .speakers = {  TC,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x2d,  .speakers = {  TC,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x2e,  .speakers = { FRH,  FLH,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x2f,  .speakers = { FRH,  FLH,  RR,  RL,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x30,  .speakers = { FRW,  FLW,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
-};
-
-/*
- * HDA/HDMI auto parsing
- */
-
-static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
-{
-       int i;
-
-       for (i = 0; nids[i]; i++)
-               if (nids[i] == nid)
-                       return i;
-
-       snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
-       return -EINVAL;
-}
-
-static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
-       int conn_len, curr;
-       int index;
-
-       if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
-               snd_printk(KERN_WARNING
-                          "HDMI: pin %d wcaps %#x "
-                          "does not support connection list\n",
-                          pin_nid, get_wcaps(codec, pin_nid));
-               return -EINVAL;
-       }
-
-       conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
-                                          HDA_MAX_CONNECTIONS);
-       if (conn_len > 1)
-               curr = snd_hda_codec_read(codec, pin_nid, 0,
-                                         AC_VERB_GET_CONNECT_SEL, 0);
-       else
-               curr = 0;
-
-       index = hda_node_index(spec->pin, pin_nid);
-       if (index < 0)
-               return -EINVAL;
-
-       spec->pin_cvt[index] = conn_list[curr];
-
-       return 0;
-}
-
-static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
-                             struct hdmi_eld *eld)
-{
-       if (!snd_hdmi_get_eld(eld, codec, pin_nid))
-               snd_hdmi_show_eld(eld);
-}
-
-static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
-                              struct hdmi_eld *eld)
-{
-       int present = snd_hda_pin_sense(codec, pin_nid);
-
-       eld->monitor_present    = !!(present & AC_PINSENSE_PRESENCE);
-       eld->eld_valid          = !!(present & AC_PINSENSE_ELDV);
-
-       if (present & AC_PINSENSE_ELDV)
-               hdmi_get_show_eld(codec, pin_nid, eld);
-}
-
-static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-
-       if (spec->num_pins >= INTEL_HDMI_PINS) {
-               snd_printk(KERN_WARNING
-                          "HDMI: no space for pin %d \n", pin_nid);
-               return -EINVAL;
-       }
-
-       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
-
-       spec->pin[spec->num_pins] = pin_nid;
-       spec->num_pins++;
-
-       /*
-        * It is assumed that converter nodes come first in the node list and
-        * hence have been registered and usable now.
-        */
-       return intel_hdmi_read_pin_conn(codec, pin_nid);
-}
-
-static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-
-       if (spec->num_cvts >= INTEL_HDMI_CVTS) {
-               snd_printk(KERN_WARNING
-                          "HDMI: no space for converter %d \n", nid);
-               return -EINVAL;
-       }
-
-       spec->cvt[spec->num_cvts] = nid;
-       spec->num_cvts++;
-
-       return 0;
-}
-
-static int intel_hdmi_parse_codec(struct hda_codec *codec)
-{
-       hda_nid_t nid;
-       int i, nodes;
-
-       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
-       if (!nid || nodes < 0) {
-               snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < nodes; i++, nid++) {
-               unsigned int caps;
-               unsigned int type;
-
-               caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
-               type = get_wcaps_type(caps);
-
-               if (!(caps & AC_WCAP_DIGITAL))
-                       continue;
-
-               switch (type) {
-               case AC_WID_AUD_OUT:
-                       if (intel_hdmi_add_cvt(codec, nid) < 0)
-                               return -EINVAL;
-                       break;
-               case AC_WID_PIN:
-                       caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-                       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
-                               continue;
-                       if (intel_hdmi_add_pin(codec, nid) < 0)
-                               return -EINVAL;
-                       break;
-               }
-       }
-
-       /*
-        * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
-        * can be lost and presence sense verb will become inaccurate if the
-        * HDA link is powered off at hot plug or hw initialization time.
-        */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
-             AC_PWRST_EPSS))
-               codec->bus->power_keep_link_on = 1;
-#endif
-
-       return 0;
-}
-
-/*
- * HDMI routines
- */
-
-#ifdef BE_PARANOID
-static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
-                               int *packet_index, int *byte_index)
-{
-       int val;
-
-       val = snd_hda_codec_read(codec, pin_nid, 0,
-                                AC_VERB_GET_HDMI_DIP_INDEX, 0);
-
-       *packet_index = val >> 5;
-       *byte_index = val & 0x1f;
-}
-#endif
-
-static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
-                               int packet_index, int byte_index)
-{
-       int val;
-
-       val = (packet_index << 5) | (byte_index & 0x1f);
-
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
-}
-
-static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
-                               unsigned char val)
-{
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
-}
-
-static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-       /* Unmute */
-       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, pin_nid, 0,
-                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-       /* Enable pin out */
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-}
-
-/*
- * Enable Audio InfoFrame Transmission
- */
-static void hdmi_start_infoframe_trans(struct hda_codec *codec,
-                                      hda_nid_t pin_nid)
-{
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
-                                               AC_DIPXMIT_BEST);
-}
-
-/*
- * Disable Audio InfoFrame Transmission
- */
-static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
-                                     hda_nid_t pin_nid)
-{
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
-                                               AC_DIPXMIT_DISABLE);
-}
-
-static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
-{
-       return 1 + snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_CVT_CHAN_COUNT, 0);
-}
-
-static void hdmi_set_channel_count(struct hda_codec *codec,
-                                  hda_nid_t nid, int chs)
-{
-       if (chs != hdmi_get_channel_count(codec, nid))
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
-}
-
-static void hdmi_debug_channel_mapping(struct hda_codec *codec,
-                                      hda_nid_t pin_nid)
-{
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       int i;
-       int slot;
-
-       for (i = 0; i < 8; i++) {
-               slot = snd_hda_codec_read(codec, pin_nid, 0,
-                                               AC_VERB_GET_HDMI_CHAN_SLOT, i);
-               printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
-                                               slot >> 4, slot & 0xf);
-       }
-#endif
-}
-
-
-/*
- * Audio InfoFrame routines
- */
-
-static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       int i;
-       int size;
-
-       size = snd_hdmi_get_eld_size(codec, pin_nid);
-       printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
-
-       for (i = 0; i < 8; i++) {
-               size = snd_hda_codec_read(codec, pin_nid, 0,
-                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
-               printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
-       }
-#endif
-}
-
-static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef BE_PARANOID
-       int i, j;
-       int size;
-       int pi, bi;
-       for (i = 0; i < 8; i++) {
-               size = snd_hda_codec_read(codec, pin_nid, 0,
-                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
-               if (size == 0)
-                       continue;
-
-               hdmi_set_dip_index(codec, pin_nid, i, 0x0);
-               for (j = 1; j < 1000; j++) {
-                       hdmi_write_dip_byte(codec, pin_nid, 0x0);
-                       hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
-                       if (pi != i)
-                               snd_printd(KERN_INFO "dip index %d: %d != %d\n",
-                                               bi, pi, i);
-                       if (bi == 0) /* byte index wrapped around */
-                               break;
-               }
-               snd_printd(KERN_INFO
-                       "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
-                       i, size, j);
-       }
-#endif
-}
-
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
-{
-       u8 *bytes = (u8 *)ai;
-       u8 sum = 0;
-       int i;
-
-       ai->checksum = 0;
-
-       for (i = 0; i < sizeof(*ai); i++)
-               sum += bytes[i];
-
-       ai->checksum = - sum;
-}
-
-static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
-                                     hda_nid_t pin_nid,
-                                     struct hdmi_audio_infoframe *ai)
-{
-       u8 *bytes = (u8 *)ai;
-       int i;
-
-       hdmi_debug_dip_size(codec, pin_nid);
-       hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
-
-       hdmi_checksum_audio_infoframe(ai);
-
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++)
-               hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
-}
-
-/*
- * Compute derived values in channel_allocations[].
- */
-static void init_channel_allocations(void)
-{
-       int i, j;
-       struct cea_channel_speaker_allocation *p;
-
-       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-               p = channel_allocations + i;
-               p->channels = 0;
-               p->spk_mask = 0;
-               for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
-                       if (p->speakers[j]) {
-                               p->channels++;
-                               p->spk_mask |= p->speakers[j];
-                       }
-       }
-}
-
-/*
- * The transformation takes two steps:
- *
- *     eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
- *           spk_mask => (channel_allocations[])         => ai->CA
- *
- * TODO: it could select the wrong CA from multiple candidates.
-*/
-static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
-                                        struct hdmi_audio_infoframe *ai)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld;
-       int i;
-       int spk_mask = 0;
-       int channels = 1 + (ai->CC02_CT47 & 0x7);
-       char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
-
-       /*
-        * CA defaults to 0 for basic stereo audio
-        */
-       if (channels <= 2)
-               return 0;
-
-       i = hda_node_index(spec->pin_cvt, nid);
-       if (i < 0)
-               return 0;
-       eld = &spec->sink_eld[i];
-
-       /*
-        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
-        * in console or for audio devices. Assume the highest speakers
-        * configuration, to _not_ prohibit multi-channel audio playback.
-        */
-       if (!eld->spk_alloc)
-               eld->spk_alloc = 0xffff;
-
-       /*
-        * expand ELD's speaker allocation mask
-        *
-        * ELD tells the speaker mask in a compact(paired) form,
-        * expand ELD's notions to match the ones used by Audio InfoFrame.
-        */
-       for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
-               if (eld->spk_alloc & (1 << i))
-                       spk_mask |= eld_speaker_allocation_bits[i];
-       }
-
-       /* search for the first working match in the CA table */
-       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-               if (channels == channel_allocations[i].channels &&
-                   (spk_mask & channel_allocations[i].spk_mask) ==
-                               channel_allocations[i].spk_mask) {
-                       ai->CA = channel_allocations[i].ca_index;
-                       break;
-               }
-       }
-
-       snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
-       snd_printdd(KERN_INFO
-                       "HDMI: select CA 0x%x for %d-channel allocation: %s\n",
-                       ai->CA, channels, buf);
-
-       return ai->CA;
-}
-
-static void hdmi_setup_channel_mapping(struct hda_codec *codec,
-                                      hda_nid_t pin_nid,
-                                      struct hdmi_audio_infoframe *ai)
-{
-       int i;
-       int ca = ai->CA;
-       int err;
-
-       if (hdmi_channel_mapping[ca][1] == 0) {
-               for (i = 0; i < channel_allocations[ca].channels; i++)
-                       hdmi_channel_mapping[ca][i] = i | (i << 4);
-               for (; i < 8; i++)
-                       hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
-       }
-
-       for (i = 0; i < 8; i++) {
-               err = snd_hda_codec_write(codec, pin_nid, 0,
-                                         AC_VERB_SET_HDMI_CHAN_SLOT,
-                                         hdmi_channel_mapping[ca][i]);
-               if (err) {
-                       snd_printdd(KERN_INFO "HDMI: channel mapping failed\n");
-                       break;
-               }
-       }
-
-       hdmi_debug_channel_mapping(codec, pin_nid);
-}
-
-static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
-                                   struct hdmi_audio_infoframe *ai)
-{
-       u8 *bytes = (u8 *)ai;
-       u8 val;
-       int i;
-
-       if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
-                                                           != AC_DIPXMIT_BEST)
-               return false;
-
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++) {
-               val = snd_hda_codec_read(codec, pin_nid, 0,
-                                        AC_VERB_GET_HDMI_DIP_DATA, 0);
-               if (val != bytes[i])
-                       return false;
-       }
-
-       return true;
-}
-
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
-                                       struct snd_pcm_substream *substream)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       hda_nid_t pin_nid;
-       int i;
-       struct hdmi_audio_infoframe ai = {
-               .type           = 0x84,
-               .ver            = 0x01,
-               .len            = 0x0a,
-               .CC02_CT47      = substream->runtime->channels - 1,
-       };
-
-       hdmi_setup_channel_allocation(codec, nid, &ai);
-
-       for (i = 0; i < spec->num_pins; i++) {
-               if (spec->pin_cvt[i] != nid)
-                       continue;
-               if (!spec->sink_eld[i].monitor_present)
-                       continue;
-
-               pin_nid = spec->pin[i];
-               if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
-                       hdmi_setup_channel_mapping(codec, pin_nid, &ai);
-                       hdmi_stop_infoframe_trans(codec, pin_nid);
-                       hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
-                       hdmi_start_infoframe_trans(codec, pin_nid);
-               }
-       }
-}
-
-
 /*
- * Unsolicited events
+ * HDMI callbacks
  */
 
-static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int pind = !!(res & AC_UNSOL_RES_PD);
-       int eldv = !!(res & AC_UNSOL_RES_ELDV);
-       int index;
-
-       printk(KERN_INFO
-               "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               tag, pind, eldv);
-
-       index = hda_node_index(spec->pin, tag);
-       if (index < 0)
-               return;
-
-       spec->sink_eld[index].monitor_present = pind;
-       spec->sink_eld[index].eld_valid = eldv;
-
-       if (pind && eldv) {
-               hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]);
-               /* TODO: do real things about ELD */
-       }
-}
-
-static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
-{
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
-       int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
-       int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
-
-       printk(KERN_INFO
-               "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
-               tag,
-               subtag,
-               cp_state,
-               cp_ready);
-
-       /* TODO */
-       if (cp_state)
-               ;
-       if (cp_ready)
-               ;
-}
-
-
-static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct intel_hdmi_spec *spec = codec->spec;
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
-
-       if (hda_node_index(spec->pin, tag) < 0) {
-               snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
-               return;
-       }
-
-       if (subtag == 0)
-               hdmi_intrinsic_event(codec, res);
-       else
-               hdmi_non_intrinsic_event(codec, res);
-}
-
-/*
- * Callbacks
- */
-
-static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-                             u32 stream_tag, int format)
-{
-       int tag;
-       int fmt;
-
-       tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
-       fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
-
-       snd_printdd("hdmi_setup_stream: "
-                   "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n",
-                   nid,
-                   tag == stream_tag ? "" : "new-",
-                   stream_tag,
-                   fmt == format ? "" : "new-",
-                   format);
-
-       if (tag != stream_tag)
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID, stream_tag << 4);
-       if (fmt != format)
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_STREAM_FORMAT, format);
-}
-
 static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                           struct hda_codec *codec,
                                           unsigned int stream_tag,
@@ -882,7 +87,7 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = {
 
 static int intel_hdmi_build_pcms(struct hda_codec *codec)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        struct hda_pcm *info = spec->pcm_rec;
        int i;
 
@@ -908,7 +113,7 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec)
 
 static int intel_hdmi_build_controls(struct hda_codec *codec)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        int err;
        int i;
 
@@ -923,7 +128,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec)
 
 static int intel_hdmi_init(struct hda_codec *codec)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        int i;
 
        for (i = 0; spec->pin[i]; i++) {
@@ -937,7 +142,7 @@ static int intel_hdmi_init(struct hda_codec *codec)
 
 static void intel_hdmi_free(struct hda_codec *codec)
 {
-       struct intel_hdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        int i;
 
        for (i = 0; i < spec->num_pins; i++)
@@ -951,12 +156,12 @@ static struct hda_codec_ops intel_hdmi_patch_ops = {
        .free                   = intel_hdmi_free,
        .build_pcms             = intel_hdmi_build_pcms,
        .build_controls         = intel_hdmi_build_controls,
-       .unsol_event            = intel_hdmi_unsol_event,
+       .unsol_event            = hdmi_unsol_event,
 };
 
 static int patch_intel_hdmi(struct hda_codec *codec)
 {
-       struct intel_hdmi_spec *spec;
+       struct hdmi_spec *spec;
        int i;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -964,7 +169,7 @@ static int patch_intel_hdmi(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       if (intel_hdmi_parse_codec(codec) < 0) {
+       if (hdmi_parse_codec(codec) < 0) {
                codec->spec = NULL;
                kfree(spec);
                return -EINVAL;
index 6afdab0..70669a2 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 
+#define MAX_HDMI_CVTS  1
+#define MAX_HDMI_PINS  1
+
+#include "patch_hdmi.c"
+
+static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
+       "NVIDIA HDMI",
+};
+
 /* define below to restrict the supported rates and formats */
 /* #define LIMITED_RATE_FMT_SUPPORT */
 
-struct nvhdmi_spec {
-       struct hda_multi_out multiout;
-
-       struct hda_pcm pcm_rec;
+enum HDACodec {
+       HDA_CODEC_NVIDIA_MCP7X,
+       HDA_CODEC_NVIDIA_MCP89,
+       HDA_CODEC_NVIDIA_GT21X,
+       HDA_CODEC_INVALID
 };
 
 #define Nv_VERB_SET_Channel_Allocation          0xF79
@@ -43,15 +53,18 @@ struct nvhdmi_spec {
 #define Nv_VERB_SET_Audio_Protection_On         0xF98
 #define Nv_VERB_SET_Audio_Protection_Off        0xF99
 
-#define Nv_Master_Convert_nid   0x04
-#define Nv_Master_Pin_nid       0x05
+#define nvhdmi_master_con_nid_7x       0x04
+#define nvhdmi_master_pin_nid_7x       0x05
 
-static hda_nid_t nvhdmi_convert_nids[4] = {
+#define nvhdmi_master_con_nid_89       0x04
+#define nvhdmi_master_pin_nid_89       0x05
+
+static hda_nid_t nvhdmi_con_nids_7x[4] = {
        /*front, rear, clfe, rear_surr */
        0x6, 0x8, 0xa, 0xc,
 };
 
-static struct hda_verb nvhdmi_basic_init[] = {
+static struct hda_verb nvhdmi_basic_init_7x[] = {
        /* set audio protect on */
        { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
        /* enable digital output on pin widget */
@@ -84,22 +97,60 @@ static struct hda_verb nvhdmi_basic_init[] = {
  */
 static int nvhdmi_build_controls(struct hda_codec *codec)
 {
-       struct nvhdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        int err;
+       int i;
 
-       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
-       if (err < 0)
-               return err;
+       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
+       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
+               for (i = 0; i < codec->num_pcms; i++) {
+                       err = snd_hda_create_spdif_out_ctls(codec,
+                                                           spec->cvt[i]);
+                       if (err < 0)
+                               return err;
+               }
+       } else {
+               err = snd_hda_create_spdif_out_ctls(codec,
+                                                   spec->multiout.dig_out_nid);
+               if (err < 0)
+                       return err;
+       }
 
        return 0;
 }
 
 static int nvhdmi_init(struct hda_codec *codec)
 {
-       snd_hda_sequence_write(codec, nvhdmi_basic_init);
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
+       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
+               for (i = 0; spec->pin[i]; i++) {
+                       hdmi_enable_output(codec, spec->pin[i]);
+                       snd_hda_codec_write(codec, spec->pin[i], 0,
+                                           AC_VERB_SET_UNSOLICITED_ENABLE,
+                                           AC_USRSP_EN | spec->pin[i]);
+               }
+       } else {
+               snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
+       }
        return 0;
 }
 
+static void nvhdmi_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
+       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
+               for (i = 0; i < spec->num_pins; i++)
+                       snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+       }
+
+       kfree(spec);
+}
+
 /*
  * Digital out
  */
@@ -107,25 +158,25 @@ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        struct snd_pcm_substream *substream)
 {
-       struct nvhdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
-static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo,
+static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        struct snd_pcm_substream *substream)
 {
-       struct nvhdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        int i;
 
-       snd_hda_codec_write(codec, Nv_Master_Convert_nid,
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
                        0, AC_VERB_SET_CHANNEL_STREAMID, 0);
        for (i = 0; i < 4; i++) {
                /* set the stream id */
-               snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
                                AC_VERB_SET_CHANNEL_STREAMID, 0);
                /* set the stream format */
-               snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
                                AC_VERB_SET_STREAM_FORMAT, 0);
        }
 
@@ -136,10 +187,25 @@ static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        struct snd_pcm_substream *substream)
 {
-       struct nvhdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
+{
+       hdmi_set_channel_count(codec, hinfo->nid,
+                              substream->runtime->channels);
+
+       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+
+       hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+       return 0;
+}
+
 static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        unsigned int stream_tag,
@@ -181,29 +247,29 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
        if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
                snd_hda_codec_write(codec,
-                               Nv_Master_Convert_nid,
+                               nvhdmi_master_con_nid_7x,
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
                                codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
 
        /* set the stream id */
-       snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
                        AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
 
        /* set the stream format */
-       snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
                        AC_VERB_SET_STREAM_FORMAT, format);
 
        /* turn on again (if needed) */
        /* enable and set the channel status audio/data flag */
        if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
                snd_hda_codec_write(codec,
-                               Nv_Master_Convert_nid,
+                               nvhdmi_master_con_nid_7x,
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
                                codec->spdif_ctls & 0xff);
                snd_hda_codec_write(codec,
-                               Nv_Master_Convert_nid,
+                               nvhdmi_master_con_nid_7x,
                                0,
                                AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
        }
@@ -220,19 +286,19 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
                if (codec->spdif_status_reset &&
                (codec->spdif_ctls & AC_DIG1_ENABLE))
                        snd_hda_codec_write(codec,
-                               nvhdmi_convert_nids[i],
+                               nvhdmi_con_nids_7x[i],
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
                                codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
                /* set the stream id */
                snd_hda_codec_write(codec,
-                               nvhdmi_convert_nids[i],
+                               nvhdmi_con_nids_7x[i],
                                0,
                                AC_VERB_SET_CHANNEL_STREAMID,
                                (stream_tag << 4) | channel_id);
                /* set the stream format */
                snd_hda_codec_write(codec,
-                               nvhdmi_convert_nids[i],
+                               nvhdmi_con_nids_7x[i],
                                0,
                                AC_VERB_SET_STREAM_FORMAT,
                                format);
@@ -241,12 +307,12 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
                if (codec->spdif_status_reset &&
                (codec->spdif_ctls & AC_DIG1_ENABLE)) {
                        snd_hda_codec_write(codec,
-                                       nvhdmi_convert_nids[i],
+                                       nvhdmi_con_nids_7x[i],
                                        0,
                                        AC_VERB_SET_DIGI_CONVERT_1,
                                        codec->spdif_ctls & 0xff);
                        snd_hda_codec_write(codec,
-                                       nvhdmi_convert_nids[i],
+                                       nvhdmi_con_nids_7x[i],
                                        0,
                                        AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
                }
@@ -261,28 +327,47 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
        return 0;
 }
 
+static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
 static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        unsigned int stream_tag,
                                        unsigned int format,
                                        struct snd_pcm_substream *substream)
 {
-       struct nvhdmi_spec *spec = codec->spec;
+       struct hdmi_spec *spec = codec->spec;
        return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
                                        format, substream);
 }
 
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = {
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
+       .substreams = 1,
+       .channels_min = 2,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
+               .cleanup = nvhdmi_playback_pcm_cleanup,
+       },
+};
+
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 8,
-       .nid = Nv_Master_Convert_nid,
+       .nid = nvhdmi_master_con_nid_7x,
        .rates = SUPPORTED_RATES,
        .maxbps = SUPPORTED_MAXBPS,
        .formats = SUPPORTED_FORMATS,
        .ops = {
                .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close_8ch,
+               .close = nvhdmi_dig_playback_pcm_close_8ch_7x,
                .prepare = nvhdmi_dig_playback_pcm_prepare_8ch
        },
 };
@@ -291,7 +376,7 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = Nv_Master_Convert_nid,
+       .nid = nvhdmi_master_con_nid_7x,
        .rates = SUPPORTED_RATES,
        .maxbps = SUPPORTED_MAXBPS,
        .formats = SUPPORTED_FORMATS,
@@ -302,10 +387,36 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
        },
 };
 
-static int nvhdmi_build_pcms_8ch(struct hda_codec *codec)
+static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+       int i;
+
+       codec->num_pcms = spec->num_cvts;
+       codec->pcm_info = info;
+
+       for (i = 0; i < codec->num_pcms; i++, info++) {
+               unsigned int chans;
+
+               chans = get_wcaps(codec, spec->cvt[i]);
+               chans = get_wcaps_channels(chans);
+
+               info->name = nvhdmi_pcm_names[i];
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK]
+                                       = nvhdmi_pcm_digital_playback_8ch_89;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
+       }
+
+       return 0;
+}
+
+static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
 {
-       struct nvhdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm_rec;
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
 
        codec->num_pcms = 1;
        codec->pcm_info = info;
@@ -313,15 +424,15 @@ static int nvhdmi_build_pcms_8ch(struct hda_codec *codec)
        info->name = "NVIDIA HDMI";
        info->pcm_type = HDA_PCM_TYPE_HDMI;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_8ch;
+                                       = nvhdmi_pcm_digital_playback_8ch_7x;
 
        return 0;
 }
 
 static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
 {
-       struct nvhdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm_rec;
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
 
        codec->num_pcms = 1;
        codec->pcm_info = info;
@@ -334,14 +445,17 @@ static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
        return 0;
 }
 
-static void nvhdmi_free(struct hda_codec *codec)
-{
-       kfree(codec->spec);
-}
+static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
+       .build_controls = nvhdmi_build_controls,
+       .build_pcms = nvhdmi_build_pcms_8ch_89,
+       .init = nvhdmi_init,
+       .free = nvhdmi_free,
+       .unsol_event = hdmi_unsol_event,
+};
 
-static struct hda_codec_ops nvhdmi_patch_ops_8ch = {
+static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
        .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_8ch,
+       .build_pcms = nvhdmi_build_pcms_8ch_7x,
        .init = nvhdmi_init,
        .free = nvhdmi_free,
 };
@@ -353,9 +467,36 @@ static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
        .free = nvhdmi_free,
 };
 
-static int patch_nvhdmi_8ch(struct hda_codec *codec)
+static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int i;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
+
+       if (hdmi_parse_codec(codec) < 0) {
+               codec->spec = NULL;
+               kfree(spec);
+               return -EINVAL;
+       }
+       codec->patch_ops = nvhdmi_patch_ops_8ch_89;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
+
+       init_channel_allocations();
+
+       return 0;
+}
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
 {
-       struct nvhdmi_spec *spec;
+       struct hdmi_spec *spec;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -365,16 +506,17 @@ static int patch_nvhdmi_8ch(struct hda_codec *codec)
 
        spec->multiout.num_dacs = 0;  /* no analog */
        spec->multiout.max_channels = 8;
-       spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
+       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
+       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
 
-       codec->patch_ops = nvhdmi_patch_ops_8ch;
+       codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
 
        return 0;
 }
 
 static int patch_nvhdmi_2ch(struct hda_codec *codec)
 {
-       struct nvhdmi_spec *spec;
+       struct hdmi_spec *spec;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -384,7 +526,8 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
 
        spec->multiout.num_dacs = 0;  /* no analog */
        spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
+       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
+       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
 
        codec->patch_ops = nvhdmi_patch_ops_2ch;
 
@@ -395,13 +538,24 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
  * patch entries
  */
 static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-       { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
-       { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
-       { .id = 0x10de0005, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
-       { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
-       { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch },
        { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
        { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
+       { .id = 0x10de0002, .name = "MCP77/78 HDMI",
+         .patch = patch_nvhdmi_8ch_7x },
+       { .id = 0x10de0003, .name = "MCP77/78 HDMI",
+         .patch = patch_nvhdmi_8ch_7x },
+       { .id = 0x10de0005, .name = "MCP77/78 HDMI",
+         .patch = patch_nvhdmi_8ch_7x },
+       { .id = 0x10de0006, .name = "MCP77/78 HDMI",
+         .patch = patch_nvhdmi_8ch_7x },
+       { .id = 0x10de0007, .name = "MCP79/7A HDMI",
+         .patch = patch_nvhdmi_8ch_7x },
+       { .id = 0x10de000c, .name = "MCP89 HDMI",
+         .patch = patch_nvhdmi_8ch_89 },
+       { .id = 0x10de000b, .name = "GT21x HDMI",
+         .patch = patch_nvhdmi_8ch_89 },
+       { .id = 0x10de000d, .name = "GT240 HDMI",
+         .patch = patch_nvhdmi_8ch_89 },
        {} /* terminator */
 };
 
@@ -412,9 +566,12 @@ MODULE_ALIAS("snd-hda-codec-id:10de0006");
 MODULE_ALIAS("snd-hda-codec-id:10de0007");
 MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
+MODULE_ALIAS("snd-hda-codec-id:10de000c");
+MODULE_ALIAS("snd-hda-codec-id:10de000b");
+MODULE_ALIAS("snd-hda-codec-id:10de000d");
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
 
 static struct hda_codec_preset_list nvhdmi_list = {
        .preset = snd_hda_preset_nvhdmi,
index e8cbe21..5d2fbb8 100644 (file)
@@ -4915,7 +4915,7 @@ static void fixup_automic_adc(struct hda_codec *codec)
 static void fixup_single_adc(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
+       hda_nid_t pin = 0;
        int i;
 
        /* search for the input pin; there must be only one */
@@ -13561,6 +13561,8 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec,
 static void alc269_quanta_fl1_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
@@ -13656,6 +13658,8 @@ static void alc269_laptop_unsol_event(struct hda_codec *codec,
 static void alc269_laptop_dmic_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
@@ -13666,6 +13670,8 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec)
 static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
@@ -13676,6 +13682,8 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 static void alc269_laptop_amic_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
index 7754db1..dbc4b89 100644 (file)
@@ -68,7 +68,7 @@ static void wm8776_write(struct oxygen *chip,
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
        if (reg < ARRAY_SIZE(data->wm8776_regs)) {
-               if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER)
+               if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
                        value &= ~WM8776_UPDATE;
                data->wm8776_regs[reg] = value;
        }
index 960a227..ad44626 100644 (file)
@@ -1974,9 +1974,9 @@ snd_riptide_proc_read(struct snd_info_entry *entry,
        }
        snd_iprintf(buffer, "Paths:\n");
        i = getpaths(cif, p);
-       while (i--) {
-               snd_iprintf(buffer, "%x->%x ", p[i - 1], p[i]);
-               i--;
+       while (i >= 2) {
+               i -= 2;
+               snd_iprintf(buffer, "%x->%x ", p[i], p[i + 1]);
        }
        snd_iprintf(buffer, "\n");
 }
index b9ef7e4..b68d99f 100644 (file)
@@ -90,12 +90,10 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
        if (reg >= codec->reg_cache_size)
                return -EINVAL;
 
-       reg &= AK4104_REG_MASK;
-       reg |= AK4104_WRITE;
-
        /* only write to the hardware if value has changed */
        if (cache[reg] != value) {
-               u8 tmp[2] = { reg, value };
+               u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value };
+
                if (spi_write(spi, tmp, sizeof(tmp))) {
                        dev_err(&spi->dev, "SPI write failed\n");
                        return -EIO;
index a03bac9..c8b0556 100644 (file)
@@ -427,24 +427,24 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        if (!runtime->hw.rates) {
                printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
        if (!runtime->hw.formats) {
                printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
 
        /* Symmetry only applies if we've already got an active stream. */
        if (cpu_dai->active || codec_dai->active) {
                ret = soc_pcm_apply_symmetry(substream);
                if (ret != 0)
-                       goto machine_err;
+                       goto config_err;
        }
 
        pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
@@ -464,10 +464,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        mutex_unlock(&pcm_mutex);
        return 0;
 
-machine_err:
+config_err:
        if (machine->ops && machine->ops->shutdown)
                machine->ops->shutdown(substream);
 
+machine_err:
+       if (codec_dai->ops->shutdown)
+               codec_dai->ops->shutdown(substream, codec_dai);
+
 codec_dai_err:
        if (platform->pcm_ops->close)
                platform->pcm_ops->close(substream);
index 8c29258..c570ae3 100644 (file)
@@ -22,13 +22,13 @@ config SND_USB_AUDIO
          will be called snd-usb-audio.
 
 config SND_USB_UA101
-       tristate "Edirol UA-101 driver (EXPERIMENTAL)"
+       tristate "Edirol UA-101/UA-1000 driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        select SND_PCM
        select SND_RAWMIDI
        help
-         Say Y here to include support for the Edirol UA-101 audio/MIDI
-         interface.
+         Say Y here to include support for the Edirol UA-101 and UA-1000
+         audio/MIDI interfaces.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-ua101.
index 9d16db0..380f984 100644 (file)
@@ -3,6 +3,6 @@
 
 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev);
 void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len);
-void snd_usb_caiaq_midi_output_done(struct urburb);
+void snd_usb_caiaq_midi_output_done(struct urb *urb);
 
 #endif /* CAIAQ_MIDI_H */
index 4f4ccdf..3d458d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Edirol UA-101 driver
+ * Edirol UA-101/UA-1000 driver
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
  * This driver is free software: you can redistribute it and/or modify
 #include <sound/pcm_params.h>
 #include "usbaudio.h"
 
-MODULE_DESCRIPTION("Edirol UA-101 driver");
+MODULE_DESCRIPTION("Edirol UA-101/1000 driver");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}");
-
-/* I use my UA-1A for testing because I don't have a UA-101 ... */
-#define UA1A_HACK
+MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}");
 
 /*
  * Should not be lower than the minimum scheduling delay of the host
@@ -132,9 +129,6 @@ struct ua101 {
                        dma_addr_t dma;
                } buffers[MAX_MEMORY_BUFFERS];
        } capture, playback;
-
-       unsigned int fps[10];
-       unsigned int frame_counter;
 };
 
 static DEFINE_MUTEX(devices_mutex);
@@ -424,16 +418,6 @@ static void capture_urb_complete(struct urb *urb)
        if (do_period_elapsed)
                snd_pcm_period_elapsed(stream->substream);
 
-       /* for debugging: measure the sample rate relative to the USB clock */
-       ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames;
-       if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) {
-               printk(KERN_DEBUG "capture rate:");
-               for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames)
-                       printk(KERN_CONT " %u", ua->fps[frames]);
-               printk(KERN_CONT "\n");
-               memset(ua->fps, 0, sizeof(ua->fps));
-               ua->frame_counter = 0;
-       }
        return;
 
 stream_stopped:
@@ -1200,13 +1184,30 @@ static int ua101_probe(struct usb_interface *interface,
                .type = QUIRK_MIDI_FIXED_ENDPOINT,
                .data = &midi_ep
        };
+       static const int intf_numbers[2][3] = {
+               {       /* UA-101 */
+                       [INTF_PLAYBACK] = 0,
+                       [INTF_CAPTURE] = 1,
+                       [INTF_MIDI] = 2,
+               },
+               {       /* UA-1000 */
+                       [INTF_CAPTURE] = 1,
+                       [INTF_PLAYBACK] = 2,
+                       [INTF_MIDI] = 3,
+               },
+       };
        struct snd_card *card;
        struct ua101 *ua;
        unsigned int card_index, i;
+       int is_ua1000;
+       const char *name;
        char usb_path[32];
        int err;
 
-       if (interface->altsetting->desc.bInterfaceNumber != 0)
+       is_ua1000 = usb_id->idProduct == 0x0044;
+
+       if (interface->altsetting->desc.bInterfaceNumber !=
+           intf_numbers[is_ua1000][0])
                return -ENODEV;
 
        mutex_lock(&devices_mutex);
@@ -1239,20 +1240,13 @@ static int ua101_probe(struct usb_interface *interface,
        init_waitqueue_head(&ua->rate_feedback_wait);
        init_waitqueue_head(&ua->alsa_playback_wait);
 
-#ifdef UA1A_HACK
-       if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) {
-               ua->intf[2] = interface;
-               ua->intf[0] = usb_ifnum_to_if(ua->dev, 1);
-               ua->intf[1] = usb_ifnum_to_if(ua->dev, 2);
-               usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua);
-               usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua);
-       } else {
-#endif
        ua->intf[0] = interface;
        for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) {
-               ua->intf[i] = usb_ifnum_to_if(ua->dev, i);
+               ua->intf[i] = usb_ifnum_to_if(ua->dev,
+                                             intf_numbers[is_ua1000][i]);
                if (!ua->intf[i]) {
-                       dev_err(&ua->dev->dev, "interface %u not found\n", i);
+                       dev_err(&ua->dev->dev, "interface %u not found\n",
+                               intf_numbers[is_ua1000][i]);
                        err = -ENXIO;
                        goto probe_error;
                }
@@ -1264,39 +1258,19 @@ static int ua101_probe(struct usb_interface *interface,
                        goto probe_error;
                }
        }
-#ifdef UA1A_HACK
-       }
-#endif
 
        snd_card_set_dev(card, &interface->dev);
 
-#ifdef UA1A_HACK
-       if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) {
-               ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE;
-               ua->rate = 44100;
-               ua->packets_per_second = 1000;
-               ua->capture.channels = 2;
-               ua->playback.channels = 2;
-               ua->capture.frame_bytes = 4;
-               ua->playback.frame_bytes = 4;
-               ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2);
-               ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1);
-               ua->capture.max_packet_bytes = 192;
-               ua->playback.max_packet_bytes = 192;
-       } else {
-#endif
        err = detect_usb_format(ua);
        if (err < 0)
                goto probe_error;
-#ifdef UA1A_HACK
-       }
-#endif
 
+       name = usb_id->idProduct == 0x0044 ? "UA-1000" : "UA-101";
        strcpy(card->driver, "UA-101");
-       strcpy(card->shortname, "UA-101");
+       strcpy(card->shortname, name);
        usb_make_path(ua->dev, usb_path, sizeof(usb_path));
        snprintf(ua->card->longname, sizeof(ua->card->longname),
-                "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed",
+                "EDIROL %s (serial %s), %u Hz at %s, %s speed", name,
                 ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path,
                 ua->dev->speed == USB_SPEED_HIGH ? "high" : "full");
 
@@ -1314,24 +1288,18 @@ static int ua101_probe(struct usb_interface *interface,
        if (err < 0)
                goto probe_error;
 
-       err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm);
+       err = snd_pcm_new(card, name, 0, 1, 1, &ua->pcm);
        if (err < 0)
                goto probe_error;
        ua->pcm->private_data = ua;
-       strcpy(ua->pcm->name, "UA-101");
+       strcpy(ua->pcm->name, name);
        snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops);
        snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops);
 
-#ifdef UA1A_HACK
-       if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) {
-#endif
        err = snd_usbmidi_create(card, ua->intf[INTF_MIDI],
                                 &ua->midi_list, &midi_quirk);
        if (err < 0)
                goto probe_error;
-#ifdef UA1A_HACK
-       }
-#endif
 
        err = snd_card_register(card);
        if (err < 0)
@@ -1386,11 +1354,9 @@ static void ua101_disconnect(struct usb_interface *interface)
 }
 
 static struct usb_device_id ua101_ids[] = {
-#ifdef UA1A_HACK
-       { USB_DEVICE(0x0582, 0x0018) },
-#endif
-       { USB_DEVICE(0x0582, 0x007d) },
-       { USB_DEVICE(0x0582, 0x008d) },
+       { USB_DEVICE(0x0582, 0x0044) }, /* UA-1000 high speed */
+       { USB_DEVICE(0x0582, 0x007d) }, /* UA-101 high speed */
+       { USB_DEVICE(0x0582, 0x008d) }, /* UA-101 full speed */
        { }
 };
 MODULE_DEVICE_TABLE(usb, ua101_ids);
index c539f7f..11b0826 100644 (file)
@@ -2483,7 +2483,6 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip,
                                   sample_width, sample_bytes);
                }
                /* check the format byte size */
-               printk(" XXXXX SAMPLE BYTES %d\n", sample_bytes);
                switch (sample_bytes) {
                case 1:
                        pcm_format = SNDRV_PCM_FORMAT_S8;
@@ -2581,6 +2580,9 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
                             chip->usb_id == USB_ID(0x0d8c, 0x0102)) &&
                            fp->altsetting == 5 && fp->maxpacksize == 392)
                                rate = 96000;
+                       /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */
+                       if (rate == 16000 && chip->usb_id == USB_ID(0x041e, 0x4068))
+                               rate = 8000;
                        fp->rate_table[fp->nr_rates] = rate;
                        if (!fp->rate_min || rate < fp->rate_min)
                                fp->rate_min = rate;
@@ -3386,58 +3388,6 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
-/*
- * Create a stream for an Edirol UA-1000 interface.
- */
-static int create_ua1000_quirk(struct snd_usb_audio *chip,
-                              struct usb_interface *iface,
-                              const struct snd_usb_audio_quirk *quirk)
-{
-       static const struct audioformat ua1000_format = {
-               .format = SNDRV_PCM_FORMAT_S32_LE,
-               .fmt_type = UAC_FORMAT_TYPE_I,
-               .altsetting = 1,
-               .altset_idx = 1,
-               .attributes = 0,
-               .rates = SNDRV_PCM_RATE_CONTINUOUS,
-       };
-       struct usb_host_interface *alts;
-       struct usb_interface_descriptor *altsd;
-       struct audioformat *fp;
-       int stream, err;
-
-       if (iface->num_altsetting != 2)
-               return -ENXIO;
-       alts = &iface->altsetting[1];
-       altsd = get_iface_desc(alts);
-       if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE ||
-           altsd->bNumEndpoints != 1)
-               return -ENXIO;
-
-       fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL);
-       if (!fp)
-               return -ENOMEM;
-
-       fp->channels = alts->extra[4];
-       fp->iface = altsd->bInterfaceNumber;
-       fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
-       fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-       fp->datainterval = parse_datainterval(chip, alts);
-       fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
-       fp->rate_max = fp->rate_min = combine_triple(&alts->extra[8]);
-
-       stream = (fp->endpoint & USB_DIR_IN)
-               ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-       err = add_audio_endpoint(chip, stream, fp);
-       if (err < 0) {
-               kfree(fp);
-               return err;
-       }
-       /* FIXME: playback must be synchronized to capture */
-       usb_set_interface(chip->dev, fp->iface, 0);
-       return 0;
-}
-
 static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                                struct usb_interface *iface,
                                const struct snd_usb_audio_quirk *quirk);
@@ -3686,7 +3636,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
-               [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
                [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk
        };
index 6b016d4..42c299c 100644 (file)
@@ -75,7 +75,6 @@ enum quirk_type {
        QUIRK_MIDI_US122L,
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
-       QUIRK_AUDIO_EDIROL_UA1000,
        QUIRK_AUDIO_EDIROL_UAXX,
        QUIRK_AUDIO_ALIGN_TRANSFER,
 
@@ -112,7 +111,7 @@ struct snd_usb_midi_endpoint_info {
 
 /* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
 
-/* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */
+/* for QUIRK_AUDIO_EDIROL_UAXX, data is NULL */
 
 /* for QUIRK_IGNORE_INTERFACE, data is NULL */
 
index f06faf7..2b426c1 100644 (file)
@@ -1015,36 +1015,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       USB_DEVICE(0x0582, 0x0044),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "UA-1000",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_EDIROL_UA1000
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_AUDIO_EDIROL_UA1000
-                       },
-                       {
-                               .ifnum = 3,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0003,
-                                       .in_cables  = 0x0003
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
 {
        /* has ID 0x0049 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0047),