]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 18:17:39 +0000 (11:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 18:17:39 +0000 (11:17 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (97 commits)
  USB: qcserial: add device id for HP devices
  USB: isp1760: Add a delay before reading the SKIPMAP registers in isp1760-hcd.c
  USB: allow malformed LANGID descriptors
  USB: pxa27x_udc: typo fixes and code cleanups
  USB: gadget: gadget zero uses new suspend/resume hooks
  USB: gadget: composite device-level suspend/resume hooks
  USB: r8a66597-hcd: suspend/resume support
  USB: more u32 conversion after transfer_buffer_length and actual_length
  USB: Fix cp2101 USB serial device driver termios functions for console use
  USB: CP2101 New Device ID
  USB: ipaq: handle 4 endpoint devices
  USB: S3C: Move usb-control.h to platform include
  USB: ohci-hcd: Add ARCH_S3C24XX to the ohci-s3c2410.c glue
  USB: pedantic: spelling correction in comment for ch9.h
  USB: host: fix sparse warning: Using plain integer as NULL pointer
  USB: ohci-s3c2410: fix name of bus clock
  USB: ohci-s3c2410: remove <mach/hardware.h> include
  USB: serial: rename cp2101 driver to cp210x
  USB: CP2101 Reduce Error Logging
  USB: CP2101 Support AN205 baud rates
  ...

952 files changed:
Documentation/ABI/testing/ima_policy [new file with mode: 0644]
Documentation/DocBook/Makefile
Documentation/DocBook/alsa-driver-api.tmpl [moved from Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl with 87% similarity]
Documentation/DocBook/uio-howto.tmpl
Documentation/DocBook/writing-an-alsa-driver.tmpl [moved from Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl with 99% similarity]
Documentation/cpu-freq/governors.txt
Documentation/cpu-freq/user-guide.txt
Documentation/dynamic-debug-howto.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sound/alsa/soc/dapm.txt
Documentation/sound/oss/CS4232 [deleted file]
Documentation/sound/oss/Introduction
MAINTAINERS
arch/arm/mach-pxa/e740.c
arch/arm/mach-pxa/e750.c
arch/arm/mach-pxa/h5000.c
arch/arm/mach-pxa/include/mach/eseries-gpio.h
arch/arm/mach-pxa/include/mach/regs-ssp.h
arch/arm/mach-pxa/spitz.c
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2440/dma.c
arch/arm/mach-s3c2443/dma.c
arch/arm/plat-s3c/include/plat/audio.h [moved from arch/arm/mach-s3c2410/include/mach/audio.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h [moved from include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h with 93% similarity]
arch/arm/plat-s3c24xx/include/plat/regs-iis.h [moved from include/asm-arm/plat-s3c24xx/regs-iis.h with 100% similarity]
arch/avr32/boards/hammerhead/flash.c
arch/avr32/include/asm/uaccess.h
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/syscall-stubs.S
arch/avr32/lib/strnlen_user.S
arch/mips/basler/excite/excite_iodev.c
arch/mips/include/asm/mipsregs.h
arch/mips/kernel/linux32.c
arch/mips/kernel/traps.c
arch/mips/mm/c-r4k.c
arch/mips/mm/dma-default.c
arch/powerpc/boot/dts/canyonlands.dts
arch/powerpc/boot/dts/kilauea.dts
arch/powerpc/platforms/ps3/system-bus.c
arch/s390/crypto/sha.h
arch/s390/crypto/sha1_s390.c
arch/s390/crypto/sha256_s390.c
arch/s390/crypto/sha512_s390.c
arch/s390/crypto/sha_common.c
arch/sh/Kconfig
arch/sh/Kconfig.cpu
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-ap325rxa.c
arch/sh/boards/board-espt.c [new file with mode: 0644]
arch/sh/boards/board-polaris.c [new file with mode: 0644]
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/board-urquell.c [new file with mode: 0644]
arch/sh/boards/mach-highlander/Kconfig
arch/sh/boards/mach-hp6xx/pm_wakeup.S
arch/sh/boards/mach-hp6xx/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-rsk/Kconfig
arch/sh/boards/mach-sh7763rdp/setup.c
arch/sh/boot/Makefile
arch/sh/cchips/hd6446x/hd64461.c
arch/sh/configs/espt_defconfig [new file with mode: 0644]
arch/sh/configs/polaris_defconfig [new file with mode: 0644]
arch/sh/configs/sh7785lcr_32bit_defconfig [new file with mode: 0644]
arch/sh/configs/urquell_defconfig [new file with mode: 0644]
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/dma/Makefile
arch/sh/drivers/dma/dma-sh.c
arch/sh/drivers/dma/dma-sh.h [deleted file]
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/atomic-irq.h
arch/sh/include/asm/bitops-llsc.h
arch/sh/include/asm/clock.h
arch/sh/include/asm/cmpxchg-llsc.h
arch/sh/include/asm/cpu-features.h
arch/sh/include/asm/dma-sh.h [new file with mode: 0644]
arch/sh/include/asm/dma.h
arch/sh/include/asm/entry-macros.S
arch/sh/include/asm/gpio.h
arch/sh/include/asm/hd64461.h
arch/sh/include/asm/io.h
arch/sh/include/asm/kprobes.h
arch/sh/include/asm/mmu_context.h
arch/sh/include/asm/mmu_context_32.h
arch/sh/include/asm/page.h
arch/sh/include/asm/processor.h
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/sections.h
arch/sh/include/asm/suspend.h [new file with mode: 0644]
arch/sh/include/asm/timer.h
arch/sh/include/asm/tlb.h
arch/sh/include/cpu-sh3/cpu/dma.h
arch/sh/include/cpu-sh4/cpu/dma-sh4a.h [new file with mode: 0644]
arch/sh/include/cpu-sh4/cpu/dma-sh7780.h [deleted file]
arch/sh/include/cpu-sh4/cpu/dma.h
arch/sh/include/cpu-sh4/cpu/freq.h
arch/sh/include/cpu-sh4/cpu/mmu_context.h
arch/sh/include/cpu-sh4/cpu/sh7786.h [new file with mode: 0644]
arch/sh/include/mach-common/mach/urquell.h [new file with mode: 0644]
arch/sh/kernel/Makefile_32
arch/sh/kernel/asm-offsets.c
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/Makefile
arch/sh/kernel/cpu/sh3/entry.S
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh3/swsusp.S [new file with mode: 0644]
arch/sh/kernel/cpu/sh4/Makefile
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7786.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c [new file with mode: 0644]
arch/sh/kernel/cpu/shmobile/Makefile [new file with mode: 0644]
arch/sh/kernel/cpu/shmobile/pm.c [new file with mode: 0644]
arch/sh/kernel/cpu/shmobile/sleep.S [new file with mode: 0644]
arch/sh/kernel/gpio.c
arch/sh/kernel/irq.c
arch/sh/kernel/machine_kexec.c
arch/sh/kernel/relocate_kernel.S
arch/sh/kernel/setup.c
arch/sh/kernel/swsusp.c [new file with mode: 0644]
arch/sh/kernel/time_32.c
arch/sh/kernel/timers/timer-mtu2.c
arch/sh/kernel/timers/timer-tmu.c
arch/sh/kernel/vmlinux_32.lds.S
arch/sh/mm/Kconfig
arch/sh/mm/Makefile_32
arch/sh/mm/asids-debugfs.c
arch/sh/mm/ioremap_32.c
arch/sh/mm/pmb-fixed.c [new file with mode: 0644]
arch/sh/mm/pmb.c
arch/sh/mm/tlb-pteaex.c [new file with mode: 0644]
arch/sh/oprofile/common.c
arch/sh/tools/mach-types
arch/x86/crypto/Makefile
arch/x86/crypto/aes-i586-asm_32.S
arch/x86/crypto/aes-x86_64-asm_64.S
arch/x86/crypto/aes_glue.c
arch/x86/crypto/aesni-intel_asm.S [new file with mode: 0644]
arch/x86/crypto/aesni-intel_glue.c [new file with mode: 0644]
arch/x86/include/asm/aes.h [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/timer.h
arch/x86/kernel/cpu/cpufreq/Kconfig
arch/x86/kernel/cpu/cpufreq/Makefile
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
arch/x86/kernel/cpu/cpufreq/e_powersaver.c
arch/x86/kernel/cpu/cpufreq/elanfreq.c
arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
arch/x86/kernel/cpu/cpufreq/longhaul.c
arch/x86/kernel/cpu/cpufreq/longhaul.h
arch/x86/kernel/cpu/cpufreq/longrun.c
arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
arch/x86/kernel/cpu/cpufreq/powernow-k6.c
arch/x86/kernel/cpu/cpufreq/powernow-k7.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.h
arch/x86/kernel/cpu/cpufreq/sc520_freq.c
arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
arch/x86/kernel/cpu/cpufreq/speedstep-lib.h
arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
arch/x86/kernel/tsc.c
crypto/Kconfig
crypto/Makefile
crypto/ablkcipher.c
crypto/aead.c
crypto/algboss.c
crypto/ansi_cprng.c
crypto/api.c
crypto/blkcipher.c
crypto/chainiv.c
crypto/cryptd.c
crypto/crypto_wq.c [new file with mode: 0644]
crypto/gf128mul.c
crypto/internal.h
crypto/pcompress.c [new file with mode: 0644]
crypto/sha256_generic.c
crypto/shash.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
crypto/zlib.c [new file with mode: 0644]
drivers/acpi/dock.c
drivers/amba/bus.c
drivers/base/base.h
drivers/base/bus.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/driver.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/sys.c
drivers/block/floppy.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/timeriomem-rng.c [new file with mode: 0644]
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_atmel.c
drivers/char/tpm/tpm_tis.c
drivers/char/vc_screen.c
drivers/char/vt.c
drivers/clocksource/Makefile
drivers/clocksource/sh_cmt.c [new file with mode: 0644]
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/freq_table.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/amcc/Makefile [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_alg.c [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_core.c [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_core.h [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_reg_def.h [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_sa.c [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_sa.h [new file with mode: 0644]
drivers/dio/dio.c
drivers/dma/dw_dmac.c
drivers/edac/cell_edac.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mv64x60_edac.c
drivers/eisa/eisa-bus.c
drivers/gpio/bt8xxgpio.c
drivers/gpu/drm/drm_sysfs.c
drivers/i2c/i2c-core.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/aec62xx.c
drivers/ide/alim15x3.c
drivers/ide/amd74xx.c
drivers/ide/atiixp.c
drivers/ide/au1xxx-ide.c
drivers/ide/cmd64x.c
drivers/ide/cs5520.c
drivers/ide/cs5530.c
drivers/ide/delkin_cb.c
drivers/ide/hpt366.c
drivers/ide/ide-acpi.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-devsets.c [new file with mode: 0644]
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c [new file with mode: 0644]
drivers/ide/ide-io-std.c [new file with mode: 0644]
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-park.c
drivers/ide/ide-pci-generic.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-xfer-mode.c [new file with mode: 0644]
drivers/ide/ide.c
drivers/ide/it821x.c
drivers/ide/ns87415.c
drivers/ide/pdc202xx_new.c
drivers/ide/pdc202xx_old.c
drivers/ide/piix.c
drivers/ide/serverworks.c
drivers/ide/setup-pci.c
drivers/ide/siimage.c
drivers/ide/sis5513.c
drivers/ide/sl82c105.c
drivers/ide/slc90e66.c
drivers/ide/trm290.c
drivers/ide/via82cxxx.c
drivers/input/joystick/maplecontrol.c
drivers/input/keyboard/maple_keyb.c
drivers/input/keyboard/sh_keysc.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/mca/mca-bus.c
drivers/media/radio/radio-tea5764.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/v4l2-device.c
drivers/mfd/mcp-core.c
drivers/mfd/ucb1x00-core.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/of_mmc_spi.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/vmu-flash.c [new file with mode: 0644]
drivers/mtd/nand/excite_nandflash.c
drivers/mtd/nand/ndfc.c
drivers/mtd/onenand/generic.c
drivers/net/arm/ks8695net.c
drivers/net/au1000_eth.c
drivers/net/bfin_mac.c
drivers/net/bmac.c
drivers/net/cpmac.c
drivers/net/declance.c
drivers/net/depca.c
drivers/net/ehea/ehea_main.c
drivers/net/jazzsonic.c
drivers/net/macb.c
drivers/net/macsonic.c
drivers/net/mipsnet.c
drivers/net/mv643xx_eth.c
drivers/net/sb1250-mac.c
drivers/net/smc911x.c
drivers/net/smc91x.c
drivers/net/smsc911x.c
drivers/net/smsc9420.c
drivers/net/tc35815.c
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/usb-notif.c
drivers/net/xtsonic.c
drivers/pci/hotplug/cpqphp_sysfs.c
drivers/pcmcia/au1000_generic.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m32r_cfc.c
drivers/pcmcia/m32r_pcc.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/tcic.c
drivers/pcmcia/vrc4171_card.c
drivers/rapidio/rio-driver.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-twl4030.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/a4000t.c
drivers/scsi/bvme6000_scsi.c
drivers/scsi/mvme16x_scsi.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
drivers/serial/sunzilog.c
drivers/sh/intc.c
drivers/sh/maple/maple.c
drivers/sh/superhyway/superhyway.c
drivers/spi/atmel_spi.c
drivers/spi/mpc52xx_psc_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/omap_uwire.c
drivers/spi/orion_spi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_gpio.c
drivers/spi/spi_imx.c
drivers/spi/spi_mpc83xx.c
drivers/spi/spi_txx9.c
drivers/staging/go7007/snd-go7007.c
drivers/tc/tc.c
drivers/uio/Kconfig
drivers/uio/Makefile
drivers/uio/uio.c
drivers/uio/uio_aec.c [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/imx_udc.c
drivers/usb/host/fhci-dbg.c
drivers/usb/host/fhci-hcd.c
drivers/usb/host/ohci-hcd.c
drivers/video/au1100fb.c
drivers/video/au1200fb.c
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
drivers/video/ps3fb.c
drivers/video/pvr2fb.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/tmiofb.c
drivers/watchdog/rm9k_wdt.c
drivers/zorro/zorro.c
fs/compat.c
fs/exec.c
fs/file_table.c
fs/gfs2/Kconfig
fs/gfs2/Makefile
fs/gfs2/acl.c
fs/gfs2/bmap.c
fs/gfs2/dir.c
fs/gfs2/eaops.c
fs/gfs2/eattr.c
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/glops.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/lock_dlm.c [new file with mode: 0644]
fs/gfs2/locking.c [deleted file]
fs/gfs2/locking/dlm/Makefile [deleted file]
fs/gfs2/locking/dlm/lock.c [deleted file]
fs/gfs2/locking/dlm/lock_dlm.h [deleted file]
fs/gfs2/locking/dlm/main.c [deleted file]
fs/gfs2/locking/dlm/mount.c [deleted file]
fs/gfs2/locking/dlm/sysfs.c [deleted file]
fs/gfs2/locking/dlm/thread.c [deleted file]
fs/gfs2/log.c
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/mount.c
fs/gfs2/mount.h [deleted file]
fs/gfs2/ops_address.c
fs/gfs2/ops_dentry.c
fs/gfs2/ops_export.c
fs/gfs2/ops_file.c
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_super.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/gfs2/super.h
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/gfs2/util.c
fs/inode.c
fs/namei.c
fs/namespace.c
fs/partitions/check.c
fs/sysfs/bin.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/sysfs.h
include/asm-frv/ide.h [deleted file]
include/asm-generic/vmlinux.lds.h
include/asm-mn10300/ide.h [deleted file]
include/asm-mn10300/pci.h
include/crypto/aes.h
include/crypto/compress.h [new file with mode: 0644]
include/crypto/cryptd.h [new file with mode: 0644]
include/crypto/crypto_wq.h [new file with mode: 0644]
include/crypto/hash.h
include/crypto/internal/compress.h [new file with mode: 0644]
include/linux/ata.h
include/linux/audit.h
include/linux/console.h
include/linux/crypto.h
include/linux/device.h
include/linux/dynamic_debug.h [new file with mode: 0644]
include/linux/dynamic_printk.h [deleted file]
include/linux/fs.h
include/linux/ide.h
include/linux/ima.h [new file with mode: 0644]
include/linux/input.h
include/linux/kernel.h
include/linux/kobject.h
include/linux/lm_interface.h [deleted file]
include/linux/maple.h
include/linux/mfd/wm8350/audio.h
include/linux/mfd/wm8400-audio.h
include/linux/mod_devicetable.h
include/linux/mount.h
include/linux/pci_ids.h
include/linux/platform_device.h
include/linux/pm.h
include/linux/sched.h
include/linux/sh_cmt.h [new file with mode: 0644]
include/linux/sh_intc.h
include/linux/timeriomem-rng.h [new file with mode: 0644]
include/linux/tpm.h [new file with mode: 0644]
include/linux/uio_driver.h
include/linux/wimax/debug.h
include/sound/ad1816a.h
include/sound/asound.h
include/sound/atmel-abdac.h [new file with mode: 0644]
include/sound/atmel-ac97c.h [new file with mode: 0644]
include/sound/control.h
include/sound/core.h
include/sound/hwdep.h
include/sound/jack.h
include/sound/pcm.h
include/sound/pxa2xx-lib.h
include/sound/rawmidi.h
include/sound/sb.h
include/sound/sfnt_info.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/uda1341.h [deleted file]
include/sound/version.h
include/sound/wss.h
ipc/shm.c
kernel/module.c
kernel/user.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/dynamic_debug.c [new file with mode: 0644]
lib/dynamic_printk.c [deleted file]
lib/kobject.c
lib/kobject_uevent.c
lib/nlattr.c [moved from net/netlink/attr.c with 99% similarity]
mm/mmap.c
mm/page-writeback.c
mm/shmem.c
net/Kconfig
net/bluetooth/hci_sysfs.c
net/bluetooth/rfcomm/tty.c
net/netfilter/nf_conntrack_pptp.c
net/netlink/Makefile
scripts/Makefile.lib
scripts/mod/file2alias.c
security/Kconfig
security/Makefile
security/inode.c
security/integrity/ima/Kconfig [new file with mode: 0644]
security/integrity/ima/Makefile [new file with mode: 0644]
security/integrity/ima/ima.h [new file with mode: 0644]
security/integrity/ima/ima_api.c [new file with mode: 0644]
security/integrity/ima/ima_audit.c [new file with mode: 0644]
security/integrity/ima/ima_crypto.c [new file with mode: 0644]
security/integrity/ima/ima_fs.c [new file with mode: 0644]
security/integrity/ima/ima_iint.c [new file with mode: 0644]
security/integrity/ima/ima_init.c [new file with mode: 0644]
security/integrity/ima/ima_main.c [new file with mode: 0644]
security/integrity/ima/ima_policy.c [new file with mode: 0644]
security/integrity/ima/ima_queue.c [new file with mode: 0644]
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/permission.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/av_perm_to_string.h
security/selinux/include/av_permissions.h
security/selinux/include/objsec.h
security/selinux/include/security.h
security/selinux/nlmsgtab.c
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/Kconfig [new file with mode: 0644]
security/tomoyo/Makefile [new file with mode: 0644]
security/tomoyo/common.c [new file with mode: 0644]
security/tomoyo/common.h [new file with mode: 0644]
security/tomoyo/domain.c [new file with mode: 0644]
security/tomoyo/file.c [new file with mode: 0644]
security/tomoyo/realpath.c [new file with mode: 0644]
security/tomoyo/realpath.h [new file with mode: 0644]
security/tomoyo/tomoyo.c [new file with mode: 0644]
security/tomoyo/tomoyo.h [new file with mode: 0644]
sound/Kconfig
sound/Makefile
sound/aoa/aoa-gpio.h
sound/aoa/core/alsa.c
sound/aoa/core/gpio-feature.c
sound/aoa/fabrics/layout.c
sound/aoa/soundbus/i2sbus/core.c
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/aaci.c
sound/arm/pxa2xx-ac97-lib.c
sound/arm/pxa2xx-ac97.c
sound/arm/sa11xx-uda1341.c [deleted file]
sound/atmel/Kconfig [new file with mode: 0644]
sound/atmel/Makefile [new file with mode: 0644]
sound/atmel/abdac.c [new file with mode: 0644]
sound/atmel/ac97c.c [new file with mode: 0644]
sound/atmel/ac97c.h [new file with mode: 0644]
sound/core/hwdep.c
sound/core/init.c
sound/core/jack.c
sound/core/misc.c
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_plugin.h
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/pcm_timer.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/seq_prioq.c
sound/core/vmaster.c
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mtpav.c
sound/drivers/mts64.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl3/opl3_oss.c
sound/drivers/opl3/opl3_synth.c
sound/drivers/pcsp/pcsp.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_hwdep.c
sound/drivers/vx/vx_uer.c
sound/i2c/Makefile
sound/i2c/l3/Makefile [deleted file]
sound/i2c/l3/uda1341.c [deleted file]
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848.c
sound/isa/adlib.c
sound/isa/als100.c
sound/isa/azt2320.c
sound/isa/cmi8330.c
sound/isa/cs423x/Makefile
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4232.c [deleted file]
sound/isa/cs423x/cs4236.c
sound/isa/cs423x/cs4236_lib.c
sound/isa/dt019x.c
sound/isa/es1688/es1688.c
sound/isa/es1688/es1688_lib.c
sound/isa/es18xx.c
sound/isa/gus/gus_dma.c
sound/isa/gus/gus_irq.c
sound/isa/gus/gus_pcm.c
sound/isa/gus/gus_uart.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/msnd/Makefile [new file with mode: 0644]
sound/isa/msnd/msnd.c [new file with mode: 0644]
sound/isa/msnd/msnd.h [new file with mode: 0644]
sound/isa/msnd/msnd_classic.c [new file with mode: 0644]
sound/isa/msnd/msnd_classic.h [new file with mode: 0644]
sound/isa/msnd/msnd_midi.c [new file with mode: 0644]
sound/isa/msnd/msnd_pinnacle.c [new file with mode: 0644]
sound/isa/msnd/msnd_pinnacle.h [new file with mode: 0644]
sound/isa/msnd/msnd_pinnacle_mixer.c [new file with mode: 0644]
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/es968.c
sound/isa/sb/sb16.c
sound/isa/sb/sb8.c
sound/isa/sb/sb_mixer.c
sound/isa/sc6000.c
sound/isa/sgalaxy.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/isa/wavefront/wavefront_synth.c
sound/isa/wss/wss_lib.c
sound/mips/au1x00.c
sound/mips/hal2.c
sound/mips/sgio2audio.c
sound/oss/ad1848.c
sound/oss/dmabuf.c
sound/oss/pas2_card.c
sound/oss/pss.c
sound/oss/sequencer.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_proc.c
sound/pci/ad1889.c
sound/pci/ak4531_codec.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/au88x0/au88x0_a3d.c
sound/pci/au88x0/au88x0_core.c
sound/pci/au88x0/au88x0_synth.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/cs46xx_lib.h
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/echoaudio/Makefile
sound/pci/echoaudio/echo3g_dsp.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/echoaudio/echoaudio_3g.c
sound/pci/echoaudio/echoaudio_dsp.c
sound/pci/echoaudio/echoaudio_dsp.h
sound/pci/echoaudio/gina20_dsp.c
sound/pci/echoaudio/indigo_dsp.c
sound/pci/echoaudio/indigo_express_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/indigodj_dsp.c
sound/pci/echoaudio/indigodjx.c [new file with mode: 0644]
sound/pci/echoaudio/indigodjx_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/indigoio_dsp.c
sound/pci/echoaudio/indigoiox.c [new file with mode: 0644]
sound/pci/echoaudio/indigoiox_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/layla20_dsp.c
sound/pci/echoaudio/mia_dsp.c
sound/pci/echoaudio/midi.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/p16v.c
sound/pci/emu10k1/voice.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/prodigy192.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/hifier.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr.h
sound/pci/pcxhr/pcxhr_core.h
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/pcxhr/pcxhr_mix22.c
sound/pci/pcxhr/pcxhr_mix22.h
sound/pci/pcxhr/pcxhr_mixer.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/pdaudiocf/pdaudiocf_core.c
sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/Kconfig
sound/ppc/awacs.c
sound/ppc/burgundy.c
sound/ppc/daca.c
sound/ppc/pmac.c
sound/ppc/powermac.c
sound/ppc/snd_ps3.c
sound/ppc/tumbler.c
sound/sh/Kconfig
sound/sh/aica.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/playpaq_wm8510.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/ad73311.h
sound/soc/codecs/ak4104.c [new file with mode: 0644]
sound/soc/codecs/ak4104.h [new file with mode: 0644]
sound/soc/codecs/ak4535.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8350.h
sound/soc/codecs/wm8400.c [new file with mode: 0644]
sound/soc/codecs/wm8400.h [new file with mode: 0644]
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8580.h
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm9705.c [new file with mode: 0644]
sound/soc/codecs/wm9705.h [new file with mode: 0644]
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-sffsdr.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_ssi.h
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/sdp3430.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c [new file with mode: 0644]
sound/soc/pxa/e750_wm9705.c [new file with mode: 0644]
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/mioa701_wm9713.c [new file with mode: 0644]
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/zylonite.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/jive_wm8750.c [new file with mode: 0644]
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c-i2s-v2.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c-i2s-v2.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2412-i2s.h
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-pcm.c
sound/soc/s3c24xx/s3c24xx_uda134x.c
sound/soc/s3c24xx/s3c64xx-i2s.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c64xx-i2s.h [new file with mode: 0644]
sound/soc/sh/hac.c
sound/soc/sh/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c [new file with mode: 0644]
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/spi/at73c213.c
sound/synth/emux/emux_hwdep.c
sound/synth/emux/emux_oss.c
sound/synth/emux/emux_seq.c
sound/synth/emux/emux_synth.c
sound/synth/emux/soundfont.c
sound/usb/Kconfig
sound/usb/caiaq/caiaq-audio.c
sound/usb/caiaq/caiaq-control.c
sound/usb/caiaq/caiaq-device.c
sound/usb/caiaq/caiaq-device.h
sound/usb/usbaudio.c
sound/usb/usbmixer.c
sound/usb/usbmixer_maps.c
sound/usb/usbquirks.h
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usX2Yhwdep.c
sound/usb/usx2y/usb_stream.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usx2yhwdeppcm.h

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
new file mode 100644 (file)
index 0000000..6434f0d
--- /dev/null
@@ -0,0 +1,61 @@
+What:          security/ima/policy
+Date:          May 2008
+Contact:       Mimi Zohar <zohar@us.ibm.com>
+Description:
+               The Trusted Computing Group(TCG) runtime Integrity
+               Measurement Architecture(IMA) maintains a list of hash
+               values of executables and other sensitive system files
+               loaded into the run-time of this system.  At runtime,
+               the policy can be constrained based on LSM specific data.
+               Policies are loaded into the securityfs file ima/policy
+               by opening the file, writing the rules one at a time and
+               then closing the file.  The new policy takes effect after
+               the file ima/policy is closed.
+
+               rule format: action [condition ...]
+
+               action: measure | dont_measure
+               condition:= base | lsm
+                       base:   [[func=] [mask=] [fsmagic=] [uid=]]
+                       lsm:    [[subj_user=] [subj_role=] [subj_type=]
+                                [obj_user=] [obj_role=] [obj_type=]]
+
+               base:   func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
+                       mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
+                       fsmagic:= hex value
+                       uid:= decimal value
+               lsm:    are LSM specific
+
+               default policy:
+                       # PROC_SUPER_MAGIC
+                       dont_measure fsmagic=0x9fa0
+                       # SYSFS_MAGIC
+                       dont_measure fsmagic=0x62656572
+                       # DEBUGFS_MAGIC
+                       dont_measure fsmagic=0x64626720
+                       # TMPFS_MAGIC
+                       dont_measure fsmagic=0x01021994
+                       # SECURITYFS_MAGIC
+                       dont_measure fsmagic=0x73636673
+
+                       measure func=BPRM_CHECK
+                       measure func=FILE_MMAP mask=MAY_EXEC
+                       measure func=INODE_PERM mask=MAY_READ uid=0
+
+               The default policy measures all executables in bprm_check,
+               all files mmapped executable in file_mmap, and all files
+               open for read by root in inode_permission.
+
+               Examples of LSM specific definitions:
+
+               SELinux:
+                       # SELINUX_MAGIC
+                       dont_measure fsmagic=0xF97CFF8C
+
+                       dont_measure obj_type=var_log_t
+                       dont_measure obj_type=auditd_log_t
+                       measure subj_user=system_u func=INODE_PERM mask=MAY_READ
+                       measure subj_role=system_r func=INODE_PERM mask=MAY_READ
+
+               Smack:
+                       measure subj_user=_ func=INODE_PERM mask=MAY_READ
index 1462ed86d40aec28e0d54e947c93ad43f22333ae..a3a83d38f96fa44a1d17d917e297959cce5036fc 100644 (file)
@@ -12,7 +12,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
-           mac80211.xml debugobjects.xml sh.xml regulator.xml
+           mac80211.xml debugobjects.xml sh.xml regulator.xml \
+           alsa-driver-api.xml writing-an-alsa-driver.xml
 
 ###
 # The build process is as follows (targets):
similarity index 87%
rename from Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
rename to Documentation/DocBook/alsa-driver-api.tmpl
index 9d644f7e241e43a0df46189ce3d5a678c0addcb0..0230a96f0564ec6cab7a250e10a7ae62ee41558a 100644 (file)
@@ -1,11 +1,11 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<book>
-<?dbhtml filename="index.html">
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <!-- ****************************************************** -->
 <!-- Header  -->
 <!-- ****************************************************** -->
+<book id="ALSA-Driver-API">
   <bookinfo>
     <title>The ALSA Driver API</title>
 
@@ -35,6 +35,8 @@
 
   </bookinfo>
 
+<toc></toc>
+
   <chapter><title>Management of Cards and Devices</title>
      <sect1><title>Card Management</title>
 !Esound/core/init.c
 !Esound/pci/ac97/ac97_codec.c
 !Esound/pci/ac97/ac97_pcm.c
      </sect1>
+     <sect1><title>Virtual Master Control API</title>
+!Esound/core/vmaster.c
+!Iinclude/sound/control.h
+     </sect1>
   </chapter>
   <chapter><title>MIDI API</title>
      <sect1><title>Raw MIDI API</title>
@@ -88,6 +94,9 @@
   <chapter><title>Miscellaneous Functions</title>
      <sect1><title>Hardware-Dependent Devices API</title>
 !Esound/core/hwdep.c
+     </sect1>
+     <sect1><title>Jack Abstraction Layer API</title>
+!Esound/core/jack.c
      </sect1>
      <sect1><title>ISA DMA Helpers</title>
 !Esound/core/isadma.c
index 52e1b79ce0e6aaa1fabc209921966ab5a6cd7d66..8f6e3b2403c717f1d6df409440773b898f5af31c 100644 (file)
@@ -41,6 +41,13 @@ GPL version 2.
 </abstract>
 
 <revhistory>
+       <revision>
+       <revnumber>0.8</revnumber>
+       <date>2008-12-24</date>
+       <authorinitials>hjk</authorinitials>
+       <revremark>Added name attributes in mem and portio sysfs directories.
+               </revremark>
+       </revision>
        <revision>
        <revnumber>0.7</revnumber>
        <date>2008-12-23</date>
@@ -303,10 +310,17 @@ interested in translating it, please email me
        appear if the size of the mapping is not 0.
 </para>
 <para>
-       Each <filename>mapX/</filename> directory contains two read-only files
-       that show start address and size of the memory:
+       Each <filename>mapX/</filename> directory contains four read-only files
+       that show attributes of the memory:
 </para>
 <itemizedlist>
+<listitem>
+       <para>
+       <filename>name</filename>: A string identifier for this mapping. This
+       is optional, the string can be empty. Drivers can set this to make it
+       easier for userspace to find the correct mapping.
+       </para>
+</listitem>
 <listitem>
        <para>
        <filename>addr</filename>: The address of memory that can be mapped.
@@ -366,10 +380,17 @@ offset = N * getpagesize();
        <filename>/sys/class/uio/uioX/portio/</filename>.
 </para>
 <para>
-       Each <filename>portX/</filename> directory contains three read-only
-       files that show start, size, and type of the port region:
+       Each <filename>portX/</filename> directory contains four read-only
+       files that show name, start, size, and type of the port region:
 </para>
 <itemizedlist>
+<listitem>
+       <para>
+       <filename>name</filename>: A string identifier for this port region.
+       The string is optional and can be empty. Drivers can set it to make it
+       easier for userspace to find a certain port region.
+       </para>
+</listitem>
 <listitem>
        <para>
        <filename>start</filename>: The first port of this region.
similarity index 99%
rename from Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
rename to Documentation/DocBook/writing-an-alsa-driver.tmpl
index 87a7c07ab6581ecd6a96d354ac5920e633548ea8..46b08fef37445b4d0455f570e1fe65871a053dda 100644 (file)
@@ -1,11 +1,11 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<book>
-<?dbhtml filename="index.html">
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
 
 <!-- ****************************************************** -->
 <!-- Header  -->
 <!-- ****************************************************** -->
+<book id="Writing-an-ALSA-Driver">
   <bookinfo>
     <title>Writing an ALSA Driver</title>
     <author>
           }
 
           /* (2) */
-          card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-          if (card == NULL)
-                  return -ENOMEM;
+          err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+          if (err < 0)
+                  return err;
 
           /* (3) */
           err = snd_mychip_create(card, pci, &chip);
             <programlisting>
 <![CDATA[
   struct snd_card *card;
+  int err;
   ....
-  card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+  err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
 ]]>
             </programlisting>
           </informalexample>
 
       <para>
         As mentioned above, to create a card instance, call
-      <function>snd_card_new()</function>.
+      <function>snd_card_create()</function>.
 
         <informalexample>
           <programlisting>
 <![CDATA[
   struct snd_card *card;
-  card = snd_card_new(index, id, module, extra_size);
+  int err;
+  err = snd_card_create(index, id, module, extra_size, &card);
 ]]>
           </programlisting>
         </informalexample>
       </para>
 
       <para>
-        The function takes four arguments, the card-index number, the
+        The function takes five arguments, the card-index number, the
         id string, the module pointer (usually
         <constant>THIS_MODULE</constant>),
-        and the size of extra-data space.  The last argument is used to
+        the size of extra-data space, and the pointer to return the
+        card instance.  The extra_size argument is used to
         allocate card-&gt;private_data for the
         chip-specific data.  Note that these data
-        are allocated by <function>snd_card_new()</function>.
+        are allocated by <function>snd_card_create()</function>.
       </para>
     </section>
 
       </para>
 
       <section id="card-management-chip-specific-snd-card-new">
-        <title>1. Allocating via <function>snd_card_new()</function>.</title>
+        <title>1. Allocating via <function>snd_card_create()</function>.</title>
         <para>
           As mentioned above, you can pass the extra-data-length
-         to the 4th argument of <function>snd_card_new()</function>, i.e.
+         to the 4th argument of <function>snd_card_create()</function>, i.e.
 
           <informalexample>
             <programlisting>
 <![CDATA[
-  card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct mychip));
+  err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                        sizeof(struct mychip), &card);
 ]]>
             </programlisting>
           </informalexample>
 
         <para>
           After allocating a card instance via
-          <function>snd_card_new()</function> (with
-          <constant>NULL</constant> on the 4th arg), call
+          <function>snd_card_create()</function> (with
+          <constant>0</constant> on the 4th arg), call
           <function>kzalloc()</function>. 
 
           <informalexample>
 <![CDATA[
   struct snd_card *card;
   struct mychip *chip;
-  card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
+  err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
   .....
   chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 ]]>
@@ -5750,8 +5754,9 @@ struct _snd_pcm_runtime {
           ....
           struct snd_card *card;
           struct mychip *chip;
+          int err;
           ....
-          card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
+          err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
           ....
           chip = kzalloc(sizeof(*chip), GFP_KERNEL);
           ....
@@ -5763,7 +5768,7 @@ struct _snd_pcm_runtime {
       </informalexample>
 
        When you created the chip data with
-       <function>snd_card_new()</function>, it's anyway accessible
+       <function>snd_card_create()</function>, it's anyway accessible
        via <structfield>private_data</structfield> field.
 
       <informalexample>
@@ -5775,9 +5780,10 @@ struct _snd_pcm_runtime {
           ....
           struct snd_card *card;
           struct mychip *chip;
+          int err;
           ....
-          card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                              sizeof(struct mychip));
+          err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                                sizeof(struct mychip), &card);
           ....
           chip = card->private_data;
           ....
index 5b0cfa67aff9c89ebc6d0f9dd4d467e8be8ae71f..ce73f3eb5ddb1a99a1b4571d6e058ac5c9823765 100644 (file)
@@ -117,10 +117,28 @@ accessible parameters:
 sampling_rate: measured in uS (10^-6 seconds), this is how often you
 want the kernel to look at the CPU usage and to make decisions on
 what to do about the frequency.  Typically this is set to values of
-around '10000' or more.
-
-show_sampling_rate_(min|max): the minimum and maximum sampling rates
-available that you may set 'sampling_rate' to.
+around '10000' or more. It's default value is (cmp. with users-guide.txt):
+transition_latency * 1000
+The lowest value you can set is:
+transition_latency * 100 or it may get restricted to a value where it
+makes not sense for the kernel anymore to poll that often which depends
+on your HZ config variable (HZ=1000: max=20000us, HZ=250: max=5000).
+Be aware that transition latency is in ns and sampling_rate is in us, so you
+get the same sysfs value by default.
+Sampling rate should always get adjusted considering the transition latency
+To set the sampling rate 750 times as high as the transition latency
+in the bash (as said, 1000 is default), do:
+echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \
+    >ondemand/sampling_rate
+
+show_sampling_rate_(min|max): THIS INTERFACE IS DEPRECATED, DON'T USE IT.
+You can use wider ranges now and the general
+cpuinfo_transition_latency variable (cmp. with user-guide.txt) can be
+used to obtain exactly the same info:
+show_sampling_rate_min = transtition_latency * 500    / 1000
+show_sampling_rate_max = transtition_latency * 500000 / 1000
+(divided by 1000 is to illustrate that sampling rate is in us and
+transition latency is exported ns).
 
 up_threshold: defines what the average CPU usage between the samplings
 of 'sampling_rate' needs to be for the kernel to make a decision on
index 917918f84fc75ac09061be1f1f242159823983cf..75f41193f3e1858b2370a2f4500caf49d2b90360 100644 (file)
@@ -152,6 +152,18 @@ cpuinfo_min_freq :         this file shows the minimum operating
                                frequency the processor can run at(in kHz) 
 cpuinfo_max_freq :             this file shows the maximum operating
                                frequency the processor can run at(in kHz) 
+cpuinfo_transition_latency     The time it takes on this CPU to
+                               switch between two frequencies in nano
+                               seconds. If unknown or known to be
+                               that high that the driver does not
+                               work with the ondemand governor, -1
+                               (CPUFREQ_ETERNAL) will be returned.
+                               Using this information can be useful
+                               to choose an appropriate polling
+                               frequency for a kernel governor or
+                               userspace daemon. Make sure to not
+                               switch the frequency too often
+                               resulting in performance loss.
 scaling_driver :               this file shows what cpufreq driver is
                                used to set the frequency on this CPU
 
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
new file mode 100644 (file)
index 0000000..674c566
--- /dev/null
@@ -0,0 +1,240 @@
+
+Introduction
+============
+
+This document describes how to use the dynamic debug (ddebug) feature.
+
+Dynamic debug is designed to allow you to dynamically enable/disable kernel
+code to obtain additional kernel information. Currently, if
+CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_debug() calls can be
+dynamically enabled per-callsite.
+
+Dynamic debug has even more useful features:
+
+ * Simple query language allows turning on and off debugging statements by
+   matching any combination of:
+
+   - source filename
+   - function name
+   - line number (including ranges of line numbers)
+   - module name
+   - format string
+
+ * Provides a debugfs control file: <debugfs>/dynamic_debug/control which can be
+   read to display the complete list of known debug statements, to help guide you
+
+Controlling dynamic debug Behaviour
+===============================
+
+The behaviour of pr_debug()/dev_debug()s are controlled via writing to a
+control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs
+filesystem, in order to make use of this feature. Subsequently, we refer to the
+control file as: <debugfs>/dynamic_debug/control. For example, if you want to
+enable printing from source file 'svcsock.c', line 1603 you simply do:
+
+nullarbor:~ # echo 'file svcsock.c line 1603 +p' >
+                               <debugfs>/dynamic_debug/control
+
+If you make a mistake with the syntax, the write will fail thus:
+
+nullarbor:~ # echo 'file svcsock.c wtf 1 +p' >
+                               <debugfs>/dynamic_debug/control
+-bash: echo: write error: Invalid argument
+
+Viewing Dynamic Debug Behaviour
+===========================
+
+You can view the currently configured behaviour of all the debug statements
+via:
+
+nullarbor:~ # cat <debugfs>/dynamic_debug/control
+# filename:lineno [module]function flags format
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline       : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth         : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests     : %d\012"
+...
+
+
+You can also apply standard Unix text manipulation filters to this
+data, e.g.
+
+nullarbor:~ # grep -i rdma <debugfs>/dynamic_debug/control  | wc -l
+62
+
+nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l
+42
+
+Note in particular that the third column shows the enabled behaviour
+flags for each debug statement callsite (see below for definitions of the
+flags).  The default value, no extra behaviour enabled, is "-".  So
+you can view all the debug statement callsites with any non-default flags:
+
+nullarbor:~ # awk '$3 != "-"' <debugfs>/dynamic_debug/control
+# filename:lineno [module]function flags format
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
+
+
+Command Language Reference
+==========================
+
+At the lexical level, a command comprises a sequence of words separated
+by whitespace characters.  Note that newlines are treated as word
+separators and do *not* end a command or allow multiple commands to
+be done together.  So these are all equivalent:
+
+nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
+                               <debugfs>/dynamic_debug/control
+nullarbor:~ # echo -c '  file   svcsock.c     line  1603 +p  ' >
+                               <debugfs>/dynamic_debug/control
+nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
+                               <debugfs>/dynamic_debug/control
+nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
+                               <debugfs>/dynamic_debug/control
+
+Commands are bounded by a write() system call.  If you want to do
+multiple commands you need to do a separate "echo" for each, like:
+
+nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
+> echo 'file svcsock.c line 1563 +p' > /proc/dprintk
+
+or even like:
+
+nullarbor:~ # (
+> echo 'file svcsock.c line 1603 +p' ;\
+> echo 'file svcsock.c line 1563 +p' ;\
+> ) > /proc/dprintk
+
+At the syntactical level, a command comprises a sequence of match
+specifications, followed by a flags change specification.
+
+command ::= match-spec* flags-spec
+
+The match-spec's are used to choose a subset of the known dprintk()
+callsites to which to apply the flags-spec.  Think of them as a query
+with implicit ANDs between each pair.  Note that an empty list of
+match-specs is possible, but is not very useful because it will not
+match any debug statement callsites.
+
+A match specification comprises a keyword, which controls the attribute
+of the callsite to be compared, and a value to compare against.  Possible
+keywords are:
+
+match-spec ::= 'func' string |
+              'file' string |
+              'module' string |
+              'format' string |
+              'line' line-range
+
+line-range ::= lineno |
+              '-'lineno |
+              lineno'-' |
+              lineno'-'lineno
+// Note: line-range cannot contain space, e.g.
+// "1-30" is valid range but "1 - 30" is not.
+
+lineno ::= unsigned-int
+
+The meanings of each keyword are:
+
+func
+    The given string is compared against the function name
+    of each callsite.  Example:
+
+    func svc_tcp_accept
+
+file
+    The given string is compared against either the full
+    pathname or the basename of the source file of each
+    callsite.  Examples:
+
+    file svcsock.c
+    file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
+
+module
+    The given string is compared against the module name
+    of each callsite.  The module name is the string as
+    seen in "lsmod", i.e. without the directory or the .ko
+    suffix and with '-' changed to '_'.  Examples:
+
+    module sunrpc
+    module nfsd
+
+format
+    The given string is searched for in the dynamic debug format
+    string.  Note that the string does not need to match the
+    entire format, only some part.  Whitespace and other
+    special characters can be escaped using C octal character
+    escape \ooo notation, e.g. the space character is \040.
+    Alternatively, the string can be enclosed in double quote
+    characters (") or single quote characters (').
+    Examples:
+
+    format svcrdma:        // many of the NFS/RDMA server dprintks
+    format readahead       // some dprintks in the readahead cache
+    format nfsd:\040SETATTR // one way to match a format with whitespace
+    format "nfsd: SETATTR"  // a neater way to match a format with whitespace
+    format 'nfsd: SETATTR'  // yet another way to match a format with whitespace
+
+line
+    The given line number or range of line numbers is compared
+    against the line number of each dprintk() callsite.  A single
+    line number matches the callsite line number exactly.  A
+    range of line numbers matches any callsite between the first
+    and last line number inclusive.  An empty first number means
+    the first line in the file, an empty line number means the
+    last number in the file.  Examples:
+
+    line 1603      // exactly line 1603
+    line 1600-1605  // the six lines from line 1600 to line 1605
+    line -1605     // the 1605 lines from line 1 to line 1605
+    line 1600-     // all lines from line 1600 to the end of the file
+
+The flags specification comprises a change operation followed
+by one or more flag characters.  The change operation is one
+of the characters:
+
+-
+    remove the given flags
+
++
+    add the given flags
+
+=
+    set the flags to the given flags
+
+The flags are:
+
+p
+    Causes a printk() message to be emitted to dmesg
+
+Note the regexp ^[-+=][scp]+$ matches a flags specification.
+Note also that there is no convenient syntax to remove all
+the flags at once, you need to use "-psc".
+
+Examples
+========
+
+// enable the message at line 1603 of file svcsock.c
+nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
+                               <debugfs>/dynamic_debug/control
+
+// enable all the messages in file svcsock.c
+nullarbor:~ # echo -n 'file svcsock.c +p' >
+                               <debugfs>/dynamic_debug/control
+
+// enable all the messages in the NFS server module
+nullarbor:~ # echo -n 'module nfsd +p' >
+                               <debugfs>/dynamic_debug/control
+
+// enable all 12 messages in the function svc_process()
+nullarbor:~ # echo -n 'func svc_process +p' >
+                               <debugfs>/dynamic_debug/control
+
+// disable all 12 messages in the function svc_process()
+nullarbor:~ # echo -n 'func svc_process -p' >
+                               <debugfs>/dynamic_debug/control
+
+// enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
+nullarbor:~ # echo -n 'format "nfsd: READ" +p' >
+                               <debugfs>/dynamic_debug/control
index 54f21a5c262b02ef6cb4718f72b8357693197cf3..1a29ff3df3c58231a3c8a639758a9f9e7557ea6b 100644 (file)
@@ -44,6 +44,7 @@ parameter is applicable:
        FB      The frame buffer device is enabled.
        HW      Appropriate hardware is enabled.
        IA-64   IA-64 architecture is enabled.
+       IMA     Integrity measurement architecture is enabled.
        IOSCHED More than one I/O scheduler is enabled.
        IP_PNP  IP DHCP, BOOTP, or RARP is enabled.
        ISAPNP  ISA PnP code is enabled.
@@ -902,6 +903,15 @@ and is between 256 and 4096 characters. It is defined in the file
        ihash_entries=  [KNL]
                        Set number of hash buckets for inode cache.
 
+       ima_audit=      [IMA]
+                       Format: { "0" | "1" }
+                       0 -- integrity auditing messages. (Default)
+                       1 -- enable informational integrity auditing messages.
+
+       ima_hash=       [IMA]
+                       Formt: { "sha1" | "md5" }
+                       default: "sha1"
+
        in2000=         [HW,SCSI]
                        See header of drivers/scsi/in2000.c.
 
@@ -1816,11 +1826,6 @@ and is between 256 and 4096 characters. It is defined in the file
                        autoconfiguration.
                        Ranges are in pairs (memory base and size).
 
-       dynamic_printk  Enables pr_debug()/dev_dbg() calls if
-                       CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled.
-                       These can also be switched on/off via
-                       <debugfs>/dynamic_printk/modules
-
        print-fatal-signals=
                        [KNL] debug: print fatal signals
                        print-fatal-signals=1: print segfault info to
index 841a9365d5fdd67b5018c7551ff7bb2433056c8a..012858d2b11935aa711e4cf9d2d8fbe637403813 100644 (file)
@@ -346,6 +346,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     sbirq      - IRQ # for CMI8330 chip (SB16)
     sbdma8     - 8bit DMA # for CMI8330 chip (SB16)
     sbdma16    - 16bit DMA # for CMI8330 chip (SB16)
+    fmport     - (optional) OPL3 I/O port
+    mpuport    - (optional) MPU401 I/O port
+    mpuirq     - (optional) MPU401 irq #
 
     This module supports multiple cards and autoprobe.
 
@@ -388,34 +391,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
     
-  Module snd-cs4232
-  -----------------
-
-    Module for sound cards based on CS4232/CS4232A ISA chips.
-
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
-
-    with isapnp=0, the following options are available:
-
-    port       - port # for CS4232 chip (PnP setup - 0x534)
-    cport      - control port # for CS4232 chip (PnP setup - 0x120,0x210,0xf00)
-    mpu_port   - port # for MPU-401 UART (PnP setup - 0x300), -1 = disable
-    fm_port    - FM port # for CS4232 chip (PnP setup - 0x388), -1 = disable
-    irq                - IRQ # for CS4232 chip (5,7,9,11,12,15)
-    mpu_irq    - IRQ # for MPU-401 UART (9,11,12,15)
-    dma1       - first DMA # for CS4232 chip (0,1,3)
-    dma2       - second DMA # for Yamaha CS4232 chip (0,1,3), -1 = disable
-    
-    This module supports multiple cards. This module does not support autoprobe
-    (if ISA PnP is not used) thus main port must be specified!!! Other ports are
-    optional.
-
-    The power-management is supported.
-    
   Module snd-cs4236
   -----------------
 
-    Module for sound cards based on CS4235/CS4236/CS4236B/CS4237B/
+    Module for sound cards based on CS4232/CS4232A,
+                                  CS4235/CS4236/CS4236B/CS4237B/
                                    CS4238B/CS4239 ISA chips.
 
     isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
@@ -437,6 +417,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+    This module is aliased as snd-cs4232 since it provides the old
+    snd-cs4232 functionality, too.
+
   Module snd-cs4281
   -----------------
 
@@ -606,6 +589,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for ESS AudioDrive ES-1688 and ES-688 sound cards.
 
     port       - port # for ES-1688 chip (0x220,0x240,0x260)
+    fm_port    - port # for OPL3 (option; share the same port as default)
     mpu_port   - port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
     irq                - IRQ # for ES-1688 chip (5,7,9,10)
     mpu_irq    - IRQ # for MPU-401 port (5,7,9,10)
@@ -757,6 +741,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     model      - force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
+                 When the bit 8 (0x100) is set, the lower 8 bits are used
+                 as the "fixed" codec slots; i.e. the driver probes the
+                 slots regardless what hardware reports back
     probe_only - Only probing and no codec initialization (default=off);
                  Useful to check the initial codec status for debugging
     bdl_pos_adj        - Specifies the DMA IRQ timing delay in samples.
@@ -1185,6 +1172,54 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports multiple devices and PnP.
     
+  Module snd-msnd-classic
+  -----------------------
+
+    Module for Turtle Beach MultiSound Classic, Tahiti or Monterey
+    soundcards.
+
+    io         - Port # for msnd-classic card
+    irq                - IRQ # for msnd-classic card
+    mem                - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000,
+                 0xe0000 or 0xe8000)
+    write_ndelay - enable write ndelay (default = 1)
+    calibrate_signal - calibrate signal (default = 0)
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+    digital    - Digital daughterboard present (default = 0)
+    cfg                - Config port (0x250, 0x260 or 0x270) default = PnP
+    reset      - Reset all devices
+    mpu_io     - MPU401 I/O port
+    mpu_irq    - MPU401 irq#
+    ide_io0    - IDE port #0
+    ide_io1    - IDE port #1
+    ide_irq    - IDE irq#
+    joystick_io        - Joystick I/O port
+
+    The driver requires firmware files "turtlebeach/msndinit.bin" and
+    "turtlebeach/msndperm.bin" in the proper firmware directory.
+
+    See Documentation/sound/oss/MultiSound for important information
+    about this driver.  Note that it has been discontinued, but the 
+    Voyetra Turtle Beach knowledge base entry for it is still available
+    at
+       http://www.turtlebeach.com/site/kb_ftp/790.asp
+
+  Module snd-msnd-pinnacle
+  ------------------------
+
+    Module for Turtle Beach MultiSound Pinnacle/Fiji soundcards.
+
+    io         - Port # for pinnacle/fiji card
+    irq                - IRQ # for pinnalce/fiji card
+    mem                - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000,
+                 0xe0000 or 0xe8000)
+    write_ndelay - enable write ndelay (default = 1)
+    calibrate_signal - calibrate signal (default = 0)
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    The driver requires firmware files "turtlebeach/pndspini.bin" and
+    "turtlebeach/pndsperm.bin" in the proper firmware directory.
+
   Module snd-mtpav
   ----------------
 
@@ -1824,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
+    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
 
     This module supports autoprobe and multiple cards.
 
index 0f5d26bea80f882ef471c858d0cc0277f4051671..8eec05bc079ebfcc0af9e030ceee652e0a9bf024 100644 (file)
@@ -56,6 +56,7 @@ ALC262
   sony-assamd  Sony ASSAMD
   toshiba-s06  Toshiba S06
   toshiba-rx1  Toshiba RX1
+  tyan         Tyan Thunder n6650W (S2915-E)
   ultra                Samsung Q1 Ultra Vista model
   lenovo-3000  Lenovo 3000 y410
   nec          NEC Versa S9100
@@ -261,6 +262,8 @@ Conexant 5051
 =============
   laptop       Basic Laptop config (default)
   hp           HP Spartan laptop
+  hp-dv6736    HP dv6736
+  lenovo-x200  Lenovo X200 laptop
 
 STAC9200
 ========
@@ -278,6 +281,7 @@ STAC9200
   gateway-m4   Gateway laptops with EAPD control
   gateway-m4-2 Gateway laptops with EAPD control
   panasonic    Panasonic CF-74
+  auto         BIOS setup (default)
 
 STAC9205/9254
 =============
@@ -285,6 +289,8 @@ STAC9205/9254
   dell-m42     Dell (unknown)
   dell-m43     Dell Precision
   dell-m44     Dell Inspiron
+  eapd         Keep EAPD on (e.g. Gateway T1616)
+  auto         BIOS setup (default)
 
 STAC9220/9221
 =============
@@ -308,6 +314,7 @@ STAC9220/9221
   dell-d82     Dell (unknown)
   dell-m81     Dell (unknown)
   dell-m82     Dell XPS M1210
+  auto         BIOS setup (default)
 
 STAC9202/9250/9251
 ==================
@@ -319,6 +326,7 @@ STAC9202/9250/9251
   m3           Some Gateway MX series laptops
   m5           Some Gateway MX series laptops (MP6954)
   m6           Some Gateway NX series laptops
+  auto         BIOS setup (default)
 
 STAC9227/9228/9229/927x
 =======================
@@ -328,6 +336,7 @@ STAC9227/9228/9229/927x
   5stack       D965 5stack + SPDIF
   dell-3stack  Dell Dimension E520
   dell-bios    Fixes with Dell BIOS setup
+  auto         BIOS setup (default)
 
 STAC92HD71B*
 ============
@@ -335,7 +344,10 @@ STAC92HD71B*
   dell-m4-1    Dell desktops
   dell-m4-2    Dell desktops
   dell-m4-3    Dell desktops
-  hp-m4                HP dv laptops
+  hp-m4                HP mini 1000
+  hp-dv5       HP dv series
+  hp-hdx       HP HDX series
+  auto         BIOS setup (default)
 
 STAC92HD73*
 ===========
@@ -345,13 +357,16 @@ STAC92HD73*
   dell-m6-dmic Dell desktops/laptops with digital mics
   dell-m6      Dell desktops/laptops with both type of mics
   dell-eq      Dell desktops/laptops
+  auto         BIOS setup (default)
 
 STAC92HD83*
 ===========
   ref          Reference board
   mic-ref      Reference board with power managment for ports
+  dell-s14     Dell laptop
+  auto         BIOS setup (default)
 
 STAC9872
 ========
-  vaio         Setup for VAIO FE550G/SZ110
-  vaio-ar Setup for VAIO AR
+  vaio         VAIO laptop without SPDIF
+  auto         BIOS setup (default)
index 8d68fff7183945a6b2dba6386ff4cf7da7ea5753..c5948f2f9a253eab2e2764a7002e912ae478fc8c 100644 (file)
@@ -109,6 +109,13 @@ slot, pass `probe_mask=1`.  For the first and the third slots, pass
 Since 2.6.29 kernel, the driver has a more robust probing method, so
 this error might happen rarely, though.
 
+On a machine with a broken BIOS, sometimes you need to force the
+driver to probe the codec slots the hardware doesn't report for use.
+In such a case, turn the bit 8 (0x100) of `probe_mask` option on.
+Then the rest 8 bits are passed as the codec slots to probe
+unconditionally.  For example, `probe_mask=0x103` will force to probe
+the codec slots 0 and 1 no matter what the hardware reports.
+
 
 Interrupt Handling
 ~~~~~~~~~~~~~~~~~~
@@ -358,10 +365,26 @@ modelname::
   to this file.
 init_verbs::
   The extra verbs to execute at initialization.  You can add a verb by
-  writing to this file.  Pass tree numbers, nid, verb and parameter.
+  writing to this file.  Pass three numbers: nid, verb and parameter
+  (separated with a space).
 hints::
-  Shows hint strings for codec parsers for any use.  Right now it's
-  not used.
+  Shows / stores hint strings for codec parsers for any use.
+  Its format is `key = value`.  For example, passing `hp_detect = yes`
+  to IDT/STAC codec parser will result in the disablement of the
+  headphone detection.
+init_pin_configs::
+  Shows the initial pin default config values set by BIOS.
+driver_pin_configs::
+  Shows the pin default values set by the codec parser explicitly.
+  This doesn't show all pin values but only the changed values by
+  the parser.  That is, if the parser doesn't change the pin default
+  config values by itself, this will contain nothing.
+user_pin_configs::
+  Shows the pin default config values to override the BIOS setup.
+  Writing this (with two numbers, NID and value) appends the new
+  value.  The given will be used instead of the initial BIOS value at
+  the next reconfiguration time.  Note that this config will override
+  even the driver pin configs, too.
 reconfig::
   Triggers the codec re-configuration.  When any value is written to
   this file, the driver re-initialize and parses the codec tree
@@ -371,6 +394,14 @@ clear::
   Resets the codec, removes the mixer elements and PCM stuff of the
   specified codec, and clear all init verbs and hints.
 
+For example, when you want to change the pin default configuration
+value of the pin widget 0x14 to 0x9993013f, and let the driver
+re-configure based on that state, run like below:
+------------------------------------------------------------------------
+  # echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs
+  # echo 1 > /sys/class/sound/hwC0D0/reconfig  
+------------------------------------------------------------------------
+
 
 Power-Saving
 ~~~~~~~~~~~~
@@ -461,6 +492,16 @@ run with `--no-upload` option, and attach the generated file.
 There are some other useful options.  See `--help` option output for
 details.
 
+When a probe error occurs or when the driver obviously assigns a
+mismatched model, it'd be helpful to load the driver with
+`probe_only=1` option (at best after the cold reboot) and run
+alsa-info at this state.  With this option, the driver won't configure
+the mixer and PCM but just tries to probe the codec slot.  After
+probing, the proc file is available, so you can get the raw codec
+information before modified by the driver.  Of course, the driver
+isn't usable with `probe_only=1`.  But you can continue the
+configuration via hwdep sysfs file if hda-reconfig option is enabled.
+
 
 hda-verb
 ~~~~~~~~
index 46f9684d0b29d8550824073f0ddf925035b5c327..9e6763264a2ee1cb5b549cc27c51f47557d3ba0d 100644 (file)
@@ -116,6 +116,9 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
 SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
        ARRAY_SIZE(wm8731_output_mixer_controls)),
 
+If you dont want the mixer elements prefixed with the name of the mixer widget,
+you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same
+as for SND_SOC_DAPM_MIXER.
 
 2.3 Platform/Machine domain Widgets
 -----------------------------------
diff --git a/Documentation/sound/oss/CS4232 b/Documentation/sound/oss/CS4232
deleted file mode 100644 (file)
index 7d6af7a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-To configure the Crystal CS423x sound chip and activate its DSP functions,
-modules may be loaded in this order:
-  
-       modprobe sound
-       insmod ad1848
-       insmod uart401
-       insmod cs4232 io=* irq=* dma=* dma2=*
-  
-This is the meaning of the parameters:
-  
-       io--I/O address of the Windows Sound System (normally 0x534)
-       irq--IRQ of this device
-       dma and dma2--DMA channels (DMA2 may be 0)
-  
-On some cards, the board attempts to do non-PnP setup, and fails.  If you
-have problems, use Linux' PnP facilities. 
-  
-To get MIDI facilities add
-  
-       insmod opl3 io=*
-  
-where "io" is the I/O address of the OPL3 synthesizer. This will be shown
-in /proc/sys/pnp and is normally 0x388.
index f04ba6bb7395685719bb883abd74b7ee7c5333a0..75d967ff92663dd7fd72db9be9ef8926d8e6cf7e 100644 (file)
@@ -80,7 +80,7 @@ Notes:
     additional features.
 
 2.  The commercial OSS driver may be obtained from the site:
-    http://www/opensound.com.  This may be used for cards that
+    http://www.opensound.com.  This may be used for cards that
     are unsupported by the kernel driver, or may be used
     by other operating systems.  
 
index 5d460c9d1c2c19ca871fabf53eb786572a64d5aa..1978fb205bf75b6b00df8f19f6b67ccf879ebeca 100644 (file)
@@ -1269,6 +1269,12 @@ L:       linux-crypto@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6.git
 S:     Maintained
 
+CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
+P:     Neil Horman
+M:     nhorman@tuxdriver.com
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+
 CS5535 Audio ALSA driver
 P:     Jaya Kumar
 M:     jayakumar.alsa@gmail.com
@@ -2216,6 +2222,11 @@ M:       stefanr@s5r6.in-berlin.de
 L:     linux1394-devel@lists.sourceforge.net
 S:     Maintained
 
+INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
+P:     Mimi Zohar
+M:     zohar@us.ibm.com
+S:     Supported
+
 IMS TWINTURBO FRAMEBUFFER DRIVER
 L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:     Orphan
@@ -3844,6 +3855,7 @@ M:        jmorris@namei.org
 L:     linux-kernel@vger.kernel.org
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
 T:     git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
+W:     http://security.wiki.kernel.org/
 S:     Supported
 
 SECURITY CONTACT
@@ -4285,6 +4297,19 @@ L:       tlan-devel@lists.sourceforge.net (subscribers-only)
 W:     http://sourceforge.net/projects/tlan/
 S:     Maintained
 
+TOMOYO SECURITY MODULE
+P:     Kentaro Takeda
+M:     takedakn@nttdata.co.jp
+P:     Tetsuo Handa
+M:     penguin-kernel@I-love.SAKURA.ne.jp
+L:     linux-kernel@vger.kernel.org (kernel issues)
+L:     tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
+L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
+L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
+W:     http://tomoyo.sourceforge.jp/
+T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
+S:     Maintained
+
 TOSHIBA ACPI EXTRAS DRIVER
 P:     John Belmonte
 M:     toshiba_acpi@memebeam.org
index 6d48e00f4f0b444913f49cdcd58c01900cddf10d..a6fff782e7a8cfcd78c0a267f5f4817dfb309c3a 100644 (file)
@@ -135,6 +135,11 @@ static unsigned long e740_pin_config[] __initdata = {
        /* IrDA */
        GPIO38_GPIO | MFP_LPM_DRIVE_HIGH,
 
+       /* Audio power control */
+       GPIO16_GPIO,  /* AC97 codec AVDD2 supply (analogue power) */
+       GPIO40_GPIO,  /* Mic amp power */
+       GPIO41_GPIO,  /* Headphone amp power */
+
        /* PC Card */
        GPIO8_GPIO,   /* CD0 */
        GPIO44_GPIO,  /* CD1 */
index be1ab8edb973eab021c7730c66246bdcac856b29..665066fd280ee123236b77e5d3d12e6f21b100ca 100644 (file)
@@ -133,6 +133,11 @@ static unsigned long e750_pin_config[] __initdata = {
        /* IrDA */
        GPIO38_GPIO | MFP_LPM_DRIVE_HIGH,
 
+       /* Audio power control */
+       GPIO4_GPIO,  /* Headphone amp power */
+       GPIO7_GPIO,  /* Speaker amp power */
+       GPIO37_GPIO, /* Headphone detect */
+
        /* PC Card */
        GPIO8_GPIO,   /* CD0 */
        GPIO44_GPIO,  /* CD1 */
index da6e4422c0f3204bfdd8a553ec4c0c59c52ed107..295ec413d804f951046eecf5fda1fc069f10a085 100644 (file)
@@ -153,6 +153,13 @@ static unsigned long h5000_pin_config[] __initdata = {
        GPIO23_SSP1_SCLK,
        GPIO25_SSP1_TXD,
        GPIO26_SSP1_RXD,
+
+       /* I2S */
+       GPIO28_I2S_BITCLK_OUT,
+       GPIO29_I2S_SDATA_IN,
+       GPIO30_I2S_SDATA_OUT,
+       GPIO31_I2S_SYNC,
+       GPIO32_I2S_SYSCLK,
 };
 
 /*
index efbd2aa9ecec394e7cf98270dfd38a0df993ad26..f3e5509820d7360270a202698d61511c31dd9be6 100644 (file)
 /* e7xx IrDA power control */
 #define GPIO_E7XX_IR_OFF         38
 
+/* e740 audio control GPIOs */
+#define GPIO_E740_WM9705_nAVDD2  16
+#define GPIO_E740_MIC_ON         40
+#define GPIO_E740_AMP_ON         41
+
+/* e750 audio control GPIOs */
+#define GPIO_E750_HP_AMP_OFF      4
+#define GPIO_E750_SPK_AMP_OFF     7
+#define GPIO_E750_HP_DETECT      37
+
+/* e800 audio control GPIOs */
+#define GPIO_E800_HP_DETECT      81
+#define GPIO_E800_HP_AMP_OFF     82
+#define GPIO_E800_SPK_AMP_ON     83
+
 /* ASIC related GPIOs */
 #define GPIO_ESERIES_TMIO_IRQ        5
 #define GPIO_ESERIES_TMIO_PCLR      19
index cf31986f6f05d1b0f8637e020c4fd421e97e03fd..018f6d65b57ba93948dc58c3d4745700fd5d0064 100644 (file)
@@ -50,7 +50,7 @@
 #define SSCR0_TUM      (1 << 23)       /* Transmit FIFO underrun interrupt mask */
 #define SSCR0_FRDC     (0x07000000)    /* Frame rate divider control (mask) */
 #define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame [1..8] */
-#define SSCR0_ADC      (1 << 30)       /* Audio clock select */
+#define SSCR0_ACS      (1 << 30)       /* Audio clock select */
 #define SSCR0_MOD      (1 << 31)       /* Mode (normal or network) */
 #endif
 
 #define SSSR_TINT              (1 << 19)       /* Receiver Time-out Interrupt */
 #define SSSR_PINT              (1 << 18)       /* Peripheral Trailing Byte Interrupt */
 
+#if defined(CONFIG_PXA3xx)
+#define SSPSP_EDMYSTOP(x)      ((x) << 28)     /* Extended Dummy Stop */
+#define SSPSP_EDMYSTRT(x)      ((x) << 26)     /* Extended Dummy Start */
+#endif
+
 #define SSPSP_FSRT             (1 << 25)       /* Frame Sync Relative Timing */
 #define SSPSP_DMYSTOP(x)       ((x) << 23)     /* Dummy Stop */
 #define SSPSP_SFRMWDTH(x)      ((x) << 16)     /* Serial Frame Width */
index 6d447c9ce8abfcadb2743f11330a48ab93d7d125..0d62d311d41ac8dfacdd4b9aba6c517968b4997d 100644 (file)
@@ -105,6 +105,12 @@ static unsigned long spitz_pin_config[] __initdata = {
        GPIO57_nIOIS16,
        GPIO104_PSKTSEL,
 
+       /* I2S */
+       GPIO28_I2S_BITCLK_OUT,
+       GPIO29_I2S_SDATA_IN,
+       GPIO30_I2S_SDATA_OUT,
+       GPIO31_I2S_SYNC,
+
        /* MMC */
        GPIO32_MMC_CLK,
        GPIO112_MMC_CMD,
index 552b4c778fdc7f6ab450cae8df014570f7f36ee1..440c014e24b31bf9b00b536bcd8e7900d836850a 100644 (file)
@@ -28,7 +28,7 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
index 919856c9433f013fb81678a485a32abc8290859c..9e3478506c6f67ef1dd307971b2d7786b32f1104 100644 (file)
@@ -29,8 +29,8 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-s3c2412-iis.h>
+#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
index 5b5ee0b8f4e0b236ec9a4922f90e3f69b3ce67d0..69b6cf34df4728907e5d9dbba631c8d3fbb90a2d 100644 (file)
@@ -28,7 +28,7 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
index 2a58a4d5aa5ae44e196c59acb8838e851defe4a3..8430e5829186da2d56f39d3069c6b99e0d708ffa 100644 (file)
@@ -29,7 +29,7 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { \
similarity index 93%
rename from include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
rename to arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
index 25d4058bcfedf8f30e472a2a62c167eba5db10fd..0fad7571030eb9f911529e85f4d1d17c729ad704 100644 (file)
@@ -33,6 +33,9 @@
 #define S3C2412_IISCON_RXDMA_ACTIVE    (1 << 1)
 #define S3C2412_IISCON_IIS_ACTIVE      (1 << 0)
 
+#define S3C64XX_IISMOD_IMS_PCLK                (0 << 10)
+#define S3C64XX_IISMOD_IMS_SYSMUX      (1 << 10)
+
 #define S3C2412_IISMOD_MASTER_INTERNAL (0 << 10)
 #define S3C2412_IISMOD_MASTER_EXTERNAL (1 << 10)
 #define S3C2412_IISMOD_SLAVE           (2 << 10)
@@ -44,8 +47,8 @@
 #define S3C2412_IISMOD_LR_LLOW         (0 << 7)
 #define S3C2412_IISMOD_LR_RLOW         (1 << 7)
 #define S3C2412_IISMOD_SDF_IIS         (0 << 5)
-#define S3C2412_IISMOD_SDF_MSB         (0 << 5)
-#define S3C2412_IISMOD_SDF_LSB         (0 << 5)
+#define S3C2412_IISMOD_SDF_MSB         (1 << 5)
+#define S3C2412_IISMOD_SDF_LSB         (2 << 5)
 #define S3C2412_IISMOD_SDF_MASK                (3 << 5)
 #define S3C2412_IISMOD_RCLK_256FS      (0 << 3)
 #define S3C2412_IISMOD_RCLK_512FS      (1 << 3)
index a98c6dd3a028affd33571ec6dbfb9b98961519a3..559bbcb03f9b696cb0589d649a803c8356772668 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mtd/physmap.h>
 #include <linux/usb/isp116x.h>
 #include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
 #include <linux/delay.h>
 
 #include <mach/portmux.h>
index ed092395215e628a6351ddf8e8fa04529374da6a..245b2ee213c915df2fc353950c3839be93daee88 100644 (file)
@@ -230,10 +230,10 @@ extern int __put_user_bad(void);
        asm volatile(                                                   \
                "1:     ld." suffix "   %1, %3                  \n"     \
                "2:                                             \n"     \
-               "       .section .fixup, \"ax\"                 \n"     \
+               "       .subsection 1                           \n"     \
                "3:     mov     %0, %4                          \n"     \
                "       rjmp    2b                              \n"     \
-               "       .previous                               \n"     \
+               "       .subsection 0                           \n"     \
                "       .section __ex_table, \"a\"              \n"     \
                "       .long   1b, 3b                          \n"     \
                "       .previous                               \n"     \
@@ -295,10 +295,10 @@ extern int __put_user_bad(void);
        asm volatile(                                                   \
                "1:     st." suffix "   %1, %3                  \n"     \
                "2:                                             \n"     \
-               "       .section .fixup, \"ax\"                 \n"     \
+               "       .subsection 1                           \n"     \
                "3:     mov     %0, %4                          \n"     \
                "       rjmp    2b                              \n"     \
-               "       .previous                               \n"     \
+               "       .subsection 0                           \n"     \
                "       .section __ex_table, \"a\"              \n"     \
                "       .long   1b, 3b                          \n"     \
                "       .previous                               \n"     \
index 33d49377b8beda6ae217cf40928d304d5eabfa6d..009a80155d67d96b7da1ee34e60ec726abcfdb4b 100644 (file)
@@ -150,10 +150,10 @@ page_not_present:
        tlbmiss_restore
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_page_fault
+       call    do_page_fault
        rjmp    ret_from_exception
 
        .align  2
@@ -250,7 +250,7 @@ syscall_badsys:
 
        .global ret_from_fork
 ret_from_fork:
-       rcall   schedule_tail
+       call   schedule_tail
 
        /* check for syscall tracing */
        get_thread_info r0
@@ -261,7 +261,7 @@ ret_from_fork:
 
 syscall_trace_enter:
        pushm   r8-r12
-       rcall   syscall_trace
+       call    syscall_trace
        popm    r8-r12
        rjmp    syscall_trace_cont
 
@@ -269,14 +269,14 @@ syscall_exit_work:
        bld     r1, TIF_SYSCALL_TRACE
        brcc    1f
        unmask_interrupts
-       rcall   syscall_trace
+       call    syscall_trace
        mask_interrupts
        ld.w    r1, r0[TI_flags]
 
 1:     bld     r1, TIF_NEED_RESCHED
        brcc    2f
        unmask_interrupts
-       rcall   schedule
+       call    schedule
        mask_interrupts
        ld.w    r1, r0[TI_flags]
        rjmp    1b
@@ -287,7 +287,7 @@ syscall_exit_work:
        unmask_interrupts
        mov     r12, sp
        mov     r11, r0
-       rcall   do_notify_resume
+       call    do_notify_resume
        mask_interrupts
        ld.w    r1, r0[TI_flags]
        rjmp    1b
@@ -394,7 +394,7 @@ handle_critical:
 
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_critical_exception
+       call    do_critical_exception
 
        /* We should never get here... */
 bad_return:
@@ -407,18 +407,18 @@ bad_return:
 do_bus_error_write:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mov     r11, 1
        rjmp    1f
 
 do_bus_error_read:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mov     r11, 0
 1:     mfsr    r12, SYSREG_BEAR
        mov     r10, sp
-       rcall   do_bus_error
+       call    do_bus_error
        rjmp    ret_from_exception
 
        .align  1
@@ -433,7 +433,7 @@ do_nmi_ll:
 1:     pushm   r8, r9  /* PC and SR */
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_nmi
+       call    do_nmi
        popm    r8-r9
        mtsr    SYSREG_RAR_NMI, r8
        tst     r0, r0
@@ -457,29 +457,29 @@ do_nmi_ll:
 handle_address_fault:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_address_exception
+       call    do_address_exception
        rjmp    ret_from_exception
 
 handle_protection_fault:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_page_fault
+       call    do_page_fault
        rjmp    ret_from_exception
 
        .align  1
 do_illegal_opcode_ll:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
-       rcall   do_illegal_opcode
+       call    do_illegal_opcode
        rjmp    ret_from_exception
 
 do_dtlb_modified:
@@ -513,11 +513,11 @@ do_dtlb_modified:
 do_fpe_ll:
        sub     sp, 4
        stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       call    save_full_context_ex
        unmask_interrupts
        mov     r12, 26
        mov     r11, sp
-       rcall   do_fpe
+       call    do_fpe
        rjmp    ret_from_exception
 
 ret_from_exception:
@@ -553,7 +553,7 @@ fault_resume_kernel:
        lddsp   r4, sp[REG_SR]
        bld     r4, SYSREG_GM_OFFSET
        brcs    1f
-       rcall   preempt_schedule_irq
+       call    preempt_schedule_irq
 1:
 #endif
 
@@ -582,7 +582,7 @@ fault_exit_work:
        bld     r1, TIF_NEED_RESCHED
        brcc    1f
        unmask_interrupts
-       rcall   schedule
+       call    schedule
        mask_interrupts
        ld.w    r1, r0[TI_flags]
        rjmp    fault_exit_work
@@ -593,7 +593,7 @@ fault_exit_work:
        unmask_interrupts
        mov     r12, sp
        mov     r11, r0
-       rcall   do_notify_resume
+       call    do_notify_resume
        mask_interrupts
        ld.w    r1, r0[TI_flags]
        rjmp    fault_exit_work
@@ -616,10 +616,10 @@ handle_debug:
 
 .Ldebug_fixup_cont:
 #ifdef CONFIG_TRACE_IRQFLAGS
-       rcall   trace_hardirqs_off
+       call    trace_hardirqs_off
 #endif
        mov     r12, sp
-       rcall   do_debug
+       call    do_debug
        mov     sp, r12
 
        lddsp   r2, sp[REG_SR]
@@ -643,7 +643,7 @@ handle_debug:
        mtsr    SYSREG_RSR_DBG, r11
        mtsr    SYSREG_RAR_DBG, r10
 #ifdef CONFIG_TRACE_IRQFLAGS
-       rcall   trace_hardirqs_on
+       call    trace_hardirqs_on
 1:
 #endif
        ldmts   sp++, r0-lr
@@ -676,7 +676,7 @@ debug_resume_kernel:
 #ifdef CONFIG_TRACE_IRQFLAGS
        bld     r11, SYSREG_GM_OFFSET
        brcc    1f
-       rcall   trace_hardirqs_on
+       call    trace_hardirqs_on
 1:
 #endif
        mfsr    r2, SYSREG_SR
@@ -747,7 +747,7 @@ irq_level\level:
        mov     r11, sp
        mov     r12, \level
 
-       rcall   do_IRQ
+       call    do_IRQ
 
        lddsp   r4, sp[REG_SR]
        bfextu  r4, r4, SYSREG_M0_OFFSET, 3
@@ -767,7 +767,7 @@ irq_level\level:
 
 1:
 #ifdef CONFIG_TRACE_IRQFLAGS
-       rcall   trace_hardirqs_on
+       call    trace_hardirqs_on
 #endif
        popm    r8-r9
        mtsr    rar_int\level, r8
@@ -807,7 +807,7 @@ irq_level\level:
        lddsp   r4, sp[REG_SR]
        bld     r4, SYSREG_GM_OFFSET
        brcs    1b
-       rcall   preempt_schedule_irq
+       call    preempt_schedule_irq
 #endif
        rjmp    1b
        .endm
index 673178e235f3a485005ecfd43415f86fad13ab9e..f7244cd02fbbf0b96fd31f56f40c47e14d61430b 100644 (file)
@@ -61,7 +61,7 @@ __sys_execve:
 __sys_mmap2:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_mmap2
+       call    sys_mmap2
        sub     sp, -4
        popm    pc
 
@@ -70,7 +70,7 @@ __sys_mmap2:
 __sys_sendto:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_sendto
+       call    sys_sendto
        sub     sp, -4
        popm    pc
 
@@ -79,7 +79,7 @@ __sys_sendto:
 __sys_recvfrom:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_recvfrom
+       call    sys_recvfrom
        sub     sp, -4
        popm    pc
 
@@ -88,7 +88,7 @@ __sys_recvfrom:
 __sys_pselect6:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_pselect6
+       call    sys_pselect6
        sub     sp, -4
        popm    pc
 
@@ -97,7 +97,7 @@ __sys_pselect6:
 __sys_splice:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_splice
+       call    sys_splice
        sub     sp, -4
        popm    pc
 
@@ -106,7 +106,7 @@ __sys_splice:
 __sys_epoll_pwait:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_epoll_pwait
+       call    sys_epoll_pwait
        sub     sp, -4
        popm    pc
 
@@ -115,6 +115,6 @@ __sys_epoll_pwait:
 __sys_sync_file_range:
        pushm   lr
        st.w    --sp, ARG6
-       rcall   sys_sync_file_range
+       call    sys_sync_file_range
        sub     sp, -4
        popm    pc
index 65ce11afa66a258d31d413a6c578c2452789d9d7..e46f4724962b79bcc03c5b54042d2f11f4fc1981 100644 (file)
@@ -48,7 +48,7 @@ adjust_length:
        lddpc   lr, _task_size
        sub     r11, lr, r12
        mov     r9, r11
-       rcall   __strnlen_user
+       call    __strnlen_user
        cp.w    r12, r9
        brgt    1f
        popm    pc
index a1e3526b4a94dd31d4013ccbc88d0a0e3857b3b2..dfbfd7e2ac088887cccfc35aac853cf9cbd07785 100644 (file)
@@ -33,8 +33,8 @@
 
 
 static const struct resource *iodev_get_resource(struct platform_device *, const char *, unsigned int);
-static int __init iodev_probe(struct device *);
-static int __exit iodev_remove(struct device *);
+static int __init iodev_probe(struct platform_device *);
+static int __exit iodev_remove(struct platform_device *);
 static int iodev_open(struct inode *, struct file *);
 static int iodev_release(struct inode *, struct file *);
 static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *);
@@ -65,13 +65,13 @@ static struct miscdevice miscdev =
        .fops           = &fops
 };
 
-static struct device_driver iodev_driver =
-{
-       .name           = (char *) iodev_name,
-       .bus            = &platform_bus_type,
-       .owner          = THIS_MODULE,
+static struct platform_driver iodev_driver = {
+       .driver = {
+               .name           = iodev_name,
+               .owner          = THIS_MODULE,
+       },
        .probe          = iodev_probe,
-       .remove         = __exit_p(iodev_remove)
+       .remove         = __devexit_p(iodev_remove),
 };
 
 
@@ -89,11 +89,10 @@ iodev_get_resource(struct platform_device *pdv, const char *name,
 
 
 /* No hotplugging on the platform bus - use __init */
-static int __init iodev_probe(struct device *dev)
+static int __init iodev_probe(struct platform_device *dev)
 {
-       struct platform_device * const pdv = to_platform_device(dev);
        const struct resource * const ri =
-               iodev_get_resource(pdv, IODEV_RESOURCE_IRQ, IORESOURCE_IRQ);
+               iodev_get_resource(dev, IODEV_RESOURCE_IRQ, IORESOURCE_IRQ);
 
        if (unlikely(!ri))
                return -ENXIO;
@@ -104,7 +103,7 @@ static int __init iodev_probe(struct device *dev)
 
 
 
-static int __exit iodev_remove(struct device *dev)
+static int __exit iodev_remove(struct platform_device *dev)
 {
        return misc_deregister(&miscdev);
 }
@@ -160,14 +159,14 @@ static irqreturn_t iodev_irqhdl(int irq, void *ctxt)
 
 static int __init iodev_init_module(void)
 {
-       return driver_register(&iodev_driver);
+       return platform_driver_register(&iodev_driver);
 }
 
 
 
 static void __exit iodev_cleanup_module(void)
 {
-       driver_unregister(&iodev_driver);
+       platform_driver_unregister(&iodev_driver);
 }
 
 module_init(iodev_init_module);
index 0417516503f634484bea51436d9befa8059b4a83..526f327475cea59bf93f0db86505fdd2ef4f86c3 100644 (file)
@@ -1391,11 +1391,11 @@ static inline void tlb_write_random(void)
 static inline unsigned int                                     \
 set_c0_##name(unsigned int set)                                        \
 {                                                              \
-       unsigned int res;                                       \
+       unsigned int res, new;                                  \
                                                                \
        res = read_c0_##name();                                 \
-       res |= set;                                             \
-       write_c0_##name(res);                                   \
+       new = res | set;                                        \
+       write_c0_##name(new);                                   \
                                                                \
        return res;                                             \
 }                                                              \
@@ -1403,24 +1403,24 @@ set_c0_##name(unsigned int set)                                 \
 static inline unsigned int                                     \
 clear_c0_##name(unsigned int clear)                            \
 {                                                              \
-       unsigned int res;                                       \
+       unsigned int res, new;                                  \
                                                                \
        res = read_c0_##name();                                 \
-       res &= ~clear;                                          \
-       write_c0_##name(res);                                   \
+       new = res & ~clear;                                     \
+       write_c0_##name(new);                                   \
                                                                \
        return res;                                             \
 }                                                              \
                                                                \
 static inline unsigned int                                     \
-change_c0_##name(unsigned int change, unsigned int new)                \
+change_c0_##name(unsigned int change, unsigned int val)                \
 {                                                              \
-       unsigned int res;                                       \
+       unsigned int res, new;                                  \
                                                                \
        res = read_c0_##name();                                 \
-       res &= ~change;                                         \
-       res |= (new & change);                                  \
-       write_c0_##name(res);                                   \
+       new = res & ~change;                                    \
+       new |= (val & change);                                  \
+       write_c0_##name(new);                                   \
                                                                \
        return res;                                             \
 }
index 1a86f84fa9470f31030c53fdc9ad45c792d08425..49aac6e17df932a89658840302c7332a8c27f012 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <linux/binfmts.h>
 #include <linux/security.h>
-#include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/vfs.h>
 #include <linux/ipc.h>
index b2d7041341b8f5afa3e313302c21b90e34e5ea3d..29fadaccecddef31d5da3ea33f819b1ad3941fe0 100644 (file)
@@ -1520,7 +1520,9 @@ void __cpuinit per_cpu_trap_init(void)
 #endif /* CONFIG_MIPS_MT_SMTC */
 
        if (cpu_has_veic || cpu_has_vint) {
+               unsigned long sr = set_c0_status(ST0_BEV);
                write_c0_ebase(ebase);
+               write_c0_status(sr);
                /* Setting vector spacing enables EI/VI mode  */
                change_c0_intctl(0x3e0, VECTORSPACING);
        }
@@ -1602,8 +1604,6 @@ void __cpuinit set_uncached_handler(unsigned long offset, void *addr,
 #ifdef CONFIG_64BIT
        unsigned long uncached_ebase = TO_UNCAC(ebase);
 #endif
-       if (cpu_has_mips_r2)
-               uncached_ebase += (read_c0_ebase() & 0x3ffff000);
 
        if (!addr)
                panic(panic_null_cerr);
@@ -1635,9 +1635,11 @@ void __init trap_init(void)
                return; /* Already done */
 #endif
 
-       if (cpu_has_veic || cpu_has_vint)
-               ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64);
-       else {
+       if (cpu_has_veic || cpu_has_vint) {
+               unsigned long size = 0x200 + VECTORSPACING*64;
+               ebase = (unsigned long)
+                       __alloc_bootmem(size, 1 << fls(size), 0);
+       } else {
                ebase = CAC_BASE;
                if (cpu_has_mips_r2)
                        ebase += (read_c0_ebase() & 0x3ffff000);
index c43f4b26a69010b63154a734618060c0981b692e..871e828bc62ac2e7db45405f4347b598374301a5 100644 (file)
@@ -780,7 +780,7 @@ static void __cpuinit probe_pcache(void)
                c->dcache.ways = 2;
                c->dcache.waybit = 0;
 
-               c->options |= MIPS_CPU_CACHE_CDEX_P;
+               c->options |= MIPS_CPU_CACHE_CDEX_P | MIPS_CPU_PREFETCH;
                break;
 
        case CPU_TX49XX:
index 546e6977d4ffb0bd1910a57114803bdb1bffe858..bed56f1ac83709887aa1c4b60922d9fa6602d354 100644 (file)
@@ -225,7 +225,7 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
        if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) {
                unsigned long addr;
 
-               addr = plat_dma_addr_to_phys(dma_address);
+               addr = dma_addr_to_virt(dma_address);
                dma_cache_wback_inv(addr, size);
        }
 
index 8b5ba8261a36ad54d80863881da214d3bc273d71..4447def69dc5175f78afb33a7546e901cb9d99b4 100644 (file)
                        dcr-reg = <0x010 0x002>;
                };
 
+               CRYPTO: crypto@180000 {
+                       compatible = "amcc,ppc460ex-crypto", "amcc,ppc4xx-crypto";
+                       reg = <4 0x00180000 0x80400>;
+                       interrupt-parent = <&UIC0>;
+                       interrupts = <0x1d 0x4>;
+               };
+
                MAL0: mcmal {
                        compatible = "ibm,mcmal-460ex", "ibm,mcmal2";
                        dcr-reg = <0x180 0x062>;
index 2804444812e5e75e0a0e19c7ea4c82ad92712700..5e6b08ff6f6701e158aa94241cabe3681024d520 100644 (file)
                                      0x6 0x4>; /* ECC SEC Error */ 
                };
 
+               CRYPTO: crypto@ef700000 {
+                       compatible = "amcc,ppc405ex-crypto", "amcc,ppc4xx-crypto";
+                       reg = <0xef700000 0x80400>;
+                       interrupt-parent = <&UIC0>;
+                       interrupts = <0x17 0x2>;
+               };
+
                MAL0: mcmal {
                        compatible = "ibm,mcmal-405ex", "ibm,mcmal2";
                        dcr-reg = <0x180 0x062>;
index 58311a867851affc29310d3557dd5410350983ff..a705fffbb498e3ec8c14f56c33f3e48b065ddca1 100644 (file)
@@ -376,7 +376,7 @@ static int ps3_system_bus_probe(struct device *_dev)
        struct ps3_system_bus_driver *drv;
 
        BUG_ON(!dev);
-       pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+       dev_dbg(_dev, "%s:%d\n", __func__, __LINE__);
 
        drv = ps3_system_bus_dev_to_system_bus_drv(dev);
        BUG_ON(!drv);
@@ -398,7 +398,7 @@ static int ps3_system_bus_remove(struct device *_dev)
        struct ps3_system_bus_driver *drv;
 
        BUG_ON(!dev);
-       pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+       dev_dbg(_dev, "%s:%d\n", __func__, __LINE__);
 
        drv = ps3_system_bus_dev_to_system_bus_drv(dev);
        BUG_ON(!drv);
index 1ceafa571eab5e2c87276a7da7f8cd1ae66e4dd5..f4e9dc71675f7e5d572c2e6d97312b097e5d89a2 100644 (file)
@@ -29,7 +29,9 @@ struct s390_sha_ctx {
        int func;               /* KIMD function to use */
 };
 
-void s390_sha_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len);
-void s390_sha_final(struct crypto_tfm *tfm, u8 *out);
+struct shash_desc;
+
+int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len);
+int s390_sha_final(struct shash_desc *desc, u8 *out);
 
 #endif
index b3cb5a89b00d08a37030c80ca53940ef9bc3af16..e85ba348722a95007d26bb8ce73e4fe5913c944f 100644 (file)
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/crypto.h>
 #include <crypto/sha.h>
 
 #include "crypt_s390.h"
 #include "sha.h"
 
-static void sha1_init(struct crypto_tfm *tfm)
+static int sha1_init(struct shash_desc *desc)
 {
-       struct s390_sha_ctx *sctx = crypto_tfm_ctx(tfm);
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
 
        sctx->state[0] = SHA1_H0;
        sctx->state[1] = SHA1_H1;
@@ -42,34 +42,36 @@ static void sha1_init(struct crypto_tfm *tfm)
        sctx->state[4] = SHA1_H4;
        sctx->count = 0;
        sctx->func = KIMD_SHA_1;
+
+       return 0;
 }
 
-static struct crypto_alg alg = {
-       .cra_name       =       "sha1",
-       .cra_driver_name=       "sha1-s390",
-       .cra_priority   =       CRYPT_S390_PRIORITY,
-       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-       .cra_blocksize  =       SHA1_BLOCK_SIZE,
-       .cra_ctxsize    =       sizeof(struct s390_sha_ctx),
-       .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-       .cra_u          =       { .digest = {
-       .dia_digestsize =       SHA1_DIGEST_SIZE,
-       .dia_init       =       sha1_init,
-       .dia_update     =       s390_sha_update,
-       .dia_final      =       s390_sha_final } }
+static struct shash_alg alg = {
+       .digestsize     =       SHA1_DIGEST_SIZE,
+       .init           =       sha1_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .base           =       {
+               .cra_name       =       "sha1",
+               .cra_driver_name=       "sha1-s390",
+               .cra_priority   =       CRYPT_S390_PRIORITY,
+               .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize  =       SHA1_BLOCK_SIZE,
+               .cra_module     =       THIS_MODULE,
+       }
 };
 
 static int __init sha1_s390_init(void)
 {
        if (!crypt_s390_func_available(KIMD_SHA_1))
                return -EOPNOTSUPP;
-       return crypto_register_alg(&alg);
+       return crypto_register_shash(&alg);
 }
 
 static void __exit sha1_s390_fini(void)
 {
-       crypto_unregister_alg(&alg);
+       crypto_unregister_shash(&alg);
 }
 
 module_init(sha1_s390_init);
index 19c03fb6ba7eee64d773ab0cdb5d0c1d556c05c0..f9fefc5696329fd4f64e272ff6dac0c4e5ec0f91 100644 (file)
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/crypto.h>
 #include <crypto/sha.h>
 
 #include "crypt_s390.h"
 #include "sha.h"
 
-static void sha256_init(struct crypto_tfm *tfm)
+static int sha256_init(struct shash_desc *desc)
 {
-       struct s390_sha_ctx *sctx = crypto_tfm_ctx(tfm);
+       struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
 
        sctx->state[0] = SHA256_H0;
        sctx->state[1] = SHA256_H1;
@@ -38,22 +38,24 @@ static void sha256_init(struct crypto_tfm *tfm)
        sctx->state[7] = SHA256_H7;
        sctx->count = 0;
        sctx->func = KIMD_SHA_256;
+
+       return 0;
 }
 
-static struct crypto_alg alg = {
-       .cra_name       =       "sha256",
-       .cra_driver_name =      "sha256-s390",
-       .cra_priority   =       CRYPT_S390_PRIORITY,
-       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-       .cra_blocksize  =       SHA256_BLOCK_SIZE,
-       .cra_ctxsize    =       sizeof(struct s390_sha_ctx),
-       .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-       .cra_u          =       { .digest = {
-       .dia_digestsize =       SHA256_DIGEST_SIZE,
-       .dia_init       =       sha256_init,
-       .dia_update     =       s390_sha_update,
-       .dia_final      =       s390_sha_final } }
+static struct shash_alg alg = {
+       .digestsize     =       SHA256_DIGEST_SIZE,
+       .init           =       sha256_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .base           =       {
+               .cra_name       =       "sha256",
+               .cra_driver_name=       "sha256-s390",
+               .cra_priority   =       CRYPT_S390_PRIORITY,
+               .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize  =       SHA256_BLOCK_SIZE,
+               .cra_module     =       THIS_MODULE,
+       }
 };
 
 static int sha256_s390_init(void)
@@ -61,12 +63,12 @@ static int sha256_s390_init(void)
        if (!crypt_s390_func_available(KIMD_SHA_256))
                return -EOPNOTSUPP;
 
-       return crypto_register_alg(&alg);
+       return crypto_register_shash(&alg);
 }
 
 static void __exit sha256_s390_fini(void)
 {
-       crypto_unregister_alg(&alg);
+       crypto_unregister_shash(&alg);
 }
 
 module_init(sha256_s390_init);
index 23c7861f6aeb4d132c2380aca491998be609174c..83192bfc80480bd1477433fd906b6450ab7c4d38 100644 (file)
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/crypto.h>
 
 #include "sha.h"
 #include "crypt_s390.h"
 
-static void sha512_init(struct crypto_tfm *tfm)
+static int sha512_init(struct shash_desc *desc)
 {
-       struct s390_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
 
        *(__u64 *)&ctx->state[0] = 0x6a09e667f3bcc908ULL;
        *(__u64 *)&ctx->state[2] = 0xbb67ae8584caa73bULL;
@@ -33,29 +33,31 @@ static void sha512_init(struct crypto_tfm *tfm)
        *(__u64 *)&ctx->state[14] = 0x5be0cd19137e2179ULL;
        ctx->count = 0;
        ctx->func = KIMD_SHA_512;
+
+       return 0;
 }
 
-static struct crypto_alg sha512_alg = {
-       .cra_name       =       "sha512",
-       .cra_driver_name =      "sha512-s390",
-       .cra_priority   =       CRYPT_S390_PRIORITY,
-       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-       .cra_blocksize  =       SHA512_BLOCK_SIZE,
-       .cra_ctxsize    =       sizeof(struct s390_sha_ctx),
-       .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(sha512_alg.cra_list),
-       .cra_u          =       { .digest = {
-       .dia_digestsize =       SHA512_DIGEST_SIZE,
-       .dia_init       =       sha512_init,
-       .dia_update     =       s390_sha_update,
-       .dia_final      =       s390_sha_final } }
+static struct shash_alg sha512_alg = {
+       .digestsize     =       SHA512_DIGEST_SIZE,
+       .init           =       sha512_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .base           =       {
+               .cra_name       =       "sha512",
+               .cra_driver_name=       "sha512-s390",
+               .cra_priority   =       CRYPT_S390_PRIORITY,
+               .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize  =       SHA512_BLOCK_SIZE,
+               .cra_module     =       THIS_MODULE,
+       }
 };
 
 MODULE_ALIAS("sha512");
 
-static void sha384_init(struct crypto_tfm *tfm)
+static int sha384_init(struct shash_desc *desc)
 {
-       struct s390_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
 
        *(__u64 *)&ctx->state[0] = 0xcbbb9d5dc1059ed8ULL;
        *(__u64 *)&ctx->state[2] = 0x629a292a367cd507ULL;
@@ -67,22 +69,25 @@ static void sha384_init(struct crypto_tfm *tfm)
        *(__u64 *)&ctx->state[14] = 0x47b5481dbefa4fa4ULL;
        ctx->count = 0;
        ctx->func = KIMD_SHA_512;
+
+       return 0;
 }
 
-static struct crypto_alg sha384_alg = {
-       .cra_name       =       "sha384",
-       .cra_driver_name =      "sha384-s390",
-       .cra_priority   =       CRYPT_S390_PRIORITY,
-       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-       .cra_blocksize  =       SHA384_BLOCK_SIZE,
-       .cra_ctxsize    =       sizeof(struct s390_sha_ctx),
-       .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(sha384_alg.cra_list),
-       .cra_u          =       { .digest = {
-       .dia_digestsize =       SHA384_DIGEST_SIZE,
-       .dia_init       =       sha384_init,
-       .dia_update     =       s390_sha_update,
-       .dia_final      =       s390_sha_final } }
+static struct shash_alg sha384_alg = {
+       .digestsize     =       SHA384_DIGEST_SIZE,
+       .init           =       sha384_init,
+       .update         =       s390_sha_update,
+       .final          =       s390_sha_final,
+       .descsize       =       sizeof(struct s390_sha_ctx),
+       .base           =       {
+               .cra_name       =       "sha384",
+               .cra_driver_name=       "sha384-s390",
+               .cra_priority   =       CRYPT_S390_PRIORITY,
+               .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize  =       SHA384_BLOCK_SIZE,
+               .cra_ctxsize    =       sizeof(struct s390_sha_ctx),
+               .cra_module     =       THIS_MODULE,
+       }
 };
 
 MODULE_ALIAS("sha384");
@@ -93,18 +98,18 @@ static int __init init(void)
 
        if (!crypt_s390_func_available(KIMD_SHA_512))
                return -EOPNOTSUPP;
-       if ((ret = crypto_register_alg(&sha512_alg)) < 0)
+       if ((ret = crypto_register_shash(&sha512_alg)) < 0)
                goto out;
-       if ((ret = crypto_register_alg(&sha384_alg)) < 0)
-               crypto_unregister_alg(&sha512_alg);
+       if ((ret = crypto_register_shash(&sha384_alg)) < 0)
+               crypto_unregister_shash(&sha512_alg);
 out:
        return ret;
 }
 
 static void __exit fini(void)
 {
-       crypto_unregister_alg(&sha512_alg);
-       crypto_unregister_alg(&sha384_alg);
+       crypto_unregister_shash(&sha512_alg);
+       crypto_unregister_shash(&sha384_alg);
 }
 
 module_init(init);
index 9d6eb8c3d37e3fac5df1312fd00d05554adbac3c..7903ec47e6b9c4a48ab9ffd6b2f47db7ee601678 100644 (file)
  *
  */
 
-#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
 #include "sha.h"
 #include "crypt_s390.h"
 
-void s390_sha_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
+int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
 {
-       struct s390_sha_ctx *ctx = crypto_tfm_ctx(tfm);
-       unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+       struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
+       unsigned int bsize = crypto_shash_blocksize(desc->tfm);
        unsigned int index;
        int ret;
 
@@ -51,13 +51,15 @@ void s390_sha_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
 store:
        if (len)
                memcpy(ctx->buf + index , data, len);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(s390_sha_update);
 
-void s390_sha_final(struct crypto_tfm *tfm, u8 *out)
+int s390_sha_final(struct shash_desc *desc, u8 *out)
 {
-       struct s390_sha_ctx *ctx = crypto_tfm_ctx(tfm);
-       unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+       struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
+       unsigned int bsize = crypto_shash_blocksize(desc->tfm);
        u64 bits;
        unsigned int index, end, plen;
        int ret;
@@ -87,9 +89,11 @@ void s390_sha_final(struct crypto_tfm *tfm, u8 *out)
        BUG_ON(ret != end);
 
        /* copy digest to out */
-       memcpy(out, ctx->state, crypto_hash_digestsize(crypto_hash_cast(tfm)));
+       memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm));
        /* wipe context */
        memset(ctx, 0, sizeof *ctx);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(s390_sha_final);
 
index ebabe518e729dcdb95fa551b21a4e404bca9ba93..8d50d527c595ff45be4a221cc8d4c6ad6956dca8 100644 (file)
@@ -107,6 +107,9 @@ config SYS_SUPPORTS_NUMA
 config SYS_SUPPORTS_PCI
        bool
 
+config SYS_SUPPORTS_CMT
+       bool
+
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -176,6 +179,10 @@ config CPU_SHX2
 config CPU_SHX3
        bool
 
+config ARCH_SHMOBILE
+       bool
+       select ARCH_SUSPEND_POSSIBLE
+
 choice
        prompt "Processor sub-type selection"
 
@@ -188,6 +195,7 @@ choice
 config CPU_SUBTYPE_SH7619
        bool "Support SH7619 processor"
        select CPU_SH2
+       select SYS_SUPPORTS_CMT
 
 # SH-2A Processor Support
 
@@ -200,15 +208,18 @@ config CPU_SUBTYPE_SH7203
        bool "Support SH7203 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7206
        bool "Support SH7206 processor"
        select CPU_SH2A
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7263
        bool "Support SH7263 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_MXG
        bool "Support MX-G processor"
@@ -323,7 +334,9 @@ config CPU_SUBTYPE_SH7723
        bool "Support SH7723 processor"
        select CPU_SH4A
        select CPU_SHX2
+       select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_CMT
        help
          Select SH7723 if you have an SH-MobileR2 CPU.
 
@@ -348,6 +361,14 @@ config CPU_SUBTYPE_SH7785
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
 
+config CPU_SUBTYPE_SH7786
+       bool "Support SH7786 processor"
+       select CPU_SH4A
+       select CPU_SHX3
+       select CPU_HAS_PTEAEX
+       select ARCH_SPARSEMEM_ENABLE
+       select SYS_SUPPORTS_NUMA
+
 config CPU_SUBTYPE_SHX3
        bool "Support SH-X3 processor"
        select CPU_SH4A
@@ -362,20 +383,26 @@ config CPU_SUBTYPE_SHX3
 config CPU_SUBTYPE_SH7343
        bool "Support SH7343 processor"
        select CPU_SH4AL_DSP
+       select ARCH_SHMOBILE
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
        select CPU_SH4AL_DSP
        select CPU_SHX2
+       select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_CMT
 
 config CPU_SUBTYPE_SH7366
        bool "Support SH7366 processor"
        select CPU_SH4AL_DSP
        select CPU_SHX2
+       select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_CMT
 
 # SH-5 Processor Support
 
@@ -398,25 +425,34 @@ source "arch/sh/boards/Kconfig"
 menu "Timer and clock configuration"
 
 config SH_TMU
-       def_bool y
-       prompt "TMU timer support"
+       bool "TMU timer support"
        depends on CPU_SH3 || CPU_SH4
+       default y
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        help
          This enables the use of the TMU as the system timer.
 
 config SH_CMT
-       def_bool y
-       prompt "CMT timer support"
-       depends on CPU_SH2 && !CPU_SUBTYPE_MXG
+       bool "CMT timer support"
+       depends on SYS_SUPPORTS_CMT && CPU_SH2
+       default y
        help
          This enables the use of the CMT as the system timer.
 
+#
+# Support for the new-style CMT driver. This will replace SH_CMT
+# once its other dependencies are merged.
+#
+config SH_TIMER_CMT
+       bool "CMT clockevents driver"
+       depends on SYS_SUPPORTS_CMT && !SH_CMT
+       select GENERIC_CLOCKEVENTS
+
 config SH_MTU2
-       def_bool n
-       prompt "MTU2 timer support"
+       bool "MTU2 timer support"
        depends on CPU_SH2A
+       default y
        help
          This enables the use of the MTU2 as the system timer.
 
@@ -426,7 +462,8 @@ config SH_TIMER_IRQ
                        CPU_SUBTYPE_SH7763
        default "86" if CPU_SUBTYPE_SH7619
        default "140" if CPU_SUBTYPE_SH7206
-       default "142" if CPU_SUBTYPE_SH7203
+       default "142" if CPU_SUBTYPE_SH7203 && SH_CMT
+       default "153" if CPU_SUBTYPE_SH7203 && SH_MTU2
        default "238" if CPU_SUBTYPE_MXG
        default "16"
 
@@ -438,7 +475,8 @@ config SH_PCLK_FREQ
        default "33333333" if CPU_SUBTYPE_SH7770 || CPU_SUBTYPE_SH7723 || \
                              CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
                              CPU_SUBTYPE_SH7203 || CPU_SUBTYPE_SH7206 || \
-                             CPU_SUBTYPE_SH7263 || CPU_SUBTYPE_MXG
+                             CPU_SUBTYPE_SH7263 || CPU_SUBTYPE_MXG    || \
+                             CPU_SUBTYPE_SH7786
        default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R
        default "66000000" if CPU_SUBTYPE_SH4_202
        default "50000000"
@@ -521,6 +559,13 @@ config CRASH_DUMP
 
          For more details see Documentation/kdump/kdump.txt
 
+config KEXEC_JUMP
+       bool "kexec jump (EXPERIMENTAL)"
+       depends on SUPERH32 && KEXEC && HIBERNATION && EXPERIMENTAL
+       help
+         Jump between original kernel and kexeced kernel and invoke
+         code via KEXEC
+
 config SECCOMP
        bool "Enable seccomp to safely compute untrusted bytecode"
        depends on PROC_FS
index 0e27fe3b182b74e17e05a4b612a3a8f5081c4382..c7d704381a6d5425548751ed4874580a0e3c1ab9 100644 (file)
@@ -104,6 +104,9 @@ config CPU_HAS_SR_RB
 config CPU_HAS_PTEA
        bool
 
+config CPU_HAS_PTEAEX
+       bool
+
 config CPU_HAS_DSP
        bool
 
index 4067b0d9287b5000290784cdf07a9322cf90aa1c..bece1f7535f2008c9f3199753e2241f1f73f9fb2 100644 (file)
@@ -80,6 +80,7 @@ OBJCOPYFLAGS  := -O binary -R .note -R .note.gnu.build-id -R .comment \
 defaultimage-$(CONFIG_SUPERH32)                        := zImage
 defaultimage-$(CONFIG_SH_SH7785LCR)            := uImage
 defaultimage-$(CONFIG_SH_RSK)                  := uImage
+defaultimage-$(CONFIG_SH_URQUELL)              := uImage
 defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux
 defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux
 
index 861914747e4ecf4d2ea2ab2ad81e5c0c4a690d9c..dcc1af8a2cfe6428c00f0b4f400ffb27cb675ca1 100644 (file)
@@ -155,17 +155,22 @@ config SH_SH7785LCR
 
 config SH_SH7785LCR_29BIT_PHYSMAPS
        bool "SH7785LCR 29bit physmaps"
-       depends on SH_SH7785LCR
+       depends on SH_SH7785LCR && 29BIT
        default y
        help
          This board has 2 physical memory maps. It can be changed with
          DIP switch(S2-5). If you set the DIP switch for S2-5 = ON,
          you can access all on-board device in 29bit address mode.
 
+config SH_URQUELL
+       bool "Urquell"
+       depends on CPU_SUBTYPE_SH7786
+       select ARCH_REQUIRE_GPIOLIB
+
 config SH_MIGOR
        bool "Migo-R"
        depends on CPU_SUBTYPE_SH7722
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Select Migo-R if configuring for the SH7722 Migo-R platform
           by Renesas System Solutions Asia Pte. Ltd.
@@ -173,7 +178,7 @@ config SH_MIGOR
 config SH_AP325RXA
        bool "AP-325RXA"
        depends on CPU_SUBTYPE_SH7723
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Renesas "AP-325RXA" support.
          Compatible with ALGO SYSTEM CO.,LTD. "AP-320A"
@@ -185,6 +190,13 @@ config SH_SH7763RDP
          Select SH7763RDP if configuring for a Renesas SH7763
          evaluation board.
 
+config SH_ESPT
+       bool "ESPT"
+       depends on CPU_SUBTYPE_SH7763
+       help
+         Select ESPT if configuring for a Renesas SH7763
+         with gigabit ether evaluation board.
+
 config SH_EDOSK7705
        bool "EDOSK7705"
        depends on CPU_SUBTYPE_SH7705
@@ -240,7 +252,7 @@ config SH_X3PROTO
 config SH_MAGIC_PANEL_R2
        bool "Magic Panel R2"
        depends on CPU_SUBTYPE_SH7720
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        help
          Select Magic Panel R2 if configuring for Magic Panel R2.
 
@@ -249,6 +261,13 @@ config SH_CAYMAN
        depends on CPU_SUBTYPE_SH5_101 || CPU_SUBTYPE_SH5_103
        select SYS_SUPPORTS_PCI
 
+config SH_POLARIS
+       bool "SMSC Polaris"
+       select CPU_HAS_IPR_IRQ
+       depends on CPU_SUBTYPE_SH7709
+       help
+         Select if configuring for an SMSC Polaris development board
+
 endmenu
 
 source "arch/sh/boards/mach-r2d/Kconfig"
index 269ae2be49ef5cc7b966d671488cc62368cd4c35..7baa2109023147f075b7d4c5e9cb2ecde248968e 100644 (file)
@@ -4,5 +4,8 @@
 obj-$(CONFIG_SH_AP325RXA)      += board-ap325rxa.o
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
+obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
 obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
+obj-$(CONFIG_SH_ESPT)          += board-espt.o
+obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
index 15b6d450fbf0e6e8c83542308608a89f6e913952..a64e38841c496448139c2f1e3ac3c05e9c52a094 100644 (file)
@@ -166,6 +166,16 @@ static void ap320_wvga_power_on(void *board_data)
        ctrl_outw(0x100, FPGA_BKLREG);
 }
 
+static void ap320_wvga_power_off(void *board_data)
+{
+       /* backlight */
+       ctrl_outw(0, FPGA_BKLREG);
+       gpio_set_value(GPIO_PTS3, 1);
+
+       /* ASD AP-320/325 LCD OFF */
+       ctrl_outw(0, FPGA_LCDREG);
+}
+
 static struct sh_mobile_lcdc_info lcdc_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
@@ -191,6 +201,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                },
                .board_cfg = {
                        .display_on = ap320_wvga_power_on,
+                       .display_off = ap320_wvga_power_off,
                },
        }
 };
diff --git a/arch/sh/boards/board-espt.c b/arch/sh/boards/board-espt.c
new file mode 100644 (file)
index 0000000..d5ce5e1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Data Technology Inc. ESPT-GIGA board suport
+ *
+ * Copyright (C) 2008, 2009 Renesas Solutions Corp.
+ * Copyright (C) 2008, 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+#include <asm/sh_eth.h>
+
+/* NOR Flash */
+static struct mtd_partition espt_nor_flash_partitions[] = {
+       {
+               .name = "U-Boot",
+               .offset = 0,
+               .size = (2 * SZ_128K),
+               .mask_flags = MTD_WRITEABLE,    /* Read-only */
+       }, {
+               .name = "Linux-Kernel",
+               .offset = MTDPART_OFS_APPEND,
+               .size = (20 * SZ_128K),
+       }, {
+               .name = "Root Filesystem",
+               .offset = MTDPART_OFS_APPEND,
+               .size = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data espt_nor_flash_data = {
+       .width = 2,
+       .parts = espt_nor_flash_partitions,
+       .nr_parts = ARRAY_SIZE(espt_nor_flash_partitions),
+};
+
+static struct resource espt_nor_flash_resources[] = {
+       [0] = {
+               .name = "NOR Flash",
+               .start = 0,
+               .end = SZ_8M - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device espt_nor_flash_device = {
+       .name = "physmap-flash",
+       .resource = espt_nor_flash_resources,
+       .num_resources = ARRAY_SIZE(espt_nor_flash_resources),
+       .dev = {
+               .platform_data = &espt_nor_flash_data,
+       },
+};
+
+/* SH-Ether */
+static struct resource sh_eth_resources[] = {
+       {
+               .start  = 0xFEE00800,   /* use eth1 */
+               .end    = 0xFEE00F7C - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = 57,   /* irq number */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sh_eth_plat_data sh7763_eth_pdata = {
+       .phy = 0,
+       .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device espt_eth_device = {
+       .name       = "sh-eth",
+       .resource   = sh_eth_resources,
+       .num_resources  = ARRAY_SIZE(sh_eth_resources),
+       .dev        = {
+               .platform_data = &sh7763_eth_pdata,
+       },
+};
+
+static struct platform_device *espt_devices[] __initdata = {
+       &espt_nor_flash_device,
+       &espt_eth_device,
+};
+
+static int __init espt_devices_setup(void)
+{
+       return platform_add_devices(espt_devices,
+                                   ARRAY_SIZE(espt_devices));
+}
+device_initcall(espt_devices_setup);
+
+static struct sh_machine_vector mv_espt __initmv = {
+       .mv_name = "ESPT-GIGA",
+};
diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c
new file mode 100644 (file)
index 0000000..62607eb
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * June 2006 steve.glendinning@smsc.com
+ *
+ * Polaris-specific resource declaration
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/heartbeat.h>
+#include <cpu/gpio.h>
+#include <mach-se/mach/se.h>
+
+#define BCR2           (0xFFFFFF62)
+#define WCR2           (0xFFFFFF66)
+#define AREA5_WAIT_CTRL        (0x1C00)
+#define WAIT_STATES_10 (0x7)
+
+static struct resource smsc911x_resources[] = {
+       [0] = {
+               .name           = "smsc911x-memory",
+               .start          = PA_EXT5,
+               .end            = PA_EXT5 + 0x1fff,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name           = "smsc911x-irq",
+               .start          = IRQ0_IRQ,
+               .end            = IRQ0_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_32BIT,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
+       .dev = {
+               .platform_data = &smsc911x_config,
+       },
+};
+
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 };
+
+static struct heartbeat_data heartbeat_data = {
+       .bit_pos        = heartbeat_bit_pos,
+       .nr_bits        = ARRAY_SIZE(heartbeat_bit_pos),
+       .regsize        = 8,
+};
+
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = PORT_PCDR,
+               .end    = PORT_PCDR,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .dev    = {
+               .platform_data  = &heartbeat_data,
+       },
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+static struct platform_device *polaris_devices[] __initdata = {
+       &smsc911x_device,
+       &heartbeat_device,
+};
+
+static int __init polaris_initialise(void)
+{
+       u16 wcr, bcr_mask;
+
+       printk(KERN_INFO "Configuring Polaris external bus\n");
+
+       /* Configure area 5 with 2 wait states */
+       wcr = ctrl_inw(WCR2);
+       wcr &= (~AREA5_WAIT_CTRL);
+       wcr |= (WAIT_STATES_10 << 10);
+       ctrl_outw(wcr, WCR2);
+
+       /* Configure area 5 for 32-bit access */
+       bcr_mask = ctrl_inw(BCR2);
+       bcr_mask |= 1 << 10;
+       ctrl_outw(bcr_mask, BCR2);
+
+       return platform_add_devices(polaris_devices,
+                                   ARRAY_SIZE(polaris_devices));
+}
+arch_initcall(polaris_initialise);
+
+static struct ipr_data ipr_irq_table[] = {
+       /* External IRQs */
+       { IRQ0_IRQ, 0,  0,  1, },       /* IRQ0 */
+       { IRQ1_IRQ, 0,  4,  1, },       /* IRQ1 */
+};
+
+static unsigned long ipr_offsets[] = {
+       INTC_IPRC
+};
+
+static struct ipr_desc ipr_irq_desc = {
+       .ipr_offsets    = ipr_offsets,
+       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
+
+       .ipr_data       = ipr_irq_table,
+       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
+       .chip = {
+               .name   = "sh7709-ext",
+       },
+};
+
+static void __init init_polaris_irq(void)
+{
+       /* Disable all interrupts */
+       ctrl_outw(0, BCR_ILCRA);
+       ctrl_outw(0, BCR_ILCRB);
+       ctrl_outw(0, BCR_ILCRC);
+       ctrl_outw(0, BCR_ILCRD);
+       ctrl_outw(0, BCR_ILCRE);
+       ctrl_outw(0, BCR_ILCRF);
+       ctrl_outw(0, BCR_ILCRG);
+
+       register_ipr_controller(&ipr_irq_desc);
+}
+
+static struct sh_machine_vector mv_polaris __initmv = {
+       .mv_name                = "Polaris",
+       .mv_nr_irqs             = 61,
+       .mv_init_irq            = init_polaris_irq,
+};
index 38a64968d7bf84366cae105e4b18d6cf43da350d..94c0296bc35df2663cbff4398d3b1ab868b1ac72 100644 (file)
@@ -275,7 +275,18 @@ void __init init_sh7785lcr_IRQ(void)
 
 static void sh7785lcr_power_off(void)
 {
-       ctrl_outb(0x01, P2SEGADDR(PLD_POFCR));
+       unsigned char *p;
+
+       p = ioremap(PLD_POFCR, PLD_POFCR + 1);
+       if (!p) {
+               printk(KERN_ERR "%s: ioremap error.\n", __func__);
+               return;
+       }
+       *p = 0x01;
+       iounmap(p);
+       set_bl_bit();
+       while (1)
+               cpu_relax();
 }
 
 /* Initialize the board */
diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c
new file mode 100644 (file)
index 0000000..17036ce
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Renesas Technology Corp. SH7786 Urquell Support.
+ *
+ * Copyright (C) 2008  Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2008  Yoshihiro Shimoda
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/smc91x.h>
+#include <linux/mtd/physmap.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <mach/urquell.h>
+#include <cpu/sh7786.h>
+#include <asm/heartbeat.h>
+#include <asm/sizes.h>
+
+static struct resource heartbeat_resources[] = {
+       [0] = {
+               .start  = BOARDREG(SLEDR),
+               .end    = BOARDREG(SLEDR),
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct heartbeat_data heartbeat_data = {
+       .regsize = 16,
+};
+
+static struct platform_device heartbeat_device = {
+       .name           = "heartbeat",
+       .id             = -1,
+       .dev    = {
+               .platform_data  = &heartbeat_data,
+       },
+       .num_resources  = ARRAY_SIZE(heartbeat_resources),
+       .resource       = heartbeat_resources,
+};
+
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
+static struct resource smc91x_eth_resources[] = {
+       [0] = {
+               .name   = "SMC91C111" ,
+               .start  = 0x05800300,
+               .end    = 0x0580030f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 11,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc91x_eth_device = {
+       .name           = "smc91x",
+       .num_resources  = ARRAY_SIZE(smc91x_eth_resources),
+       .resource       = smc91x_eth_resources,
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+static struct mtd_partition nor_flash_partitions[] = {
+       {
+               .name           = "loader",
+               .offset         = 0x00000000,
+               .size           = SZ_512K,
+               .mask_flags     = MTD_WRITEABLE,        /* Read-only */
+       },
+       {
+               .name           = "bootenv",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_512K,
+               .mask_flags     = MTD_WRITEABLE,        /* Read-only */
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_4M,
+       },
+       {
+               .name           = "data",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data nor_flash_data = {
+       .width          = 2,
+       .parts          = nor_flash_partitions,
+       .nr_parts       = ARRAY_SIZE(nor_flash_partitions),
+};
+
+static struct resource nor_flash_resources[] = {
+       [0] = {
+               .start  = NOR_FLASH_ADDR,
+               .end    = NOR_FLASH_ADDR + NOR_FLASH_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device nor_flash_device = {
+       .name           = "physmap-flash",
+       .dev            = {
+               .platform_data  = &nor_flash_data,
+       },
+       .num_resources  = ARRAY_SIZE(nor_flash_resources),
+       .resource       = nor_flash_resources,
+};
+
+static struct platform_device *urquell_devices[] __initdata = {
+       &heartbeat_device,
+       &smc91x_eth_device,
+       &nor_flash_device,
+};
+
+static int __init urquell_devices_setup(void)
+{
+       /* USB */
+       gpio_request(GPIO_FN_USB_OVC0,  NULL);
+       gpio_request(GPIO_FN_USB_PENC0, NULL);
+
+       return platform_add_devices(urquell_devices,
+                                   ARRAY_SIZE(urquell_devices));
+}
+device_initcall(urquell_devices_setup);
+
+static void urquell_power_off(void)
+{
+       __raw_writew(0xa5a5, UBOARDREG(SRSTR));
+}
+
+static void __init urquell_init_irq(void)
+{
+       plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK);
+}
+
+/* Initialize the board */
+static void __init urquell_setup(char **cmdline_p)
+{
+       printk(KERN_INFO "Renesas Technology Corp. Urquell support.\n");
+
+       pm_power_off = urquell_power_off;
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_urquell __initmv = {
+       .mv_name        = "Urquell",
+       .mv_setup       = urquell_setup,
+       .mv_init_irq    = urquell_init_irq,
+};
index 08057f62687b7bcc3e3687dabf4b53554500d080..def49cc0a7b9266b3d1f75a074017a2f49b670ac 100644 (file)
@@ -18,7 +18,7 @@ config SH_R7780MP
 config SH_R7785RP
        bool "R7785RP board support"
        depends on CPU_SUBTYPE_SH7785
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
 
 endchoice
 
index 44b648cf6f235988e42c10a566f92a64c309a2db..4f18d44e05413f265e3de3d5629d6a8e97f50093 100644 (file)
 #include <linux/linkage.h>
 #include <cpu/mmu_context.h>
 
-#define k0     r0
-#define k1     r1
-#define k2     r2
-#define k3     r3
-#define k4     r4
-
 /*
  * Kernel mode register usage:
  *     k0      scratch
  *     k1      scratch
- *     k2      scratch (Exception code)
- *     k3      scratch (Return address)
- *     k4      scratch
- *     k5      reserved
- *     k6      Global Interrupt Mask (0--15 << 4)
- *     k7      CURRENT_THREAD_INFO (pointer to current thread info)
+ * For more details, please have a look at entry.S
  */
 
+#define k0     r0
+#define k1     r1
+
 ENTRY(wakeup_start)
 ! clear STBY bit
-       mov     #-126, k2
+       mov     #-126, k1
        and     #127, k0
-       mov.b   k0, @k2
+       mov.b   k0, @k1
 ! enable refresh
        mov.l   5f, k1
        mov.w   6f, k0
        mov.w   k0, @k1
 ! jump to handler
-       mov.l   2f, k2
-       mov.l   3f, k3
-       mov.l   @k2, k2
-
        mov.l   4f, k1
        jmp     @k1
-       nop
+        nop
 
        .align  2
-1:     .long   EXPEVT
-2:     .long   INTEVT
-3:     .long   ret_from_irq
-4:     .long   handle_exception
+4:     .long   handle_interrupt
 5:     .long   0xffffff68
 6:     .word   0x0524
 
index 746742bdc0142d6d45be6c55bbe38970be3324d1..8f305b36358ba4912ea6c9bf2deb2fd017969421 100644 (file)
@@ -115,7 +115,6 @@ static struct sh_machine_vector mv_hp6xx __initmv = {
        .mv_setup = hp6xx_setup,
        /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
        .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
-       .mv_irq_demux = hd64461_irq_demux,
        /* Enable IRQ0 -> IRQ3 in IRQ_MODE */
        .mv_init_irq = hp6xx_init_irq,
 };
index 28e56c5809a2187f543afa749465651a29c47ded..bc35b4cae6b3678f4e7062b8af0a5bf45c9e2194 100644 (file)
@@ -450,6 +450,14 @@ static struct spi_board_info migor_spi_devices[] = {
 
 static int __init migor_devices_setup(void)
 {
+
+#ifdef CONFIG_PM
+       /* Let D11 LED show STATUS0 */
+       gpio_request(GPIO_FN_STATUS0, NULL);
+
+       /* Lit D12 LED show PDSTATUS */
+       gpio_request(GPIO_FN_PDSTATUS, NULL);
+#else
        /* Lit D11 LED */
        gpio_request(GPIO_PTJ7, NULL);
        gpio_direction_output(GPIO_PTJ7, 1);
@@ -459,6 +467,7 @@ static int __init migor_devices_setup(void)
        gpio_request(GPIO_PTJ5, NULL);
        gpio_direction_output(GPIO_PTJ5, 1);
        gpio_export(GPIO_PTJ5, 0);
+#endif
 
        /* SMC91C111 - Enable IRQ0, Setup CS4 for 16-bit fast access */
        gpio_request(GPIO_FN_IRQ0, NULL);
index bff095dffc02bbb41525c9c81a3042a00d5b4433..aeff3b04220590f70a28de6d4ff960326a78b034 100644 (file)
@@ -10,7 +10,7 @@ config SH_RSK7201
 
 config SH_RSK7203
        bool "RSK7203"
-       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        depends on CPU_SUBTYPE_SH7203
 
 endchoice
index 6f926fd2162b20380034add765471f2f72b7f2b0..390534a0b35c860a9545678b00e4d4c633867ca4 100644 (file)
@@ -63,15 +63,19 @@ static struct platform_device sh7763rdp_nor_flash_device = {
        },
 };
 
-/* SH-Ether */
+/*
+ * SH-Ether
+ *
+ * SH Ether of SH7763 has multi IRQ handling.
+ * (57,58,59 -> 57)
+ */
 static struct resource sh_eth_resources[] = {
        {
                .start  = 0xFEE00800,   /* use eth1 */
                .end    = 0xFEE00F7C - 1,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 58,   /* irq number */
-               .end    = 58,
+               .start  = 57,   /* irq number */
                .flags  = IORESOURCE_IRQ,
        },
 };
index c16ccd4bfa16ac4b424e1032ada796f75ea88e32..95483d16125882d69d24620f9f8d5a8c7e736c98 100644 (file)
@@ -33,20 +33,24 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
 $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
-ifeq ($(CONFIG_32BIT),y)
-KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
-                    $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_ZERO_PAGE_OFFSET)]')
-else
+KERNEL_MEMORY := 0x00000000
+ifeq ($(CONFIG_PMB_FIXED),y)
+KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
+                    $$[$(CONFIG_MEMORY_START) & 0x1fffffff]')
+endif
+ifeq ($(CONFIG_29BIT),y)
+KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
+                    $$[$(CONFIG_MEMORY_START)]')
+endif
+
 KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_MEMORY_START) + \
+                       $(KERNEL_MEMORY) + \
                        $(CONFIG_ZERO_PAGE_OFFSET)]')
-endif
 
 KERNEL_ENTRY   := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_MEMORY_START) + \
+                       $(KERNEL_MEMORY) + \
                        $(CONFIG_ZERO_PAGE_OFFSET) + $(CONFIG_ENTRY_OFFSET)]')
 
 quiet_cmd_uimage = UIMAGE  $@
index 27ceeb948bb1059a142f627c540d07848993e52b..25ef910615217a5c7115d19e77d9008c68085b67 100644 (file)
@@ -53,21 +53,22 @@ static struct irq_chip hd64461_irq_chip = {
        .unmask         = hd64461_unmask_irq,
 };
 
-int hd64461_irq_demux(int irq)
+static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-       if (irq == CONFIG_HD64461_IRQ) {
-               unsigned short bit;
-               unsigned short nirr = inw(HD64461_NIRR);
-               unsigned short nimr = inw(HD64461_NIMR);
-               int i;
-
-               nirr &= ~nimr;
-               for (bit = 1, i = 0; i < 16; bit <<= 1, i++)
-                       if (nirr & bit)
-                               break;
-               irq = HD64461_IRQBASE + i;
+       unsigned short intv = ctrl_inw(HD64461_NIRR);
+       struct irq_desc *ext_desc;
+       unsigned int ext_irq = HD64461_IRQBASE;
+
+       intv &= (1 << HD64461_IRQ_NUM) - 1;
+
+       while (intv) {
+               if (intv & 1) {
+                       ext_desc = irq_desc + ext_irq;
+                       handle_level_irq(ext_irq, ext_desc);
+               }
+               intv >>= 1;
+               ext_irq++;
        }
-       return irq;
 }
 
 int __init setup_hd64461(void)
@@ -93,6 +94,9 @@ int __init setup_hd64461(void)
                set_irq_chip_and_handler(i, &hd64461_irq_chip,
                                         handle_level_irq);
 
+       set_irq_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux);
+       set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW);
+
 #ifdef CONFIG_HD64461_ENABLER
        printk(KERN_INFO "HD64461: enabling PCMCIA devices\n");
        __raw_writeb(0x4c, HD64461_PCC1CSCIER);
diff --git a/arch/sh/configs/espt_defconfig b/arch/sh/configs/espt_defconfig
new file mode 100644 (file)
index 0000000..873ec42
--- /dev/null
@@ -0,0 +1,1190 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc7
+# Tue Mar 17 13:25:58 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+CONFIG_CPU_SUBTYPE_SH7763=y
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH7786 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_29BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+# CONFIG_SH_SH7763RDP is not set
+CONFIG_SH_ESPT=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+CONFIG_SH_PCLK_FREQ=66666666
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/nfs ip=bootp"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+# CONFIG_CPU_IDLE is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+CONFIG_SH_ETH=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=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=y
+CONFIG_FB_BOTH_ENDIAN=y
+# CONFIG_FB_BIG_ENDIAN is not set
+# CONFIG_FB_LITTLE_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_SH_MOBILE_LCDC is not set
+CONFIG_FB_SH7760=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_SUPERH_MONO=y
+CONFIG_LOGO_SUPERH_VGA16=y
+CONFIG_LOGO_SUPERH_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/polaris_defconfig b/arch/sh/configs/polaris_defconfig
new file mode 100644 (file)
index 0000000..320def2
--- /dev/null
@@ -0,0 +1,969 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc4
+# Wed Feb 11 18:41:59 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+CONFIG_CPU_SUBTYPE_SH7709=y
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0C000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_29BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU_EMU=y
+CONFIG_SH_ADC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Board support
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_HP6XX is not set
+CONFIG_SH_POLARIS=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=33000000
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA_API=y
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_GUSA=y
+# CONFIG_GUSA_RB is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 root=/dev/mtdblock2 rootfstype=jffs2 mem=63M mtdparts=physmap-flash.0:0x00100000(bootloader)ro,0x00500000(Kernel)ro,0x00A00000(Filesystem)"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+# CONFIG_CPU_IDLE is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_COMPAT=y
+CONFIG_MTD_PHYSMAP_START=0x00000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_QINFO_PROBE is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_PI_LIST=y
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_PROVE_LOCKING is not set
+CONFIG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_DEBUG_SG=y
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0x00000000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_IRQSTACKS is not set
+CONFIG_DUMP_CODE=y
+# CONFIG_SH_NO_BSS_INIT is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
new file mode 100644 (file)
index 0000000..54e1dee
--- /dev/null
@@ -0,0 +1,1553 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc4
+# Fri Feb 20 18:25:29 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_SYS_SUPPORTS_NUMA=y
+CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_IO_TRAPPED=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+CONFIG_CPU_SUBTYPE_SH7785=y
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x20000000
+# CONFIG_29BIT is not set
+CONFIG_32BIT=y
+CONFIG_PMB_ENABLE=y
+# CONFIG_PMB is not set
+CONFIG_PMB_FIXED=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+# CONFIG_NUMA is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=2
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+# CONFIG_SH_HIGHLANDER is not set
+CONFIG_SH_SH7785LCR=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+CONFIG_SH_PCLK_FREQ=50000000
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+# CONFIG_CPU_IDLE is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_QINFO_PROBE is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOPCA=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_I2C_PCA_PLATFORM=y
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+CONFIG_MFD_SM501=y
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL 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=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_DEFERRED_IO=y
+# 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_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_SH_MOBILE_LCDC=m
+CONFIG_FB_SM501=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+# CONFIG_LOGO_SUPERH_CLUT224 is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+CONFIG_THRUSTMASTER_FF=m
+CONFIG_ZEROPLUS_FF=m
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_R8A66597_HCD=y
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+CONFIG_RTC_DRV_RS5C372=y
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_SH is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_DEBUG_BOOTMEM is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_DUMP_CODE is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/urquell_defconfig b/arch/sh/configs/urquell_defconfig
new file mode 100644 (file)
index 0000000..be726c7
--- /dev/null
@@ -0,0 +1,1332 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc4
+# Thu Mar  5 17:28:13 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_SYS_SUPPORTS_NUMA=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+CONFIG_CPU_SUBTYPE_SH7786=y
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_29BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+# CONFIG_NUMA is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+CONFIG_SH_URQUELL=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1, 38400 earlyprintk=serial ip=on ignore_loglevel root=/dev/nfs ip=dhcp memchunk.vpu=4m"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+# CONFIG_CPU_IDLE is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_QINFO_PROBE is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_MV is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOPCA=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_I2C_PCA_PLATFORM=y
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+CONFIG_MFD_SM501=y
+# CONFIG_MFD_SM501_GPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=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=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_DEFERRED_IO=y
+# 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_SH_MOBILE_LCDC=m
+CONFIG_FB_SM501=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+# CONFIG_LOGO_SUPERH_CLUT224 is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_NTRIG is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+CONFIG_THRUSTMASTER_FF=m
+CONFIG_ZEROPLUS_FF=m
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 01936368b8b0d5529dfa6675a7b69560accfcbce..f13a05285a9debead65c8a6911e5bc4cb291b7dc 100644 (file)
@@ -9,13 +9,21 @@ config SH_DMA
        select SH_DMA_API
        default n
 
+config SH_DMA_IRQ_MULTI
+       bool
+       depends on SH_DMA
+       default y if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7751 || \
+               CPU_SUBTYPE_SH7750S || CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R || \
+               CPU_SUBTYPE_SH7091 || CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7764 || \
+               CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
+
 config NR_ONCHIP_DMA_CHANNELS
        int
        depends on SH_DMA
-       default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
-       default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
-       default "12" if CPU_SUBTYPE_SH7780
-       default "4"
+       default "4" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7750S
+       default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R || CPU_SUBTYPE_SH7760
+       default "12" if CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
+       default "6"
        help
          This allows you to specify the number of channels that the on-chip
          DMAC supports. This will be 4 for SH7750/SH7751 and 8 for the
@@ -46,4 +54,28 @@ config SH_DMABRG
          of the SH7760.
          Say Y if you want to use Audio/USB DMA on your SH7760 board.
 
+config PVR2_DMA
+       tristate "PowerVR 2 DMAC support"
+       depends on SH_DREAMCAST && SH_DMA
+       help
+         Selecting this will enable support for the PVR2 DMA controller.
+         As this chains off of the on-chip DMAC, that must also be
+         enabled by default.
+
+         This is primarily used by the pvr2fb framebuffer driver for
+         certain optimizations, but is not necessary for functionality.
+
+         If in doubt, say N.
+
+config G2_DMA
+       tristate "G2 Bus DMA support"
+       depends on SH_DREAMCAST
+       select SH_DMA_API
+       help
+         This enables support for the DMA controller for the Dreamcast's
+         G2 bus. Drivers that want this will generally enable this on
+         their own.
+
+         If in doubt, say N.
+
 endmenu
index ab956adacb47688505f53061a105eae22134eb38..c6068137b46f42aa13f8491a3a8a298a4514d01b 100644 (file)
@@ -4,5 +4,6 @@
 
 obj-$(CONFIG_SH_DMA_API)       += dma-api.o dma-sysfs.o
 obj-$(CONFIG_SH_DMA)           += dma-sh.o
-obj-$(CONFIG_SH_DREAMCAST)     += dma-pvr2.o dma-g2.o
+obj-$(CONFIG_PVR2_DMA)         += dma-pvr2.o
+obj-$(CONFIG_G2_DMA)           += dma-g2.o
 obj-$(CONFIG_SH_DMABRG)                += dmabrg.o
index 50887a592dd02e3a13a0360357069ada0277a2e6..37fb5b8bbc3f122d0e0a1b3e50ee43b6e630fcc6 100644 (file)
 #include <mach-dreamcast/mach/dma.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include "dma-sh.h"
-
-static int dmte_irq_map[] = {
-       DMTE0_IRQ,
-       DMTE1_IRQ,
-       DMTE2_IRQ,
-       DMTE3_IRQ,
-#if defined(CONFIG_CPU_SUBTYPE_SH7720)  ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7721)  ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7751R) ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7760)  ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)  ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7780)
-       DMTE4_IRQ,
-       DMTE5_IRQ,
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7751R) ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7760)  ||     \
-    defined(CONFIG_CPU_SUBTYPE_SH7780)
-       DMTE6_IRQ,
-       DMTE7_IRQ,
+#include <asm/dma-sh.h>
+
+#if defined(DMAE1_IRQ)
+#define NR_DMAE                2
+#else
+#define NR_DMAE                1
 #endif
+
+static const char *dmae_name[] = {
+       "DMAC Address Error0", "DMAC Address Error1"
 };
 
 static inline unsigned int get_dmte_irq(unsigned int chan)
@@ -46,7 +34,14 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
        unsigned int irq = 0;
        if (chan < ARRAY_SIZE(dmte_irq_map))
                irq = dmte_irq_map[chan];
+
+#if defined(CONFIG_SH_DMA_IRQ_MULTI)
+       if (irq > DMTE6_IRQ)
+               return DMTE6_IRQ;
+       return DMTE0_IRQ;
+#else
        return irq;
+#endif
 }
 
 /*
@@ -59,7 +54,7 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
  */
 static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
 {
-       u32 chcr = ctrl_inl(CHCR[chan->chan]);
+       u32 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
 
        return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT];
 }
@@ -75,13 +70,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id)
        struct dma_channel *chan = dev_id;
        u32 chcr;
 
-       chcr = ctrl_inl(CHCR[chan->chan]);
+       chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
 
        if (!(chcr & CHCR_TE))
                return IRQ_NONE;
 
        chcr &= ~(CHCR_IE | CHCR_DE);
-       ctrl_outl(chcr, CHCR[chan->chan]);
+       ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
 
        wake_up(&chan->wait_queue);
 
@@ -94,7 +89,12 @@ static int sh_dmac_request_dma(struct dma_channel *chan)
                return 0;
 
        return request_irq(get_dmte_irq(chan->chan), dma_tei,
-                          IRQF_DISABLED, chan->dev_id, chan);
+#if defined(CONFIG_SH_DMA_IRQ_MULTI)
+                               IRQF_SHARED,
+#else
+                               IRQF_DISABLED,
+#endif
+                               chan->dev_id, chan);
 }
 
 static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -115,7 +115,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
                chan->flags &= ~DMA_TEI_CAPABLE;
        }
 
-       ctrl_outl(chcr, CHCR[chan->chan]);
+       ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
 
        chan->flags |= DMA_CONFIGURED;
        return 0;
@@ -126,13 +126,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan)
        int irq;
        u32 chcr;
 
-       chcr = ctrl_inl(CHCR[chan->chan]);
+       chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
        chcr |= CHCR_DE;
 
        if (chan->flags & DMA_TEI_CAPABLE)
                chcr |= CHCR_IE;
 
-       ctrl_outl(chcr, CHCR[chan->chan]);
+       ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
 
        if (chan->flags & DMA_TEI_CAPABLE) {
                irq = get_dmte_irq(chan->chan);
@@ -150,9 +150,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan)
                disable_irq(irq);
        }
 
-       chcr = ctrl_inl(CHCR[chan->chan]);
+       chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
        chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
-       ctrl_outl(chcr, CHCR[chan->chan]);
+       ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
 }
 
 static int sh_dmac_xfer_dma(struct dma_channel *chan)
@@ -183,12 +183,13 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
         */
        if (chan->sar || (mach_is_dreamcast() &&
                          chan->chan == PVR2_CASCADE_CHAN))
-               ctrl_outl(chan->sar, SAR[chan->chan]);
+               ctrl_outl(chan->sar, (dma_base_addr[chan->chan]+SAR));
        if (chan->dar || (mach_is_dreamcast() &&
                          chan->chan == PVR2_CASCADE_CHAN))
-               ctrl_outl(chan->dar, DAR[chan->chan]);
+               ctrl_outl(chan->dar, (dma_base_addr[chan->chan] + DAR));
 
-       ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]);
+       ctrl_outl(chan->count >> calc_xmit_shift(chan),
+               (dma_base_addr[chan->chan] + TCR));
 
        sh_dmac_enable_dma(chan);
 
@@ -197,36 +198,26 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
 
 static int sh_dmac_get_dma_residue(struct dma_channel *chan)
 {
-       if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE))
+       if (!(ctrl_inl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE))
                return 0;
 
-       return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan);
+       return ctrl_inl(dma_base_addr[chan->chan] + TCR)
+                << calc_xmit_shift(chan);
 }
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-#define dmaor_read_reg()       ctrl_inw(DMAOR)
-#define dmaor_write_reg(data)  ctrl_outw(data, DMAOR)
-#else
-#define dmaor_read_reg()       ctrl_inl(DMAOR)
-#define dmaor_write_reg(data)  ctrl_outl(data, DMAOR)
-#endif
-
-static inline int dmaor_reset(void)
+static inline int dmaor_reset(int no)
 {
-       unsigned long dmaor = dmaor_read_reg();
+       unsigned long dmaor = dmaor_read_reg(no);
 
        /* Try to clear the error flags first, incase they are set */
        dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
-       dmaor_write_reg(dmaor);
+       dmaor_write_reg(no, dmaor);
 
        dmaor |= DMAOR_INIT;
-       dmaor_write_reg(dmaor);
+       dmaor_write_reg(no, dmaor);
 
        /* See if we got an error again */
-       if ((dmaor_read_reg() & (DMAOR_AE | DMAOR_NMIF))) {
+       if ((dmaor_read_reg(no) & (DMAOR_AE | DMAOR_NMIF))) {
                printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n");
                return -EINVAL;
        }
@@ -237,10 +228,33 @@ static inline int dmaor_reset(void)
 #if defined(CONFIG_CPU_SH4)
 static irqreturn_t dma_err(int irq, void *dummy)
 {
-       dmaor_reset();
+#if defined(CONFIG_SH_DMA_IRQ_MULTI)
+       int cnt = 0;
+       switch (irq) {
+#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
+       case DMTE6_IRQ:
+               cnt++;
+#endif
+       case DMTE0_IRQ:
+               if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
+                       disable_irq(irq);
+                       /* DMA multi and error IRQ */
+                       return IRQ_HANDLED;
+               }
+       default:
+               return IRQ_NONE;
+       }
+#else
+       dmaor_reset(0);
+#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
+               defined(CONFIG_CPU_SUBTYPE_SH7780)      || \
+               defined(CONFIG_CPU_SUBTYPE_SH7785)
+       dmaor_reset(1);
+#endif
        disable_irq(irq);
 
        return IRQ_HANDLED;
+#endif
 }
 #endif
 
@@ -259,24 +273,59 @@ static struct dma_info sh_dmac_info = {
        .flags          = DMAC_CHANNELS_TEI_CAPABLE,
 };
 
+#ifdef CONFIG_CPU_SH4
+static unsigned int get_dma_error_irq(int n)
+{
+#if defined(CONFIG_SH_DMA_IRQ_MULTI)
+       return (n == 0) ? get_dmte_irq(0) : get_dmte_irq(6);
+#else
+       return (n == 0) ? DMAE0_IRQ :
+#if defined(DMAE1_IRQ)
+                               DMAE1_IRQ;
+#else
+                               -1;
+#endif
+#endif
+}
+#endif
+
 static int __init sh_dmac_init(void)
 {
        struct dma_info *info = &sh_dmac_info;
        int i;
 
 #ifdef CONFIG_CPU_SH4
-       i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0);
-       if (unlikely(i < 0))
-               return i;
+       int n;
+
+       for (n = 0; n < NR_DMAE; n++) {
+               i = request_irq(get_dma_error_irq(n), dma_err,
+#if defined(CONFIG_SH_DMA_IRQ_MULTI)
+                               IRQF_SHARED,
+#else
+                               IRQF_DISABLED,
 #endif
+                               dmae_name[n], (void *)dmae_name[n]);
+               if (unlikely(i < 0)) {
+                       printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
+                       return i;
+               }
+       }
+#endif /* CONFIG_CPU_SH4 */
 
        /*
         * Initialize DMAOR, and clean up any error flags that may have
         * been set.
         */
-       i = dmaor_reset();
+       i = dmaor_reset(0);
+       if (unlikely(i != 0))
+               return i;
+#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
+               defined(CONFIG_CPU_SUBTYPE_SH7780)      || \
+               defined(CONFIG_CPU_SUBTYPE_SH7785)
+       i = dmaor_reset(1);
        if (unlikely(i != 0))
                return i;
+#endif
 
        return register_dmac(info);
 }
@@ -284,8 +333,12 @@ static int __init sh_dmac_init(void)
 static void __exit sh_dmac_exit(void)
 {
 #ifdef CONFIG_CPU_SH4
-       free_irq(DMAE_IRQ, 0);
-#endif
+       int n;
+
+       for (n = 0; n < NR_DMAE; n++) {
+               free_irq(get_dma_error_irq(n), (void *)dmae_name[n]);
+       }
+#endif /* CONFIG_CPU_SH4 */
        unregister_dmac(&sh_dmac_info);
 }
 
diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h
deleted file mode 100644 (file)
index 05fecd5..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/sh/drivers/dma/dma-sh.h
- *
- * Copyright (C) 2000  Takashi YOSHII
- * Copyright (C) 2003  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __DMA_SH_H
-#define __DMA_SH_H
-
-#include <cpu/dma.h>
-
-/* Definitions for the SuperH DMAC */
-#define REQ_L  0x00000000
-#define REQ_E  0x00080000
-#define RACK_H 0x00000000
-#define RACK_L 0x00040000
-#define ACK_R  0x00000000
-#define ACK_W  0x00020000
-#define ACK_H  0x00000000
-#define ACK_L  0x00010000
-#define DM_INC 0x00004000
-#define DM_DEC 0x00008000
-#define SM_INC 0x00001000
-#define SM_DEC 0x00002000
-#define RS_IN  0x00000200
-#define RS_OUT 0x00000300
-#define TS_BLK 0x00000040
-#define TM_BUR 0x00000020
-#define CHCR_DE 0x00000001
-#define CHCR_TE 0x00000002
-#define CHCR_IE 0x00000004
-
-/* DMAOR definitions */
-#define DMAOR_AE       0x00000004
-#define DMAOR_NMIF     0x00000002
-#define DMAOR_DME      0x00000001
-
-/*
- * Define the default configuration for dual address memory-memory transfer.
- * The 0x400 value represents auto-request, external->external.
- */
-#define RS_DUAL        (DM_INC | SM_INC | 0x400 | TS_32)
-
-#define MAX_DMAC_CHANNELS      (CONFIG_NR_ONCHIP_DMA_CHANNELS)
-
-/*
- * Subtypes that have fewer channels than this simply need to change
- * CONFIG_NR_ONCHIP_DMA_CHANNELS. Likewise, subtypes with a larger number
- * of channels should expand on this.
- *
- * For most subtypes we can easily figure these values out with some
- * basic calculation, unfortunately on other subtypes these are more
- * scattered, so we just leave it unrolled for simplicity.
- */
-#define SAR    ((unsigned long[]){SH_DMAC_BASE + 0x00, SH_DMAC_BASE + 0x10, \
-                                  SH_DMAC_BASE + 0x20, SH_DMAC_BASE + 0x30, \
-                                  SH_DMAC_BASE + 0x50, SH_DMAC_BASE + 0x60})
-#define DAR    ((unsigned long[]){SH_DMAC_BASE + 0x04, SH_DMAC_BASE + 0x14, \
-                                  SH_DMAC_BASE + 0x24, SH_DMAC_BASE + 0x34, \
-                                  SH_DMAC_BASE + 0x54, SH_DMAC_BASE + 0x64})
-#define DMATCR ((unsigned long[]){SH_DMAC_BASE + 0x08, SH_DMAC_BASE + 0x18, \
-                                  SH_DMAC_BASE + 0x28, SH_DMAC_BASE + 0x38, \
-                                  SH_DMAC_BASE + 0x58, SH_DMAC_BASE + 0x68})
-#define CHCR   ((unsigned long[]){SH_DMAC_BASE + 0x0c, SH_DMAC_BASE + 0x1c, \
-                                  SH_DMAC_BASE + 0x2c, SH_DMAC_BASE + 0x3c, \
-                                  SH_DMAC_BASE + 0x5c, SH_DMAC_BASE + 0x6c})
-
-#define DMAOR  (SH_DMAC_BASE + 0x40)
-
-#endif /* __DMA_SH_H */
-
index 078dc44d6b08b8a6e5fc2090e832e8f5d6fcb977..773d575a04b9a385c332b7d91904c5a4d12cdbbe 100644 (file)
@@ -127,8 +127,8 @@ int __init sh7780_pcic_init(struct sh4_pci_address_map *map)
        pci_write_reg(word, SH4_PCILSR0);
        pci_write_reg(0x00000001, SH4_PCILSR1);
        /* Set the values on window 0 PCI config registers */
-       word = (CONFIG_MEMORY_SIZE > 0x08000000) ? 0x10000000 : 0x08000000;
-       pci_write_reg(word | 0xa0000000, SH4_PCILAR0);
+       word = CONFIG_MEMORY_START | (CONFIG_MEMORY_SIZE - 0x01000000);
+       pci_write_reg(word, SH4_PCILAR0);
        pci_write_reg(word, SH7780_PCIMBAR0);
        /* Set the values on window 1 PCI config registers */
        pci_write_reg(0x00000000, SH4_PCILAR1);
index 36736c7e93dbd7a7621b9874047e7957294e4397..80d40813e057fc235c4f0f6b21bd57c6f671345e 100644 (file)
@@ -31,7 +31,7 @@
 /* Returns the physical address of a PnSEG (n=1,2) address   */
 #define PHYSADDR(a)    (((unsigned long)(a)) & 0x1fffffff)
 
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
 /*
  * Map an address to a certain privileged segment
  */
@@ -43,7 +43,7 @@
        ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
 #define P4SEGADDR(a)   \
        ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
-#endif /* 29BIT */
+#endif /* 29BIT || PMB_FIXED */
 #endif /* P1SEG */
 
 /* Check if an address can be reached in 29 bits */
index 74f7943cff6f3a80b6c084c86d9b360945e05892..a0b348068cae66f4407760abde7013d0e7034f7a 100644 (file)
@@ -11,7 +11,7 @@ static inline void atomic_add(int i, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v += i;
+       v->counter += i;
        local_irq_restore(flags);
 }
 
@@ -20,7 +20,7 @@ static inline void atomic_sub(int i, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v -= i;
+       v->counter -= i;
        local_irq_restore(flags);
 }
 
@@ -29,9 +29,9 @@ static inline int atomic_add_return(int i, atomic_t *v)
        unsigned long temp, flags;
 
        local_irq_save(flags);
-       temp = *(long *)v;
+       temp = v->counter;
        temp += i;
-       *(long *)v = temp;
+       v->counter = temp;
        local_irq_restore(flags);
 
        return temp;
@@ -42,9 +42,9 @@ static inline int atomic_sub_return(int i, atomic_t *v)
        unsigned long temp, flags;
 
        local_irq_save(flags);
-       temp = *(long *)v;
+       temp = v->counter;
        temp -= i;
-       *(long *)v = temp;
+       v->counter = temp;
        local_irq_restore(flags);
 
        return temp;
@@ -55,7 +55,7 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v &= ~mask;
+       v->counter &= ~mask;
        local_irq_restore(flags);
 }
 
@@ -64,7 +64,7 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
        unsigned long flags;
 
        local_irq_save(flags);
-       *(long *)v |= mask;
+       v->counter |= mask;
        local_irq_restore(flags);
 }
 
index 1d2fc0b010adf1a608375d3a59c6cce57e42002a..d8328be0619113d254de7a9f2deec3648feee404 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_SH_BITOPS_LLSC_H
 #define __ASM_SH_BITOPS_LLSC_H
 
-static inline void set_bit(int nr, volatile void * addr)
+static inline void set_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -13,16 +13,16 @@ static inline void set_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! set_bit               \n\t"
-               "or             %3, %0                          \n\t"
+               "or             %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 }
 
-static inline void clear_bit(int nr, volatile void * addr)
+static inline void clear_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -34,16 +34,16 @@ static inline void clear_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! clear_bit             \n\t"
-               "and            %3, %0                          \n\t"
+               "and            %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (~mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (~mask)
                : "t", "memory"
        );
 }
 
-static inline void change_bit(int nr, volatile void * addr)
+static inline void change_bit(int nr, volatile void *addr)
 {
        int     mask;
        volatile unsigned int *a = addr;
@@ -55,16 +55,16 @@ static inline void change_bit(int nr, volatile void * addr)
        __asm__ __volatile__ (
                "1:                                             \n\t"
                "movli.l        @%1, %0 ! change_bit            \n\t"
-               "xor            %3, %0                          \n\t"
+               "xor            %2, %0                          \n\t"
                "movco.l        %0, @%1                         \n\t"
                "bf             1b                              \n\t"
-               : "=&z" (tmp), "=r" (a)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 }
 
-static inline int test_and_set_bit(int nr, volatile void * addr)
+static inline int test_and_set_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -75,21 +75,21 @@ static inline int test_and_set_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_set_bit      \n\t"
-               "mov            %0, %2                          \n\t"
-               "or             %4, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_set_bit      \n\t"
+               "mov            %0, %1                          \n\t"
+               "or             %3, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask)
+               "and            %3, %1                          \n\t"
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 
        return retval != 0;
 }
 
-static inline int test_and_clear_bit(int nr, volatile void * addr)
+static inline int test_and_clear_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -100,22 +100,22 @@ static inline int test_and_clear_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_clear_bit    \n\t"
-               "mov            %0, %2                          \n\t"
-               "and            %5, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_clear_bit    \n\t"
+               "mov            %0, %1                          \n\t"
+               "and            %4, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
+               "and            %3, %1                          \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask), "r" (~mask)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask), "r" (~mask)
                : "t", "memory"
        );
 
        return retval != 0;
 }
 
-static inline int test_and_change_bit(int nr, volatile void * addr)
+static inline int test_and_change_bit(int nr, volatile void *addr)
 {
        int     mask, retval;
        volatile unsigned int *a = addr;
@@ -126,15 +126,15 @@ static inline int test_and_change_bit(int nr, volatile void * addr)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! test_and_change_bit   \n\t"
-               "mov            %0, %2                          \n\t"
-               "xor            %4, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movli.l        @%2, %0 ! test_and_change_bit   \n\t"
+               "mov            %0, %1                          \n\t"
+               "xor            %3, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
-               "and            %4, %2                          \n\t"
+               "and            %3, %1                          \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (a), "=&r" (retval)
-               : "1" (a), "r" (mask)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (a), "r" (mask)
                : "t", "memory"
        );
 
index f9c88583d90aba3395c2a520ed05662056231269..2f6c9627bc1f81c6dcbc041ee003b47010ae8f21 100644 (file)
@@ -15,6 +15,7 @@ struct clk_ops {
        void (*disable)(struct clk *clk);
        void (*recalc)(struct clk *clk);
        int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+       int (*set_parent)(struct clk *clk, struct clk *parent);
        long (*round_rate)(struct clk *clk, unsigned long rate);
 };
 
index aee3bf2865818131a5d4700d970f080ca84a6ce0..0fac3da536ca025797385130a9972296c578276c 100644 (file)
@@ -8,14 +8,14 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
 
        __asm__ __volatile__ (
                "1:                                     \n\t"
-               "movli.l        @%1, %0 ! xchg_u32      \n\t"
-               "mov            %0, %2                  \n\t"
-               "mov            %4, %0                  \n\t"
-               "movco.l        %0, @%1                 \n\t"
+               "movli.l        @%2, %0 ! xchg_u32      \n\t"
+               "mov            %0, %1                  \n\t"
+               "mov            %3, %0                  \n\t"
+               "movco.l        %0, @%2                 \n\t"
                "bf             1b                      \n\t"
                "synco                                  \n\t"
-               : "=&z"(tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (val)
+               : "=&z"(tmp), "=&r" (retval)
+               : "r" (m), "r" (val)
                : "t", "memory"
        );
 
@@ -29,14 +29,14 @@ static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
 
        __asm__ __volatile__ (
                "1:                                     \n\t"
-               "movli.l        @%1, %0 ! xchg_u8       \n\t"
-               "mov            %0, %2                  \n\t"
-               "mov            %4, %0                  \n\t"
-               "movco.l        %0, @%1                 \n\t"
+               "movli.l        @%2, %0 ! xchg_u8       \n\t"
+               "mov            %0, %1                  \n\t"
+               "mov            %3, %0                  \n\t"
+               "movco.l        %0, @%2                 \n\t"
                "bf             1b                      \n\t"
                "synco                                  \n\t"
-               : "=&z"(tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (val & 0xff)
+               : "=&z"(tmp), "=&r" (retval)
+               : "r" (m), "r" (val & 0xff)
                : "t", "memory"
        );
 
@@ -51,17 +51,17 @@ __cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new)
 
        __asm__ __volatile__ (
                "1:                                             \n\t"
-               "movli.l        @%1, %0 ! __cmpxchg_u32         \n\t"
-               "mov            %0, %2                          \n\t"
-               "cmp/eq         %2, %4                          \n\t"
+               "movli.l        @%2, %0 ! __cmpxchg_u32         \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/eq         %1, %3                          \n\t"
                "bf             2f                              \n\t"
-               "mov            %5, %0                          \n\t"
+               "mov            %3, %0                          \n\t"
                "2:                                             \n\t"
-               "movco.l        %0, @%1                         \n\t"
+               "movco.l        %0, @%2                         \n\t"
                "bf             1b                              \n\t"
                "synco                                          \n\t"
-               : "=&z" (tmp), "=r" (m), "=&r" (retval)
-               : "1" (m), "r" (old), "r" (new)
+               : "=&z" (tmp), "=&r" (retval)
+               : "r" (m), "r" (old), "r" (new)
                : "t", "memory"
        );
 
index 86308aa3973180867a7b30a2f95e43f6137e54c2..694abe490edb73edb280654b2ad8eec9a21d0ed6 100644 (file)
@@ -21,5 +21,6 @@
 #define CPU_HAS_LLSC           0x0040  /* movli.l/movco.l */
 #define CPU_HAS_L2_CACHE       0x0080  /* Secondary cache / URAM */
 #define CPU_HAS_OP32           0x0100  /* 32-bit instruction support */
+#define CPU_HAS_PTEAEX         0x0200  /* PTE ASID Extension support */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h
new file mode 100644 (file)
index 0000000..0c8f8e1
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * arch/sh/include/asm/dma-sh.h
+ *
+ * Copyright (C) 2000  Takashi YOSHII
+ * Copyright (C) 2003  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __DMA_SH_H
+#define __DMA_SH_H
+
+#include <asm/dma.h>
+#include <cpu/dma.h>
+
+/* DMAOR contorl: The DMAOR access size is different by CPU.*/
+#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define dmaor_read_reg(n) \
+    (n ? ctrl_inw(SH_DMAC_BASE1 + DMAOR) \
+       : ctrl_inw(SH_DMAC_BASE0 + DMAOR))
+#define dmaor_write_reg(n, data) \
+    (n ? ctrl_outw(data, SH_DMAC_BASE1 + DMAOR) \
+    : ctrl_outw(data, SH_DMAC_BASE0 + DMAOR))
+#else /* Other CPU */
+#define dmaor_read_reg(n) ctrl_inw(SH_DMAC_BASE0 + DMAOR)
+#define dmaor_write_reg(n, data) ctrl_outw(data, SH_DMAC_BASE0 + DMAOR)
+#endif
+
+static int dmte_irq_map[] __maybe_unused = {
+#if (MAX_DMA_CHANNELS >= 4)
+    DMTE0_IRQ,
+    DMTE0_IRQ + 1,
+    DMTE0_IRQ + 2,
+    DMTE0_IRQ + 3,
+#endif
+#if (MAX_DMA_CHANNELS >= 6)
+    DMTE4_IRQ,
+    DMTE4_IRQ + 1,
+#endif
+#if (MAX_DMA_CHANNELS >= 8)
+    DMTE6_IRQ,
+    DMTE6_IRQ + 1,
+#endif
+#if (MAX_DMA_CHANNELS >= 12)
+    DMTE8_IRQ,
+    DMTE9_IRQ,
+    DMTE10_IRQ,
+    DMTE11_IRQ,
+#endif
+};
+
+/* Definitions for the SuperH DMAC */
+#define REQ_L  0x00000000
+#define REQ_E  0x00080000
+#define RACK_H 0x00000000
+#define RACK_L 0x00040000
+#define ACK_R  0x00000000
+#define ACK_W  0x00020000
+#define ACK_H  0x00000000
+#define ACK_L  0x00010000
+#define DM_INC 0x00004000
+#define DM_DEC 0x00008000
+#define SM_INC 0x00001000
+#define SM_DEC 0x00002000
+#define RS_IN  0x00000200
+#define RS_OUT 0x00000300
+#define TS_BLK 0x00000040
+#define TM_BUR 0x00000020
+#define CHCR_DE 0x00000001
+#define CHCR_TE 0x00000002
+#define CHCR_IE 0x00000004
+
+/* DMAOR definitions */
+#define DMAOR_AE       0x00000004
+#define DMAOR_NMIF     0x00000002
+#define DMAOR_DME      0x00000001
+
+/*
+ * Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL        (DM_INC | SM_INC | 0x400 | TS_32)
+
+/* DMA base address */
+static u32 dma_base_addr[] __maybe_unused = {
+#if (MAX_DMA_CHANNELS >= 4)
+       SH_DMAC_BASE0 + 0x00,   /* channel 0 */
+       SH_DMAC_BASE0 + 0x10,
+       SH_DMAC_BASE0 + 0x20,
+       SH_DMAC_BASE0 + 0x30,
+#endif
+#if (MAX_DMA_CHANNELS >= 6)
+       SH_DMAC_BASE0 + 0x50,
+       SH_DMAC_BASE0 + 0x60,
+#endif
+#if (MAX_DMA_CHANNELS >= 8)
+       SH_DMAC_BASE1 + 0x00,
+       SH_DMAC_BASE1 + 0x10,
+#endif
+#if (MAX_DMA_CHANNELS >= 12)
+       SH_DMAC_BASE1 + 0x20,
+       SH_DMAC_BASE1 + 0x30,
+       SH_DMAC_BASE1 + 0x50,
+       SH_DMAC_BASE1 + 0x60, /* channel 11 */
+#endif
+};
+
+/* DMA register */
+#define SAR     0x00
+#define DAR     0x04
+#define TCR     0x08
+#define CHCR    0x0C
+#define DMAOR  0x40
+
+#endif /* __DMA_SH_H */
index beca7128e2ab8f2a5177d9ea76c975433b864111..6bd17847387849008d62bcd6316a8ad460c4aa68 100644 (file)
@@ -25,9 +25,9 @@
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET+0x10000000)
 
 #ifdef CONFIG_NR_DMA_CHANNELS
-#  define MAX_DMA_CHANNELS     (CONFIG_NR_DMA_CHANNELS)
+#  define MAX_DMA_CHANNELS   (CONFIG_NR_DMA_CHANNELS)
 #else
-#  define MAX_DMA_CHANNELS     (CONFIG_NR_ONCHIP_DMA_CHANNELS)
+#  define MAX_DMA_CHANNELS   (CONFIG_NR_ONCHIP_DMA_CHANNELS)
 #endif
 
 /*
index 2dab0b8d9454f8d8b67afa46016b2924b6b9b28f..3a4752a657220e10729a00fbdb3507b3aa7df1b8 100644 (file)
@@ -31,3 +31,8 @@
 #endif 
        .endm
 
+#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
+# define PREF(x)       pref    @x
+#else
+# define PREF(x)       nop
+#endif
index 90673658eb14c19e5506ebcda7c3024084fbd036..61f93da2c62e3dc41de14a4b05eccabf3df84f36 100644 (file)
 #include <cpu/gpio.h>
 #endif
 
+#define ARCH_NR_GPIOS 512
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       WARN_ON(1);
+       return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
 typedef unsigned short pinmux_enum_t;
-typedef unsigned char pinmux_flag_t;
+typedef unsigned short pinmux_flag_t;
 
 #define PINMUX_TYPE_NONE            0
 #define PINMUX_TYPE_FUNCTION        1
@@ -34,6 +68,11 @@ typedef unsigned char pinmux_flag_t;
 #define PINMUX_FLAG_WANT_PULLUP     (1 << 3)
 #define PINMUX_FLAG_WANT_PULLDOWN   (1 << 4)
 
+#define PINMUX_FLAG_DBIT_SHIFT      5
+#define PINMUX_FLAG_DBIT            (0x1f << PINMUX_FLAG_DBIT_SHIFT)
+#define PINMUX_FLAG_DREG_SHIFT      10
+#define PINMUX_FLAG_DREG            (0x3f << PINMUX_FLAG_DREG_SHIFT)
+
 struct pinmux_gpio {
        pinmux_enum_t enum_id;
        pinmux_flag_t flags;
@@ -54,7 +93,7 @@ struct pinmux_cfg_reg {
        .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \
 
 struct pinmux_data_reg {
-       unsigned long reg, reg_width;
+       unsigned long reg, reg_width, reg_shadow;
        pinmux_enum_t *enum_ids;
 };
 
@@ -89,34 +128,9 @@ struct pinmux_info {
        unsigned int gpio_data_size;
 
        unsigned long *gpio_in_use;
+       struct gpio_chip chip;
 };
 
 int register_pinmux(struct pinmux_info *pip);
 
-int __gpio_request(unsigned gpio);
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return __gpio_request(gpio);
-}
-void gpio_free(unsigned gpio);
-int gpio_direction_input(unsigned gpio);
-int gpio_direction_output(unsigned gpio, int value);
-int gpio_get_value(unsigned gpio);
-void gpio_set_value(unsigned gpio, int value);
-
-/* IRQ modes are unspported */
-static inline int gpio_to_irq(unsigned gpio)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-#include <asm-generic/gpio.h>
-
 #endif /* __ASM_SH_GPIO_H */
index 8c1353baf00f8e5e1676d0e5940304e3fdfa9b62..52b4b62382777a3d03ff41c62441d0102521be61 100644 (file)
 #include <asm/io_generic.h>
 
 /* arch/sh/cchips/hd6446x/hd64461/setup.c */
-int hd64461_irq_demux(int irq);
 void hd64461_register_irq_demux(int irq,
                                int (*demux) (int irq, void *dev), void *dev);
 void hd64461_unregister_irq_demux(int irq);
index 61f6dae40534831195c12972091f859ad2d14214..0454f8d6805917dabb8efb00aa4810fee4520790 100644 (file)
@@ -238,7 +238,7 @@ extern void onchip_unmap(unsigned long vaddr);
 static inline void __iomem *
 __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
 {
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
        unsigned long last_addr = offset + size - 1;
 #endif
        void __iomem *ret;
@@ -247,7 +247,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
        if (ret)
                return ret;
 
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
        /*
         * For P1 and P2 space this is trivial, as everything is already
         * mapped. Uncached access for P1 addresses are done through P2.
index 6078d8e551d4960e66c0cf7da92fc266470d717a..613644a758e8e82b54a975d17376bd63bdd63768 100644 (file)
@@ -16,7 +16,7 @@ typedef u16 kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define regs_return_value(regs)                ((regs)->regs[0])
+#define regs_return_value(_regs)               ((_regs)->regs[0])
 #define flush_insn_slot(p)             do { } while (0)
 #define kretprobe_blacklist_size       0
 
index 5d9157bd474df7b6988f512e85389b1b31da0d5a..2a9c55f1a83f9f7429104b4c2671460d7caba373 100644 (file)
  *    (a) TLB cache version (or round, cycle whatever expression you like)
  *    (b) ASID (Address Space IDentifier)
  */
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMU_CONTEXT_ASID_MASK          0x0000ffff
+#else
 #define MMU_CONTEXT_ASID_MASK          0x000000ff
-#define MMU_CONTEXT_VERSION_MASK       0xffffff00
-#define MMU_CONTEXT_FIRST_VERSION      0x00000100
-#define NO_CONTEXT                     0UL
+#endif
 
-/* ASID is 8-bit value, so it can't be 0x100 */
-#define MMU_NO_ASID                    0x100
+#define MMU_CONTEXT_VERSION_MASK       (~0UL & ~MMU_CONTEXT_ASID_MASK)
+#define MMU_CONTEXT_FIRST_VERSION      (MMU_CONTEXT_ASID_MASK + 1)
+
+/* Impossible ASID value, to differentiate from NO_CONTEXT. */
+#define MMU_NO_ASID                    MMU_CONTEXT_FIRST_VERSION
+#define NO_CONTEXT                     0UL
 
 #define asid_cache(cpu)                (cpu_data[cpu].asid_cache)
 
index f4f9aebd68b797a7df2d9005af2e6e3ad0b4d58f..8ef800c549abcfd4be2ff3e8db9325ed88762442 100644 (file)
@@ -10,6 +10,17 @@ static inline void destroy_context(struct mm_struct *mm)
        /* Do nothing */
 }
 
+#ifdef CONFIG_CPU_HAS_PTEAEX
+static inline void set_asid(unsigned long asid)
+{
+       __raw_writel(asid, MMU_PTEAEX);
+}
+
+static inline unsigned long get_asid(void)
+{
+       return __raw_readl(MMU_PTEAEX) & MMU_CONTEXT_ASID_MASK;
+}
+#else
 static inline void set_asid(unsigned long asid)
 {
        unsigned long __dummy;
@@ -33,6 +44,7 @@ static inline unsigned long get_asid(void)
        asid &= MMU_CONTEXT_ASID_MASK;
        return asid;
 }
+#endif /* CONFIG_CPU_HAS_PTEAEX */
 
 /* MMU_TTB is used for optimizing the fault handling. */
 static inline void set_TTB(pgd_t *pgd)
index 5871d78e47e529208e28a523abb30fd2e075f429..9c6d21ec0240981f3bc4da574162caebad1feac6 100644 (file)
@@ -129,7 +129,12 @@ typedef struct page *pgtable_t;
  * is not visible (it is part of the PMB mapping) and so needs to be
  * added or subtracted as required.
  */
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_PMB_FIXED)
+/* phys = virt - PAGE_OFFSET - (__MEMORY_START & 0xe0000000) */
+#define PMB_OFFSET     (PAGE_OFFSET - PXSEG(__MEMORY_START))
+#define __pa(x)        ((unsigned long)(x) - PMB_OFFSET)
+#define __va(x)        ((void *)((unsigned long)(x) + PMB_OFFSET))
+#elif defined(CONFIG_32BIT)
 #define __pa(x)        ((unsigned long)(x)-PAGE_OFFSET+__MEMORY_START)
 #define __va(x)        ((void *)((unsigned long)(x)+PAGE_OFFSET-__MEMORY_START))
 #else
index 1ef4b24d7619551306f0b0fd5a84f989149fb535..1fd58b421438e87ae141f2b798c39f7bea497294 100644 (file)
@@ -31,7 +31,7 @@ enum cpu_type {
        CPU_SH7760, CPU_SH4_202, CPU_SH4_501,
 
        /* SH-4A types */
-       CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785,
+       CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786,
        CPU_SH7723, CPU_SHX3,
 
        /* SH4AL-DSP types */
index d79063c5eb9c1ebb531425dda142c031115cfca2..efdd78a53b111f493f6f62280c1d9c19d3c6791d 100644 (file)
@@ -108,12 +108,12 @@ extern int ubc_usercnt;
 /*
  * Do necessary setup to start up a newly executed thread.
  */
-#define start_thread(regs, new_pc, new_sp)      \
+#define start_thread(_regs, new_pc, new_sp)     \
        set_fs(USER_DS);                         \
-       regs->pr = 0;                            \
-       regs->sr = SR_FD;       /* User mode. */ \
-       regs->pc = new_pc;                       \
-       regs->regs[15] = new_sp
+       _regs->pr = 0;                           \
+       _regs->sr = SR_FD;      /* User mode. */ \
+       _regs->pc = new_pc;                      \
+       _regs->regs[15] = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -189,10 +189,9 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
 
-#define user_stack_pointer(regs)       ((regs)->regs[15])
+#define user_stack_pointer(_regs)      ((_regs)->regs[15])
 
-#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
-    defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
 #define PREFETCH_STRIDE                L1_CACHE_BYTES
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
index 803177fcf0868b1e5f3a84462a6d3fe514f101c8..5727d31b0ccfd89f6e80c5f610b36bd5f48c0dc5 100644 (file)
@@ -145,13 +145,13 @@ struct thread_struct {
  */
 #define SR_USER (SR_MMU | SR_FD)
 
-#define start_thread(regs, new_pc, new_sp)                     \
+#define start_thread(_regs, new_pc, new_sp)                    \
        set_fs(USER_DS);                                        \
-       regs->sr = SR_USER;     /* User mode. */                \
-       regs->pc = new_pc - 4;  /* Compensate syscall exit */   \
-       regs->pc |= 1;          /* Set SHmedia ! */             \
-       regs->regs[18] = 0;                                     \
-       regs->regs[15] = new_sp
+       _regs->sr = SR_USER;    /* User mode. */                \
+       _regs->pc = new_pc - 4; /* Compensate syscall exit */   \
+       _regs->pc |= 1;         /* Set SHmedia ! */             \
+       _regs->regs[18] = 0;                                    \
+       _regs->regs[15] = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -226,7 +226,7 @@ extern unsigned long get_wchan(struct task_struct *p);
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
 
-#define user_stack_pointer(regs)       ((regs)->regs[15])
+#define user_stack_pointer(_regs)      ((_regs)->regs[15])
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SH_PROCESSOR_64_H */
index 12912ab80c15be73c0d21b7e76df1e166183e09c..81c6568fdb3ed5ede3287f8f26dee1b21b9848f6 100644 (file)
@@ -122,14 +122,12 @@ extern void user_disable_single_step(struct task_struct *);
 #ifdef CONFIG_SH_DSP
 #define task_pt_regs(task) \
        ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
-                - sizeof(struct pt_dspregs) - sizeof(unsigned long)) - 1)
+                - sizeof(struct pt_dspregs)) - 1)
 #define task_pt_dspregs(task) \
-       ((struct pt_dspregs *) (task_stack_page(task) + THREAD_SIZE \
-                - sizeof(unsigned long)) - 1)
+       ((struct pt_dspregs *) (task_stack_page(task) + THREAD_SIZE) - 1)
 #else
 #define task_pt_regs(task) \
-       ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
-                - sizeof(unsigned long)) - 1)
+       ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
 #endif
 
 static inline unsigned long profile_pc(struct pt_regs *regs)
index 8f8f4ad400dfd5a5b6d05d592abd96258810a3be..01a4076a3719b5d42661157836e5dde18943ba02 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <asm-generic/sections.h>
 
+extern void __nosave_begin, __nosave_end;
 extern long __machvec_start, __machvec_end;
 extern char __uncached_start, __uncached_end;
 extern char _ebss[];
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
new file mode 100644 (file)
index 0000000..b1b9953
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _ASM_SH_SUSPEND_H
+#define _ASM_SH_SUSPEND_H
+
+#ifndef __ASSEMBLY__
+static inline int arch_prepare_suspend(void) { return 0; }
+
+#include <asm/ptrace.h>
+
+struct swsusp_arch_regs {
+       struct pt_regs user_regs;
+       unsigned long bank1_regs[8];
+};
+#endif
+
+/* flags passed to assembly suspend code */
+#define SUSP_SH_SLEEP          (1 << 0) /* Regular sleep mode */
+#define SUSP_SH_STANDBY                (1 << 1) /* SH-Mobile Software standby mode */
+#define SUSP_SH_RSTANDBY       (1 << 2) /* SH-Mobile R-standby mode */
+#define SUSP_SH_USTANDBY       (1 << 3) /* SH-Mobile U-standby mode */
+#define SUSP_SH_SF             (1 << 4) /* Enable self-refresh */
+
+#endif /* _ASM_SH_SUSPEND_H */
index a7ca3a195bb589609e1d0eac2c4709f2251b46a4..4c3b66e30af23fccb48b2392b54ae5cbb581827c 100644 (file)
@@ -9,7 +9,6 @@ struct sys_timer_ops {
        int (*init)(void);
        int (*start)(void);
        int (*stop)(void);
-       cycle_t (*read)(void);
 #ifndef CONFIG_GENERIC_TIME
        unsigned long (*get_offset)(void);
 #endif
@@ -39,6 +38,7 @@ struct sys_timer *get_sys_timer(void);
 
 /* arch/sh/kernel/time.c */
 void handle_timer_tick(void);
-extern unsigned long sh_hpt_frequency;
+
+extern struct clocksource clocksource_sh;
 
 #endif /* __ASM_SH_TIMER_H */
index 88ff1ae8a6b872bd0c2043692938e95e47fd37d7..9c16f737074afb62b552170227fdf4571c66912d 100644 (file)
 #endif
 
 #ifndef __ASSEMBLY__
+#include <linux/pagemap.h>
+
+#ifdef CONFIG_MMU
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+/*
+ * TLB handling.  This allows us to remove pages from the page
+ * tables, and efficiently handle the TLB issues.
+ */
+struct mmu_gather {
+       struct mm_struct        *mm;
+       unsigned int            fullmm;
+       unsigned long           start, end;
+};
 
-#define tlb_start_vma(tlb, vma) \
-       flush_cache_range(vma, vma->vm_start, vma->vm_end)
+DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-#define tlb_end_vma(tlb, vma)  \
-       flush_tlb_range(vma, vma->vm_start, vma->vm_end)
+static inline void init_tlb_gather(struct mmu_gather *tlb)
+{
+       tlb->start = TASK_SIZE;
+       tlb->end = 0;
 
-#define __tlb_remove_tlb_entry(tlb, pte, address)      do { } while (0)
+       if (tlb->fullmm) {
+               tlb->start = 0;
+               tlb->end = TASK_SIZE;
+       }
+}
+
+static inline struct mmu_gather *
+tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+{
+       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+
+       tlb->mm = mm;
+       tlb->fullmm = full_mm_flush;
+
+       init_tlb_gather(tlb);
+
+       return tlb;
+}
+
+static inline void
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+       if (tlb->fullmm)
+               flush_tlb_mm(tlb->mm);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+
+       put_cpu_var(mmu_gathers);
+}
+
+static inline void
+tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long address)
+{
+       if (tlb->start > address)
+               tlb->start = address;
+       if (tlb->end < address + PAGE_SIZE)
+               tlb->end = address + PAGE_SIZE;
+}
 
 /*
- * Flush whole TLBs for MM
+ * In the case of tlb vma handling, we can optimise these away in the
+ * case where we're doing a full MM flush.  When we're doing a munmap,
+ * the vmas are adjusted to only cover the region to be torn down.
  */
-#define tlb_flush(tlb)                         flush_tlb_mm((tlb)->mm)
+static inline void
+tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+       if (!tlb->fullmm)
+               flush_cache_range(vma, vma->vm_start, vma->vm_end);
+}
+
+static inline void
+tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+       if (!tlb->fullmm && tlb->end) {
+               flush_tlb_range(vma, tlb->start, tlb->end);
+               init_tlb_gather(tlb);
+       }
+}
+
+#define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
+#define pte_free_tlb(tlb, ptep)                pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp)                pmd_free((tlb)->mm, pmdp)
+#define pud_free_tlb(tlb, pudp)                pud_free((tlb)->mm, pudp)
+
+#define tlb_migrate_finish(mm)         do { } while (0)
+
+#else /* CONFIG_MMU */
+
+#define tlb_start_vma(tlb, vma)                                do { } while (0)
+#define tlb_end_vma(tlb, vma)                          do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, pte, address)      do { } while (0)
+#define tlb_flush(tlb)                                 do { } while (0)
 
-#include <linux/pagemap.h>
 #include <asm-generic/tlb.h>
 
+#endif /* CONFIG_MMU */
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SH_TLB_H */
index 6813c3220a1d7a6693d2481d7dccda4cd7b3e76b..0ea15f3f236346a625a65d10e02b0eac4ef49880 100644 (file)
@@ -1,22 +1,17 @@
 #ifndef __ASM_CPU_SH3_DMA_H
 #define __ASM_CPU_SH3_DMA_H
 
-
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721)
-#define SH_DMAC_BASE   0xa4010020
-#else
-#define SH_DMAC_BASE   0xa4000020
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SH_DMAC_BASE0  0xa4010020
+#else /* SH7705/06/07/09 */
+#define SH_DMAC_BASE0  0xa4000020
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7709)
 #define DMTE0_IRQ      48
-#define DMTE1_IRQ      49
-#define DMTE2_IRQ      50
-#define DMTE3_IRQ      51
 #define DMTE4_IRQ      76
-#define DMTE5_IRQ      77
-#endif
 
 /* Definitions for the SuperH DMAC */
 #define TM_BURST       0x00000020
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
new file mode 100644 (file)
index 0000000..0ed5178
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
+#define __ASM_SH_CPU_SH4_DMA_SH7780_H
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7722) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7730)
+#define DMTE0_IRQ      48
+#define DMTE4_IRQ      76
+#define DMAE0_IRQ      78      /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#define SH_DMARS_BASE  0xFE009000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7764)
+#define DMTE0_IRQ      34
+#define DMTE4_IRQ      44
+#define DMAE0_IRQ      38
+#define SH_DMAC_BASE0  0xFF608020
+#define SH_DMARS_BASE  0xFF609000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#define DMTE0_IRQ      48      /* DMAC0A*/
+#define DMTE4_IRQ      40      /* DMAC0B */
+#define DMTE6_IRQ      42
+#define DMTE8_IRQ      76      /* DMAC1A */
+#define DMTE9_IRQ      77
+#define DMTE10_IRQ     72      /* DMAC1B */
+#define DMTE11_IRQ     73
+#define DMAE0_IRQ      78      /* DMA Error IRQ*/
+#define DMAE1_IRQ      74      /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#define SH_DMAC_BASE1  0xFDC08020
+#define SH_DMARS_BASE  0xFDC09000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#define DMTE0_IRQ      34
+#define DMTE4_IRQ      44
+#define DMTE6_IRQ      46
+#define DMTE8_IRQ      92
+#define DMTE9_IRQ      93
+#define DMTE10_IRQ     94
+#define DMTE11_IRQ     95
+#define DMAE0_IRQ      38      /* DMA Error IRQ */
+#define SH_DMAC_BASE0  0xFC808020
+#define SH_DMAC_BASE1  0xFC818020
+#define SH_DMARS_BASE  0xFC809000
+#else /* SH7785 */
+#define DMTE0_IRQ      33
+#define DMTE4_IRQ      37
+#define DMTE6_IRQ      52
+#define DMTE8_IRQ      54
+#define DMTE9_IRQ      55
+#define DMTE10_IRQ     56
+#define DMTE11_IRQ     57
+#define DMAE0_IRQ      39      /* DMA Error IRQ0 */
+#define DMAE1_IRQ      58      /* DMA Error IRQ1 */
+#define SH_DMAC_BASE0  0xFC808020
+#define SH_DMAC_BASE1  0xFCC08020
+#define SH_DMARS_BASE  0xFC809000
+#endif
+
+#define REQ_HE 0x000000C0
+#define REQ_H  0x00000080
+#define REQ_LE 0x00000040
+#define TM_BURST 0x0000020
+#define TS_8   0x00000000
+#define TS_16  0x00000008
+#define TS_32  0x00000010
+#define TS_16BLK       0x00000018
+#define TS_32BLK       0x00100000
+
+/*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+ *
+ * Defaults to a 64-bit transfer size.
+ */
+enum {
+       XMIT_SZ_8BIT,
+       XMIT_SZ_16BIT,
+       XMIT_SZ_32BIT,
+       XMIT_SZ_128BIT,
+       XMIT_SZ_256BIT,
+};
+
+/*
+ * The DMA count is defined as the number of bytes to transfer.
+ */
+static unsigned int ts_shift[] __maybe_unused = {
+       [XMIT_SZ_8BIT]          = 0,
+       [XMIT_SZ_16BIT]         = 1,
+       [XMIT_SZ_32BIT]         = 2,
+       [XMIT_SZ_128BIT]        = 4,
+       [XMIT_SZ_256BIT]        = 5,
+};
+
+#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh7780.h b/arch/sh/include/cpu-sh4/cpu/dma-sh7780.h
deleted file mode 100644 (file)
index 71b426a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
-#define __ASM_SH_CPU_SH4_DMA_SH7780_H
-
-#define REQ_HE 0x000000C0
-#define REQ_H  0x00000080
-#define REQ_LE 0x00000040
-#define TM_BURST 0x0000020
-#define TS_8   0x00000000
-#define TS_16  0x00000008
-#define TS_32  0x00000010
-#define TS_16BLK       0x00000018
-#define TS_32BLK       0x00100000
-
-/*
- * The SuperH DMAC supports a number of transmit sizes, we list them here,
- * with their respective values as they appear in the CHCR registers.
- *
- * Defaults to a 64-bit transfer size.
- */
-enum {
-       XMIT_SZ_8BIT,
-       XMIT_SZ_16BIT,
-       XMIT_SZ_32BIT,
-       XMIT_SZ_128BIT,
-       XMIT_SZ_256BIT,
-};
-
-/*
- * The DMA count is defined as the number of bytes to transfer.
- */
-static unsigned int ts_shift[] __maybe_unused = {
-       [XMIT_SZ_8BIT]          = 0,
-       [XMIT_SZ_16BIT]         = 1,
-       [XMIT_SZ_32BIT]         = 2,
-       [XMIT_SZ_128BIT]        = 4,
-       [XMIT_SZ_256BIT]        = 5,
-};
-
-#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
index 235b7cd1fc9a72eb7757d2f977ff0e06aa122fb5..bcb30246e85c9fce6c85593736884eac76242bcf 100644 (file)
@@ -1,31 +1,29 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
-#define DMAOR_INIT     ( 0x8000 | DMAOR_DME )
-
 /* SH7751/7760/7780 DMA IRQ sources */
-#define DMTE0_IRQ      34
-#define DMTE1_IRQ      35
-#define DMTE2_IRQ      36
-#define DMTE3_IRQ      37
-#define DMTE4_IRQ      44
-#define DMTE5_IRQ      45
-#define DMTE6_IRQ      46
-#define DMTE7_IRQ      47
-#define DMAE_IRQ       38
 
 #ifdef CONFIG_CPU_SH4A
-#define SH_DMAC_BASE   0xfc808020
 
+#define DMAOR_INIT     (DMAOR_DME)
 #define CHCR_TS_MASK   0x18
 #define CHCR_TS_SHIFT  3
 
-#include <cpu/dma-sh7780.h>
-#else
-#define SH_DMAC_BASE   0xffa00000
+#include <cpu/dma-sh4a.h>
+#else /* CONFIG_CPU_SH4A */
+/*
+ * SH7750/SH7751/SH7760
+ */
+#define DMTE0_IRQ      34
+#define DMTE4_IRQ      44
+#define DMTE6_IRQ      46
+#define DMAE0_IRQ      38
 
+#define DMAOR_INIT     (0x8000|DMAOR_DME)
+#define SH_DMAC_BASE0  0xffa00000
+#define SH_DMAC_BASE1  0xffa00070
 /* Definitions for the SuperH DMAC */
-#define TM_BURST       0x0000080
+#define TM_BURST       0x00000080
 #define TS_8           0x00000010
 #define TS_16          0x00000020
 #define TS_32          0x00000030
index c23af81c2e701805a0656b84ec459181f2c5b8ca..749d1c43433754beebd7fad01d930dd72266e016 100644 (file)
 #define FRQCR0                 0xffc80000
 #define FRQCR1                 0xffc80004
 #define FRQMR1                 0xffc80014
+#elif defined(CONFIG_CPU_SUBTYPE_SH7786)
+#define FRQCR0                 0xffc40000
+#define FRQCR1                 0xffc40004
+#define FRQMR1                 0xffc40014
 #elif defined(CONFIG_CPU_SUBTYPE_SHX3)
 #define FRQCR                  0xffc00014
 #else
index 9ea8eb27b18e20dd69d43ce9897a163a3851c9ed..3ce7ef6c29789ae0ff876703257f6f4b0d42d8d0 100644 (file)
 #define MMU_PTEL       0xFF000004      /* Page table entry register LOW */
 #define MMU_TTB                0xFF000008      /* Translation table base register */
 #define MMU_TEA                0xFF00000C      /* TLB Exception Address */
-#define MMU_PTEA       0xFF000034      /* Page table entry assistance register */
+#define MMU_PTEA       0xFF000034      /* PTE assistance register */
+#define MMU_PTEAEX     0xFF00007C      /* PTE ASID extension register */
 
 #define MMUCR          0xFF000010      /* MMU Control Register */
 
-#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000
 #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
+#define MMU_UTLB_ADDRESS_ARRAY2        0xF6800000
 #define MMU_PAGE_ASSOC_BIT     0x80
 
 #define MMUCR_TI               (1<<2)
 
-#ifdef CONFIG_X2TLB
-#define MMUCR_ME               (1 << 7)
-#else
-#define MMUCR_ME               (0)
-#endif
-
 #if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40)
 #define MMUCR_SE               (1 << 4)
 #else
 #define MMUCR_SE               (0)
 #endif
 
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMUCR_AEX              (1 << 6)
+#else
+#define MMUCR_AEX              (0)
+#endif
+
+#ifdef CONFIG_X2TLB
+#define MMUCR_ME               (1 << 7)
+#else
+#define MMUCR_ME               (0)
+#endif
+
 #ifdef CONFIG_SH_STORE_QUEUES
 #define MMUCR_SQMD             (1 << 9)
 #else
 #endif
 
 #define MMU_NTLB_ENTRIES       64
-#define MMU_CONTROL_INIT       (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE)
-
-#define MMU_ITLB_DATA_ARRAY    0xF3000000
-#define MMU_UTLB_DATA_ARRAY    0xF7000000
-
-#define MMU_UTLB_ENTRIES          64
-#define MMU_U_ENTRY_SHIFT          8
-#define MMU_UTLB_VALID         0x100
-#define MMU_ITLB_ENTRIES           4
-#define MMU_I_ENTRY_SHIFT          8
-#define MMU_ITLB_VALID         0x100
+#define MMU_CONTROL_INIT       (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE|MMUCR_AEX)
 
 #define TRA    0xff000020
 #define EXPEVT 0xff000024
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7786.h b/arch/sh/include/cpu-sh4/cpu/sh7786.h
new file mode 100644 (file)
index 0000000..48688ad
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * SH7786 Pinmux
+ *
+ * Copyright (C) 2008, 2009  Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ *  Based on sh7785.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __CPU_SH7786_H__
+#define __CPU_SH7786_H__
+
+enum {
+       /* PA */
+       GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
+       GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+       /* PB */
+       GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+       GPIO_PB3, GPIO_PB2, GPIO_PB1, GPIO_PB0,
+
+       /* PC */
+       GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+       GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+       /* PD */
+       GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+       GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+       /* PE */
+       GPIO_PE5, GPIO_PE4, GPIO_PE3, GPIO_PE2,
+       GPIO_PE1, GPIO_PE0,
+
+       /* PF */
+       GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+       GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+       /* PG */
+       GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+       GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+       /* PH */
+       GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+       GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+       /* PJ */
+       GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+       GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+       GPIO_FN_CDE,
+       GPIO_FN_ETH_MAGIC,
+       GPIO_FN_DISP,
+       GPIO_FN_ETH_LINK,
+       GPIO_FN_DR5,
+       GPIO_FN_ETH_TX_ER,
+       GPIO_FN_DR4,
+       GPIO_FN_ETH_TX_EN,
+       GPIO_FN_DR3,
+       GPIO_FN_ETH_TXD3,
+       GPIO_FN_DR2,
+       GPIO_FN_ETH_TXD2,
+       GPIO_FN_DR1,
+       GPIO_FN_ETH_TXD1,
+       GPIO_FN_DR0,
+       GPIO_FN_ETH_TXD0,
+       GPIO_FN_VSYNC,
+       GPIO_FN_HSPI_CLK,
+       GPIO_FN_ODDF,
+       GPIO_FN_HSPI_CS,
+       GPIO_FN_DG5,
+       GPIO_FN_ETH_MDIO,
+       GPIO_FN_DG4,
+       GPIO_FN_ETH_RX_CLK,
+       GPIO_FN_DG3,
+       GPIO_FN_ETH_MDC,
+       GPIO_FN_DG2,
+       GPIO_FN_ETH_COL,
+       GPIO_FN_DG1,
+       GPIO_FN_ETH_TX_CLK,
+       GPIO_FN_DG0,
+       GPIO_FN_ETH_CRS,
+       GPIO_FN_DCLKIN,
+       GPIO_FN_HSPI_RX,
+       GPIO_FN_HSYNC,
+       GPIO_FN_HSPI_TX,
+       GPIO_FN_DB5,
+       GPIO_FN_ETH_RXD3,
+       GPIO_FN_DB4,
+       GPIO_FN_ETH_RXD2,
+       GPIO_FN_DB3,
+       GPIO_FN_ETH_RXD1,
+       GPIO_FN_DB2,
+       GPIO_FN_ETH_RXD0,
+       GPIO_FN_DB1,
+       GPIO_FN_ETH_RX_DV,
+       GPIO_FN_DB0,
+       GPIO_FN_ETH_RX_ER,
+       GPIO_FN_DCLKOUT,
+       GPIO_FN_SCIF1_SLK,
+       GPIO_FN_SCIF1_RXD,
+       GPIO_FN_SCIF1_TXD,
+       GPIO_FN_DACK1,
+       GPIO_FN_BACK,
+       GPIO_FN_FALE,
+       GPIO_FN_DACK0,
+       GPIO_FN_FCLE,
+       GPIO_FN_DREQ1,
+       GPIO_FN_BREQ,
+       GPIO_FN_USB_OVC1,
+       GPIO_FN_DREQ0,
+       GPIO_FN_USB_OVC0,
+       GPIO_FN_USB_PENC1,
+       GPIO_FN_USB_PENC0,
+       GPIO_FN_HAC1_SDOUT,
+       GPIO_FN_SSI1_SDATA,
+       GPIO_FN_SDIF1CMD,
+       GPIO_FN_HAC1_SDIN,
+       GPIO_FN_SSI1_SCK,
+       GPIO_FN_SDIF1CD,
+       GPIO_FN_HAC1_SYNC,
+       GPIO_FN_SSI1_WS,
+       GPIO_FN_SDIF1WP,
+       GPIO_FN_HAC1_BITCLK,
+       GPIO_FN_SSI1_CLK,
+       GPIO_FN_SDIF1CLK,
+       GPIO_FN_HAC0_SDOUT,
+       GPIO_FN_SSI0_SDATA,
+       GPIO_FN_SDIF1D3,
+       GPIO_FN_HAC0_SDIN,
+       GPIO_FN_SSI0_SCK,
+       GPIO_FN_SDIF1D2,
+       GPIO_FN_HAC0_SYNC,
+       GPIO_FN_SSI0_WS,
+       GPIO_FN_SDIF1D1,
+       GPIO_FN_HAC0_BITCLK,
+       GPIO_FN_SSI0_CLK,
+       GPIO_FN_SDIF1D0,
+       GPIO_FN_SCIF3_SCK,
+       GPIO_FN_SSI2_SDATA,
+       GPIO_FN_SCIF3_RXD,
+       GPIO_FN_TCLK,
+       GPIO_FN_SSI2_SCK,
+       GPIO_FN_SCIF3_TXD,
+       GPIO_FN_HAC_RES,
+       GPIO_FN_SSI2_WS,
+       GPIO_FN_DACK3,
+       GPIO_FN_SDIF0CMD,
+       GPIO_FN_DACK2,
+       GPIO_FN_SDIF0CD,
+       GPIO_FN_DREQ3,
+       GPIO_FN_SDIF0WP,
+       GPIO_FN_SCIF0_CTS,
+       GPIO_FN_DREQ2,
+       GPIO_FN_SDIF0CLK,
+       GPIO_FN_SCIF0_RTS,
+       GPIO_FN_IRL7,
+       GPIO_FN_SDIF0D3,
+       GPIO_FN_SCIF0_SCK,
+       GPIO_FN_IRL6,
+       GPIO_FN_SDIF0D2,
+       GPIO_FN_SCIF0_RXD,
+       GPIO_FN_IRL5,
+       GPIO_FN_SDIF0D1,
+       GPIO_FN_SCIF0_TXD,
+       GPIO_FN_IRL4,
+       GPIO_FN_SDIF0D0,
+       GPIO_FN_SCIF5_SCK,
+       GPIO_FN_FRB,
+       GPIO_FN_SCIF5_RXD,
+       GPIO_FN_IOIS16,
+       GPIO_FN_SCIF5_TXD,
+       GPIO_FN_CE2B,
+       GPIO_FN_DRAK3,
+       GPIO_FN_CE2A,
+       GPIO_FN_SCIF4_SCK,
+       GPIO_FN_DRAK2,
+       GPIO_FN_SSI3_WS,
+       GPIO_FN_SCIF4_RXD,
+       GPIO_FN_DRAK1,
+       GPIO_FN_SSI3_SDATA,
+       GPIO_FN_FSTATUS,
+       GPIO_FN_SCIF4_TXD,
+       GPIO_FN_DRAK0,
+       GPIO_FN_SSI3_SCK,
+       GPIO_FN_FSE,
+};
+
+#endif /* __CPU_SH7786_H__ */
diff --git a/arch/sh/include/mach-common/mach/urquell.h b/arch/sh/include/mach-common/mach/urquell.h
new file mode 100644 (file)
index 0000000..14b3e1d
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __MACH_URQUELL_H
+#define __MACH_URQUELL_H
+
+/*
+ * ------ 0x00000000 ------------------------------------
+ *  CS0 | (SW1,SW47)    EEPROM, SRAM, NOR FLASH
+ * -----+ 0x04000000 ------------------------------------
+ *  CS1 | (SW47)        SRAM, SRAM-LAN-PCMCIA, NOR FLASH
+ * -----+ 0x08000000 ------------------------------------
+ *  CS2 |               DDR3
+ *  CS3 |
+ * -----+ 0x10000000 ------------------------------------
+ *  CS4 |               PCIe
+ * -----+ 0x14000000 ------------------------------------
+ *  CS5 | (SW47)        LRAM/URAM, SRAM-LAN-PCMCIA
+ * -----+ 0x18000000 ------------------------------------
+ *  CS6 |               ATA, NAND FLASH
+ * -----+ 0x1c000000 ------------------------------------
+ *  CS7 |               SH7786 register
+ * -----+------------------------------------------------
+ */
+
+#define NOR_FLASH_ADDR 0x00000000
+#define NOR_FLASH_SIZE 0x04000000
+
+#define CS1_BASE       0x05000000
+#define CS5_BASE       0x15000000
+#define FPGA_BASE      CS1_BASE
+
+#define BOARDREG(ofs)  (FPGA_BASE + ofs##_OFS)
+#define UBOARDREG(ofs) (0xa0000000 + FPGA_BASE + ofs##_OFS)
+
+#define SRSTR_OFS      0x0000 /* System reset register */
+#define BDMR_OFS       0x0010 /* Board operating mode resister */
+#define IRL0SR_OFS     0x0020 /* IRL0 Status register */
+#define IRL0MSKR_OFS   0x0030 /* IRL0 Mask register */
+#define IRL1SR_OFS     0x0040 /* IRL1 Status register */
+#define IRL1MSKR_OFS   0x0050 /* IRL1 Mask register */
+#define IRL2SR_OFS     0x0060 /* IRL2 Status register */
+#define IRL2MSKR_OFS   0x0070 /* IRL2 Mask register */
+#define IRL3SR_OFS     0x0080 /* IRL3 Status register */
+#define IRL3MSKR_OFS   0x0090 /* IRL3 Mask register */
+#define SOFTINTR_OFS   0x0120 /* Softwear Interrupt register */
+#define SLEDR_OFS      0x0130 /* LED control resister */
+#define MAPSCIFSWR_OFS 0x0140 /* Map/SCIF Switch register */
+#define FPVERR_OFS     0x0150 /* FPGA Version register */
+#define FPDATER_OFS    0x0160 /* FPGA Date register */
+#define FPYEARR_OFS    0x0170 /* FPGA Year register */
+#define TCLKCR_OFS     0x0180 /* TCLK Control register */
+#define DIPSWMR_OFS    0x1000 /* DIPSW monitor register */
+#define FPODR_OFS      0x1010 /* Output port data register */
+#define ATACNR_OFS     0x1020 /* ATA-CN Control/status register */
+#define FPINDR_OFS     0x1030 /* Input port data register */
+#define MDSWMR_OFS     0x1040 /* MODE SW monitor register */
+#define DDR3BUPCR_OFS  0x1050 /* DDR3 Backup control register */
+#define SSICODECCR_OFS 0x1060 /* SSI-CODEC control register */
+#define PCIESLOTSR_OFS 0x1070 /* PCIexpress Slot status register */
+#define ETHERPORTSR_OFS        0x1080 /* EtherPhy Port status register */
+#define LATCHCR_OFS    0x3000 /* Latch control register */
+#define LATCUAR_OFS    0x3010 /* Latch upper address register */
+#define LATCLAR_OFS    0x3012 /* Latch lower address register */
+#define LATCLUDR_OFS   0x3024 /* Latch D31-16 register */
+#define LATCLLDR_OFS   0x3026 /* Latch D15-0 register */
+
+#define CHARLED_OFS    0x2000 /* Character LED */
+
+#endif  /* __MACH_URQUELL_H */
+
index 2e1b86e16ab54184d5d99a720e1b76e8c88adadb..82a3a150c00da2505add91e5cfb37d43b82bc597 100644 (file)
@@ -30,5 +30,6 @@ obj-$(CONFIG_KPROBES)         += kprobes.o
 obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
 obj-$(CONFIG_DUMP_CODE)                += disassemble.o
+obj-$(CONFIG_HIBERNATION)      += swsusp.o
 
 EXTRA_CFLAGS += -Werror
index 57cf0e0680f36b3e4b397d16979ec2f53c36df40..99aceb28ee2475818186f6477ce17950bacc7afc 100644 (file)
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/kbuild.h>
+#include <linux/suspend.h>
 
 #include <asm/thread_info.h>
+#include <asm/suspend.h>
 
 int main(void)
 {
@@ -25,5 +27,11 @@ int main(void)
        DEFINE(TI_PRE_COUNT,    offsetof(struct thread_info, preempt_count));
        DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
 
+#ifdef CONFIG_HIBERNATION
+       DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
+       DEFINE(PBE_ORIG_ADDRESS, offsetof(struct pbe, orig_address));
+       DEFINE(PBE_NEXT, offsetof(struct pbe, next));
+       DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs));
+#endif
        return 0;
 }
index f471d242774e13c60b31f3766ebfc6ab9f7f496d..2600641a483f743ab7938f4daf9a42e58111733a 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_CPU_SH5)         = sh5/
 # Special cases for family ancestry.
 
 obj-$(CONFIG_CPU_SH4A)         += sh4a/
+obj-$(CONFIG_ARCH_SHMOBILE)    += shmobile/
 
 # Common interfaces.
 
index 7b17137536d622c3909e7ee8f6cac6ac78bb56c3..1dc896483b591169bcf1254b70e4961ed3e88337 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/kref.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -239,6 +241,35 @@ void clk_recalc_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_recalc_rate);
 
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -EINVAL;
+       struct clk *old;
+
+       if (!parent || !clk)
+               return ret;
+
+       old = clk->parent;
+       if (likely(clk->ops && clk->ops->set_parent)) {
+               unsigned long flags;
+               spin_lock_irqsave(&clock_lock, flags);
+               ret = clk->ops->set_parent(clk, parent);
+               spin_unlock_irqrestore(&clock_lock, flags);
+               clk->parent = (ret ? old : parent);
+       }
+
+       if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
+               propagate_rate(clk);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
        if (likely(clk->ops && clk->ops->round_rate)) {
@@ -329,6 +360,70 @@ static int show_clocks(char *buf, char **start, off_t off,
        return p - buf;
 }
 
+#ifdef CONFIG_PM
+static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+       static pm_message_t prev_state;
+       struct clk *clkp;
+
+       switch (state.event) {
+       case PM_EVENT_ON:
+               /* Resumeing from hibernation */
+               if (prev_state.event == PM_EVENT_FREEZE) {
+                       list_for_each_entry(clkp, &clock_list, node)
+                               if (likely(clkp->ops)) {
+                                       unsigned long rate = clkp->rate;
+
+                                       if (likely(clkp->ops->set_parent))
+                                               clkp->ops->set_parent(clkp,
+                                                       clkp->parent);
+                                       if (likely(clkp->ops->set_rate))
+                                               clkp->ops->set_rate(clkp,
+                                                       rate, NO_CHANGE);
+                                       else if (likely(clkp->ops->recalc))
+                                               clkp->ops->recalc(clkp);
+                                       }
+               }
+               break;
+       case PM_EVENT_FREEZE:
+               break;
+       case PM_EVENT_SUSPEND:
+               break;
+       }
+
+       prev_state = state;
+       return 0;
+}
+
+static int clks_sysdev_resume(struct sys_device *dev)
+{
+       return clks_sysdev_suspend(dev, PMSG_ON);
+}
+
+static struct sysdev_class clks_sysdev_class = {
+       .name = "clks",
+};
+
+static struct sysdev_driver clks_sysdev_driver = {
+       .suspend = clks_sysdev_suspend,
+       .resume = clks_sysdev_resume,
+};
+
+static struct sys_device clks_sysdev_dev = {
+       .cls = &clks_sysdev_class,
+};
+
+static int __init clk_sysdev_init(void)
+{
+       sysdev_class_register(&clks_sysdev_class);
+       sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
+       sysdev_register(&clks_sysdev_dev);
+
+       return 0;
+}
+subsys_initcall(clk_sysdev_init);
+#endif
+
 int __init clk_init(void)
 {
        int i, ret = 0;
index 56e5878e55164f69b26aa54500d72227e794a63c..0e32d8e448ca5fa5937011aeb3328d55f2a2b2fa 100644 (file)
@@ -2,6 +2,7 @@
  * SH7619 Setup
  *
  *  Copyright (C) 2006  Yoshinori Sato
+ *  Copyright (C) 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -18,15 +19,10 @@ enum {
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
        WDT, EDMAC, CMT0, CMT1,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
-       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+       SCIF0, SCIF1, SCIF2,
        HIF_HIFI, HIF_HIFBI,
        DMAC0, DMAC1, DMAC2, DMAC3,
        SIOF,
-
-       /* interrupt groups */
-       SCIF0, SCIF1, SCIF2,
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -36,24 +32,18 @@ static struct intc_vect vectors[] __initdata = {
        INTC_IRQ(IRQ6, 82), INTC_IRQ(IRQ7, 83),
        INTC_IRQ(WDT, 84), INTC_IRQ(EDMAC, 85),
        INTC_IRQ(CMT0, 86), INTC_IRQ(CMT1, 87),
-       INTC_IRQ(SCIF0_ERI, 88), INTC_IRQ(SCIF0_RXI, 89),
-       INTC_IRQ(SCIF0_BRI, 90), INTC_IRQ(SCIF0_TXI, 91),
-       INTC_IRQ(SCIF1_ERI, 92), INTC_IRQ(SCIF1_RXI, 93),
-       INTC_IRQ(SCIF1_BRI, 94), INTC_IRQ(SCIF1_TXI, 95),
-       INTC_IRQ(SCIF2_ERI, 96), INTC_IRQ(SCIF2_RXI, 97),
-       INTC_IRQ(SCIF2_BRI, 98), INTC_IRQ(SCIF2_TXI, 99),
+       INTC_IRQ(SCIF0, 88), INTC_IRQ(SCIF0, 89),
+       INTC_IRQ(SCIF0, 90), INTC_IRQ(SCIF0, 91),
+       INTC_IRQ(SCIF1, 92), INTC_IRQ(SCIF1, 93),
+       INTC_IRQ(SCIF1, 94), INTC_IRQ(SCIF1, 95),
+       INTC_IRQ(SCIF2, 96), INTC_IRQ(SCIF2, 97),
+       INTC_IRQ(SCIF2, 98), INTC_IRQ(SCIF2, 99),
        INTC_IRQ(HIF_HIFI, 100), INTC_IRQ(HIF_HIFBI, 101),
        INTC_IRQ(DMAC0, 104), INTC_IRQ(DMAC1, 105),
        INTC_IRQ(DMAC2, 106), INTC_IRQ(DMAC3, 107),
        INTC_IRQ(SIOF, 108),
 };
 
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
-       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
-};
-
 static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xf8140006, 0, 16, 4, /* IPRA */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
        { 0xf8140008, 0, 16, 4, /* IPRB */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
@@ -64,7 +54,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xf8080008, 0, 16, 4, /* IPRG */ { SIOF } },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, NULL,
                         NULL, prio_registers, NULL);
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -72,17 +62,17 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xf8400000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 88, 89, 91, 90},
+               .irqs           = { 88, 88, 88, 88 },
        }, {
                .mapbase        = 0xf8410000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 92, 93, 95, 94},
+               .irqs           = { 92, 92, 92, 92 },
        }, {
                .mapbase        = 0xf8420000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 96, 97, 99, 98},
+               .irqs           = { 96, 96, 96, 96 },
        }, {
                .flags = 0,
        }
index e611d79fac4c2d1059262a423d8db5c47ef41230..844293723cfc8239ef7453c09bdb119e71b569f0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Renesas MX-G (R8A03022BG) Setup
  *
- *  Copyright (C) 2008  Paul Mundt
+ *  Copyright (C) 2008, 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -20,23 +20,15 @@ enum {
        IRQ8, IRQ9, IRQ10, IRQ11, IRQ12, IRQ13, IRQ14, IRQ15,
 
        PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
-
        SINT8, SINT7, SINT6, SINT5, SINT4, SINT3, SINT2, SINT1,
 
-       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
-       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+       SCIF0, SCIF1,
 
-       MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
-       MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
-       MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
-       MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
-       MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
-       MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
-       MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
+       MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3, MTU2_GROUP4, MTU2_GROUP5
+       MTU2_TGI3B, MTU2_TGI3C,
 
        /* interrupt groups */
-       PINT, SCIF0, SCIF1,
-       MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3, MTU2_GROUP4, MTU2_GROUP5
+       PINT,
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -59,47 +51,36 @@ static struct intc_vect vectors[] __initdata = {
        INTC_IRQ(SINT4, 98), INTC_IRQ(SINT3, 99),
        INTC_IRQ(SINT2, 100), INTC_IRQ(SINT1, 101),
 
-       INTC_IRQ(SCIF0_RXI, 220), INTC_IRQ(SCIF0_TXI, 221),
-       INTC_IRQ(SCIF0_BRI, 222), INTC_IRQ(SCIF0_ERI, 223),
-       INTC_IRQ(SCIF1_RXI, 224), INTC_IRQ(SCIF1_TXI, 225),
-       INTC_IRQ(SCIF1_BRI, 226), INTC_IRQ(SCIF1_ERI, 227),
+       INTC_IRQ(SCIF0, 220), INTC_IRQ(SCIF0, 221),
+       INTC_IRQ(SCIF0, 222), INTC_IRQ(SCIF0, 223),
+       INTC_IRQ(SCIF1, 224), INTC_IRQ(SCIF1, 225),
+       INTC_IRQ(SCIF1, 226), INTC_IRQ(SCIF1, 227),
 
-       INTC_IRQ(MTU2_TGI0A, 228), INTC_IRQ(MTU2_TGI0B, 229),
-       INTC_IRQ(MTU2_TGI0C, 230), INTC_IRQ(MTU2_TGI0D, 231),
-       INTC_IRQ(MTU2_TCI0V, 232), INTC_IRQ(MTU2_TGI0E, 233),
+       INTC_IRQ(MTU2_GROUP1, 228), INTC_IRQ(MTU2_GROUP1, 229),
+       INTC_IRQ(MTU2_GROUP1, 230), INTC_IRQ(MTU2_GROUP1, 231),
+       INTC_IRQ(MTU2_GROUP1, 232), INTC_IRQ(MTU2_GROUP1, 233),
 
-       INTC_IRQ(MTU2_TGI0F, 234), INTC_IRQ(MTU2_TGI1A, 235),
-       INTC_IRQ(MTU2_TGI1B, 236), INTC_IRQ(MTU2_TCI1V, 237),
-       INTC_IRQ(MTU2_TCI1U, 238), INTC_IRQ(MTU2_TGI2A, 239),
+       INTC_IRQ(MTU2_GROUP2, 234), INTC_IRQ(MTU2_GROUP2, 235),
+       INTC_IRQ(MTU2_GROUP2, 236), INTC_IRQ(MTU2_GROUP2, 237),
+       INTC_IRQ(MTU2_GROUP2, 238), INTC_IRQ(MTU2_GROUP2, 239),
 
-       INTC_IRQ(MTU2_TGI2B, 240), INTC_IRQ(MTU2_TCI2V, 241),
-       INTC_IRQ(MTU2_TCI2U, 242), INTC_IRQ(MTU2_TGI3A, 243),
+       INTC_IRQ(MTU2_GROUP3, 240), INTC_IRQ(MTU2_GROUP3, 241),
+       INTC_IRQ(MTU2_GROUP3, 242), INTC_IRQ(MTU2_GROUP3, 243),
 
        INTC_IRQ(MTU2_TGI3B, 244),
        INTC_IRQ(MTU2_TGI3C, 245),
 
-       INTC_IRQ(MTU2_TGI3D, 246), INTC_IRQ(MTU2_TCI3V, 247),
-       INTC_IRQ(MTU2_TGI4A, 248), INTC_IRQ(MTU2_TGI4B, 249),
-       INTC_IRQ(MTU2_TGI4C, 250), INTC_IRQ(MTU2_TGI4D, 251),
+       INTC_IRQ(MTU2_GROUP4, 246), INTC_IRQ(MTU2_GROUP4, 247),
+       INTC_IRQ(MTU2_GROUP4, 248), INTC_IRQ(MTU2_GROUP4, 249),
+       INTC_IRQ(MTU2_GROUP4, 250), INTC_IRQ(MTU2_GROUP4, 251),
 
-       INTC_IRQ(MTU2_TCI4V, 252), INTC_IRQ(MTU2_TGI5U, 253),
-       INTC_IRQ(MTU2_TGI5V, 254), INTC_IRQ(MTU2_TGI5W, 255),
+       INTC_IRQ(MTU2_GROUP5, 252), INTC_IRQ(MTU2_GROUP5, 253),
+       INTC_IRQ(MTU2_GROUP5, 254), INTC_IRQ(MTU2_GROUP5, 255),
 };
 
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
                   PINT4, PINT5, PINT6, PINT7),
-       INTC_GROUP(MTU2_GROUP1, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
-                  MTU2_TCI0V, MTU2_TGI0E),
-       INTC_GROUP(MTU2_GROUP2, MTU2_TGI0F, MTU2_TGI1A, MTU2_TGI1B,
-                  MTU2_TCI1V, MTU2_TCI1U, MTU2_TGI2A),
-       INTC_GROUP(MTU2_GROUP3, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
-                  MTU2_TGI3A),
-       INTC_GROUP(MTU2_GROUP4, MTU2_TGI3D, MTU2_TCI3V, MTU2_TGI4A,
-                  MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
-       INTC_GROUP(MTU2_GROUP5, MTU2_TCI4V, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
-       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -137,7 +118,7 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xff804000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 223, 220, 221, 222 },
+               .irqs           = { 220, 220, 220, 220 },
        }, {
                .flags = 0,
        }
index 0631e421c022710e6964eca336a98869c7bef793..00f42f9e3f5c6bfec5c23897b1019fdeb9aefdd6 100644 (file)
@@ -2,6 +2,7 @@
  *  SH7201 setup
  *
  *  Copyright (C) 2008  Peter Griffin pgriffin@mpc-data.co.uk
+ *  Copyright (C) 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -18,57 +19,32 @@ enum {
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
        PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
        ADC_ADI,
-       MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
-       MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
-       MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
-       MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
-       MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
-       MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
-       MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
-       RTC_ARM, RTC_PRD, RTC_CUP,
-       WDT,
-       IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI,
-       IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI,
-       IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI,
+
+       MTU20_ABCD, MTU20_VEF, MTU21_AB, MTU21_VU, MTU22_AB, MTU22_VU,
+       MTU23_ABCD, MTU24_ABCD, MTU25_UVW, MTU2_TCI3V, MTU2_TCI4V,
+
+       RTC, WDT,
+
+       IIC30, IIC31, IIC32,
 
        DMAC0_DMINT0, DMAC1_DMINT1,
        DMAC2_DMINT2, DMAC3_DMINT3,
 
-       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
-       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
-       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
-       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
-       SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
-       SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
-       SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
-       SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+       SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
 
        DMAC0_DMINTA, DMAC4_DMINT4, DMAC5_DMINT5, DMAC6_DMINT6,
        DMAC7_DMINT7,
 
-       RCAN0_ERS, RCAN0_OVR,
-       RCAN0_SLE,
-       RCAN0_RM0, RCAN0_RM1,
-
-       RCAN1_ERS, RCAN1_OVR,
-       RCAN1_SLE,
-       RCAN1_RM0, RCAN1_RM1,
+       RCAN0, RCAN1,
 
        SSI0_SSII, SSI1_SSII,
 
-       TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0,
-       TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1,
+       TMR0, TMR1,
 
        /* interrupt groups */
-
-       IRQ, PINT, ADC,
-       MTU20_ABCD, MTU20_VEF, MTU21_AB, MTU21_VU, MTU22_AB, MTU22_VU,
-       MTU23_ABCD, MTU24_ABCD, MTU25_UVW,
-       RTC, IIC30, IIC31, IIC32,
-       SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
-       RCAN0, RCAN1, TMR0, TMR1
-
+       PINT,
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -76,6 +52,7 @@ static struct intc_vect vectors[] __initdata = {
        INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
        INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
        INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
        INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
        INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
        INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
@@ -83,123 +60,92 @@ static struct intc_vect vectors[] __initdata = {
 
        INTC_IRQ(ADC_ADI, 92),
 
-       INTC_IRQ(MTU2_TGI0A, 108), INTC_IRQ(MTU2_TGI0B, 109),
-       INTC_IRQ(MTU2_TGI0C, 110), INTC_IRQ(MTU2_TGI0D, 111),
-       INTC_IRQ(MTU2_TCI0V, 112),
-       INTC_IRQ(MTU2_TGI0E, 113), INTC_IRQ(MTU2_TGI0F, 114),
+       INTC_IRQ(MTU20_ABCD, 108), INTC_IRQ(MTU20_ABCD, 109),
+       INTC_IRQ(MTU20_ABCD, 110), INTC_IRQ(MTU20_ABCD, 111),
+
+       INTC_IRQ(MTU20_VEF, 112), INTC_IRQ(MTU20_VEF, 113),
+       INTC_IRQ(MTU20_VEF, 114),
+
+       INTC_IRQ(MTU21_AB, 116), INTC_IRQ(MTU21_AB, 117),
+       INTC_IRQ(MTU21_VU, 120), INTC_IRQ(MTU21_VU, 121),
 
-       INTC_IRQ(MTU2_TGI1A, 116), INTC_IRQ(MTU2_TGI1B, 117),
-       INTC_IRQ(MTU2_TCI1V, 120), INTC_IRQ(MTU2_TCI1U, 121),
+       INTC_IRQ(MTU22_AB, 124), INTC_IRQ(MTU22_AB, 125),
+       INTC_IRQ(MTU22_VU, 128), INTC_IRQ(MTU22_VU, 129),
 
-       INTC_IRQ(MTU2_TGI2A, 124), INTC_IRQ(MTU2_TGI2B, 125),
-       INTC_IRQ(MTU2_TCI2V, 128), INTC_IRQ(MTU2_TCI2U, 129),
+       INTC_IRQ(MTU23_ABCD, 132), INTC_IRQ(MTU23_ABCD, 133),
+       INTC_IRQ(MTU23_ABCD, 134), INTC_IRQ(MTU23_ABCD, 135),
 
-       INTC_IRQ(MTU2_TGI3A, 132), INTC_IRQ(MTU2_TGI3B, 133),
-       INTC_IRQ(MTU2_TGI3C, 134), INTC_IRQ(MTU2_TGI3D, 135),
        INTC_IRQ(MTU2_TCI3V, 136),
 
-       INTC_IRQ(MTU2_TGI4A, 140), INTC_IRQ(MTU2_TGI4B, 141),
-       INTC_IRQ(MTU2_TGI4C, 142), INTC_IRQ(MTU2_TGI4D, 143),
+       INTC_IRQ(MTU24_ABCD, 140), INTC_IRQ(MTU24_ABCD, 141),
+       INTC_IRQ(MTU24_ABCD, 142), INTC_IRQ(MTU24_ABCD, 143),
+
        INTC_IRQ(MTU2_TCI4V, 144),
 
-       INTC_IRQ(MTU2_TGI5U, 148), INTC_IRQ(MTU2_TGI5V, 149),
-       INTC_IRQ(MTU2_TGI5W, 150),
+       INTC_IRQ(MTU25_UVW, 148), INTC_IRQ(MTU25_UVW, 149),
+       INTC_IRQ(MTU25_UVW, 150),
+
+       INTC_IRQ(RTC, 152), INTC_IRQ(RTC, 153),
+       INTC_IRQ(RTC, 154),
 
-       INTC_IRQ(RTC_ARM, 152), INTC_IRQ(RTC_PRD, 153),
-       INTC_IRQ(RTC_CUP, 154), INTC_IRQ(WDT, 156),
+       INTC_IRQ(WDT, 156),
 
-       INTC_IRQ(IIC30_STPI, 157), INTC_IRQ(IIC30_NAKI, 158),
-       INTC_IRQ(IIC30_RXI, 159), INTC_IRQ(IIC30_TXI, 160),
-       INTC_IRQ(IIC30_TEI, 161),
+       INTC_IRQ(IIC30, 157), INTC_IRQ(IIC30, 158),
+       INTC_IRQ(IIC30, 159), INTC_IRQ(IIC30, 160),
+       INTC_IRQ(IIC30, 161),
 
-       INTC_IRQ(IIC31_STPI, 164), INTC_IRQ(IIC31_NAKI, 165),
-       INTC_IRQ(IIC31_RXI, 166), INTC_IRQ(IIC31_TXI, 167),
-       INTC_IRQ(IIC31_TEI, 168),
+       INTC_IRQ(IIC31, 164), INTC_IRQ(IIC31, 165),
+       INTC_IRQ(IIC31, 166), INTC_IRQ(IIC31, 167),
+       INTC_IRQ(IIC31, 168),
 
-       INTC_IRQ(IIC32_STPI, 170), INTC_IRQ(IIC32_NAKI, 171),
-       INTC_IRQ(IIC32_RXI, 172), INTC_IRQ(IIC32_TXI, 173),
-       INTC_IRQ(IIC32_TEI, 174),
+       INTC_IRQ(IIC32, 170), INTC_IRQ(IIC32, 171),
+       INTC_IRQ(IIC32, 172), INTC_IRQ(IIC32, 173),
+       INTC_IRQ(IIC32, 174),
 
        INTC_IRQ(DMAC0_DMINT0, 176), INTC_IRQ(DMAC1_DMINT1, 177),
        INTC_IRQ(DMAC2_DMINT2, 178), INTC_IRQ(DMAC3_DMINT3, 179),
 
-       INTC_IRQ(SCIF0_BRI, 180), INTC_IRQ(SCIF0_ERI, 181),
-       INTC_IRQ(SCIF0_RXI, 182), INTC_IRQ(SCIF0_TXI, 183),
-       INTC_IRQ(SCIF1_BRI, 184), INTC_IRQ(SCIF1_ERI, 185),
-       INTC_IRQ(SCIF1_RXI, 186), INTC_IRQ(SCIF1_TXI, 187),
-       INTC_IRQ(SCIF2_BRI, 188), INTC_IRQ(SCIF2_ERI, 189),
-       INTC_IRQ(SCIF2_RXI, 190), INTC_IRQ(SCIF2_TXI, 191),
-       INTC_IRQ(SCIF3_BRI, 192), INTC_IRQ(SCIF3_ERI, 193),
-       INTC_IRQ(SCIF3_RXI, 194), INTC_IRQ(SCIF3_TXI, 195),
-       INTC_IRQ(SCIF4_BRI, 196), INTC_IRQ(SCIF4_ERI, 197),
-       INTC_IRQ(SCIF4_RXI, 198), INTC_IRQ(SCIF4_TXI, 199),
-       INTC_IRQ(SCIF5_BRI, 200), INTC_IRQ(SCIF5_ERI, 201),
-       INTC_IRQ(SCIF5_RXI, 202), INTC_IRQ(SCIF5_TXI, 203),
-       INTC_IRQ(SCIF6_BRI, 204), INTC_IRQ(SCIF6_ERI, 205),
-       INTC_IRQ(SCIF6_RXI, 206), INTC_IRQ(SCIF6_TXI, 207),
-       INTC_IRQ(SCIF7_BRI, 208), INTC_IRQ(SCIF7_ERI, 209),
-       INTC_IRQ(SCIF7_RXI, 210), INTC_IRQ(SCIF7_TXI, 211),
+       INTC_IRQ(SCIF0, 180), INTC_IRQ(SCIF0, 181),
+       INTC_IRQ(SCIF0, 182), INTC_IRQ(SCIF0, 183),
+       INTC_IRQ(SCIF1, 184), INTC_IRQ(SCIF1, 185),
+       INTC_IRQ(SCIF1, 186), INTC_IRQ(SCIF1, 187),
+       INTC_IRQ(SCIF2, 188), INTC_IRQ(SCIF2, 189),
+       INTC_IRQ(SCIF2, 190), INTC_IRQ(SCIF2, 191),
+       INTC_IRQ(SCIF3, 192), INTC_IRQ(SCIF3, 193),
+       INTC_IRQ(SCIF3, 194), INTC_IRQ(SCIF3, 195),
+       INTC_IRQ(SCIF4, 196), INTC_IRQ(SCIF4, 197),
+       INTC_IRQ(SCIF4, 198), INTC_IRQ(SCIF4, 199),
+       INTC_IRQ(SCIF5, 200), INTC_IRQ(SCIF5, 201),
+       INTC_IRQ(SCIF5, 202), INTC_IRQ(SCIF5, 203),
+       INTC_IRQ(SCIF6, 204), INTC_IRQ(SCIF6, 205),
+       INTC_IRQ(SCIF6, 206), INTC_IRQ(SCIF6, 207),
+       INTC_IRQ(SCIF7, 208), INTC_IRQ(SCIF7, 209),
+       INTC_IRQ(SCIF7, 210), INTC_IRQ(SCIF7, 211),
 
        INTC_IRQ(DMAC0_DMINTA, 212), INTC_IRQ(DMAC4_DMINT4, 216),
        INTC_IRQ(DMAC5_DMINT5, 217), INTC_IRQ(DMAC6_DMINT6, 218),
        INTC_IRQ(DMAC7_DMINT7, 219),
 
-       INTC_IRQ(RCAN0_ERS, 228), INTC_IRQ(RCAN0_OVR, 229),
-       INTC_IRQ(RCAN0_SLE, 230),
-       INTC_IRQ(RCAN0_RM0, 231), INTC_IRQ(RCAN0_RM1, 232),
+       INTC_IRQ(RCAN0, 228), INTC_IRQ(RCAN0, 229),
+       INTC_IRQ(RCAN0, 230),
+       INTC_IRQ(RCAN0, 231), INTC_IRQ(RCAN0, 232),
 
-       INTC_IRQ(RCAN1_ERS, 234), INTC_IRQ(RCAN1_OVR, 235),
-       INTC_IRQ(RCAN1_SLE, 236),
-       INTC_IRQ(RCAN1_RM0, 237), INTC_IRQ(RCAN1_RM1, 238),
+       INTC_IRQ(RCAN1, 234), INTC_IRQ(RCAN1, 235),
+       INTC_IRQ(RCAN1, 236),
+       INTC_IRQ(RCAN1, 237), INTC_IRQ(RCAN1, 238),
 
        INTC_IRQ(SSI0_SSII, 244), INTC_IRQ(SSI1_SSII, 245),
 
-       INTC_IRQ(TMR0_CMIA0, 246), INTC_IRQ(TMR0_CMIB0, 247),
-       INTC_IRQ(TMR0_OVI0, 248),
-
-       INTC_IRQ(TMR1_CMIA1, 252), INTC_IRQ(TMR1_CMIB1, 253),
-       INTC_IRQ(TMR1_OVI1, 254),
+       INTC_IRQ(TMR0, 246), INTC_IRQ(TMR0, 247),
+       INTC_IRQ(TMR0, 248),
 
+       INTC_IRQ(TMR1, 252), INTC_IRQ(TMR1, 253),
+       INTC_IRQ(TMR1, 254),
 };
 
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
                   PINT4, PINT5, PINT6, PINT7),
-       INTC_GROUP(MTU20_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
-       INTC_GROUP(MTU20_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
-
-       INTC_GROUP(MTU21_AB, MTU2_TGI1A, MTU2_TGI1B),
-       INTC_GROUP(MTU21_VU, MTU2_TCI1V, MTU2_TCI1U),
-       INTC_GROUP(MTU22_AB, MTU2_TGI2A, MTU2_TGI2B),
-       INTC_GROUP(MTU22_VU, MTU2_TCI2V, MTU2_TCI2U),
-       INTC_GROUP(MTU23_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
-       INTC_GROUP(MTU24_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
-       INTC_GROUP(MTU25_UVW, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
-       INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP ),
-
-       INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI,
-                  IIC30_TEI),
-       INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI,
-                  IIC31_TEI),
-       INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI,
-                  IIC32_TEI),
-
-       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
-       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
-       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
-       INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
-       INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
-       INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
-       INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
-
-       INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1,
-                  RCAN0_SLE),
-       INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1,
-                  RCAN1_SLE),
-
-       INTC_GROUP(TMR0, TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0),
-       INTC_GROUP(TMR1, TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1),
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -212,7 +158,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
 
        { 0xfffe9806, 0, 16, 4, /* IPR09 */ { RTC, WDT, IIC30, 0 } },
        { 0xfffe9808, 0, 16, 4, /* IPR10 */ { IIC31, IIC32, DMAC0_DMINT0, DMAC1_DMINT1 } },
-       { 0xfffe980a, 0, 16, 4, /* IPR11 */ { DMAC2_DMINT2, DMAC3_DMINT3, SCIF0 , SCIF1 } },
+       { 0xfffe980a, 0, 16, 4, /* IPR11 */ { DMAC2_DMINT2, DMAC3_DMINT3, SCIF0, SCIF1 } },
        { 0xfffe980c, 0, 16, 4, /* IPR12 */ { SCIF2, SCIF3, SCIF4, SCIF5 } },
        { 0xfffe980e, 0, 16, 4, /* IPR13 */ { SCIF6, SCIF7, DMAC0_DMINTA, DMAC4_DMINT4  } },
        { 0xfffe9810, 0, 16, 4, /* IPR14 */ { DMAC5_DMINT5, DMAC6_DMINT6, DMAC7_DMINT7, 0 } },
@@ -234,42 +180,42 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xfffe8000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 181, 182, 183, 180}
+               .irqs           = { 180, 180, 180, 180 }
        }, {
                .mapbase        = 0xfffe8800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 185, 186, 187, 184}
+               .irqs           = { 184, 184, 184, 184 }
        }, {
                .mapbase        = 0xfffe9000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 189, 186, 187, 188}
+               .irqs           = { 188, 188, 188, 188 }
        }, {
                .mapbase        = 0xfffe9800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 193, 194, 195, 192}
+               .irqs           = { 192, 192, 192, 192 }
        }, {
                .mapbase        = 0xfffea000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 196, 198, 199, 196}
+               .irqs           = { 196, 196, 196, 196 }
        }, {
                .mapbase        = 0xfffea800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 201, 202, 203, 200}
+               .irqs           = { 200, 200, 200, 200 }
        }, {
                .mapbase        = 0xfffeb000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 205, 206, 207, 204}
+               .irqs           = { 204, 204, 204, 204 }
        }, {
                .mapbase        = 0xfffeb800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 209, 210, 211, 208}
+               .irqs           = { 208, 208, 208, 208 }
        }, {
                .flags = 0,
        }
@@ -290,17 +236,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 153,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 154,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
+               /* Shared Period/Carry/Alarm IRQ */
                .start  = 152,
                .flags  = IORESOURCE_IRQ,
        },
index e98dc4450352c6d1a474d2edfce07c03a723c53b..820dfb2e8656354e7972ccfc55371695c53e72f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH7203 and SH7263 Setup
  *
- *  Copyright (C) 2007  Paul Mundt
+ *  Copyright (C) 2007 - 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -18,50 +18,27 @@ enum {
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
        PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
-       DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
-       DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
-       DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
-       DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
+       DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
        USB, LCDC, CMT0, CMT1, BSC, WDT,
-       MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
-       MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
-       MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
-       MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
-       MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
-       MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
-       ADC_ADI,
-       IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI,
-       IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI,
-       IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI,
-       IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI, IIC33_TEI,
-       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
-       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
-       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
-       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
-       SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI,
-       SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI,
-       SSI0_SSII, SSI1_SSII, SSI2_SSII, SSI3_SSII,
 
-       /* ROM-DEC, SDHI, SRC, and IEB are SH7263 specific */
-       ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG, ROMDEC_ISEC, ROMDEC_IBUF,
-       ROMDEC_IREADY,
+       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+       MTU3_ABCD, MTU4_ABCD, MTU2_TCI3V, MTU2_TCI4V,
 
-       FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+       ADC_ADI,
+
+       IIC30, IIC31, IIC32, IIC33,
+       SCIF0, SCIF1, SCIF2, SCIF3,
 
-       SDHI3, SDHI0, SDHI1,
+       SSU0, SSU1,
 
-       RTC_ARM, RTC_PRD, RTC_CUP,
-       RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1, RCAN0_SLE,
-       RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1, RCAN1_SLE,
+       SSI0_SSII, SSI1_SSII, SSI2_SSII, SSI3_SSII,
 
-       SRC_OVF, SRC_ODFI, SRC_IDEI, IEBI,
+       /* ROM-DEC, SDHI, SRC, and IEB are SH7263 specific */
+       ROMDEC, FLCTL, SDHI, RTC, RCAN0, RCAN1,
+       SRC, IEBI,
 
        /* interrupt groups */
-       PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
-       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
-       MTU3_ABCD, MTU4_ABCD,
-       IIC30, IIC31, IIC32, IIC33, SCIF0, SCIF1, SCIF2, SCIF3,
-       SSU0, SSU1, ROMDEC, SDHI, FLCTL, RTC, RCAN0, RCAN1, SRC
+       PINT,
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -73,79 +50,80 @@ static struct intc_vect vectors[] __initdata = {
        INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
        INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
        INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
-       INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
-       INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
-       INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
-       INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
-       INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
-       INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
-       INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
-       INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
+       INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+       INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+       INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+       INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+       INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+       INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+       INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+       INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
        INTC_IRQ(USB, 140), INTC_IRQ(LCDC, 141),
        INTC_IRQ(CMT0, 142), INTC_IRQ(CMT1, 143),
        INTC_IRQ(BSC, 144), INTC_IRQ(WDT, 145),
-       INTC_IRQ(MTU2_TGI0A, 146), INTC_IRQ(MTU2_TGI0B, 147),
-       INTC_IRQ(MTU2_TGI0C, 148), INTC_IRQ(MTU2_TGI0D, 149),
-       INTC_IRQ(MTU2_TCI0V, 150),
-       INTC_IRQ(MTU2_TGI0E, 151), INTC_IRQ(MTU2_TGI0F, 152),
-       INTC_IRQ(MTU2_TGI1A, 153), INTC_IRQ(MTU2_TGI1B, 154),
-       INTC_IRQ(MTU2_TCI1V, 155), INTC_IRQ(MTU2_TCI1U, 156),
-       INTC_IRQ(MTU2_TGI2A, 157), INTC_IRQ(MTU2_TGI2B, 158),
-       INTC_IRQ(MTU2_TCI2V, 159), INTC_IRQ(MTU2_TCI2U, 160),
-       INTC_IRQ(MTU2_TGI3A, 161), INTC_IRQ(MTU2_TGI3B, 162),
-       INTC_IRQ(MTU2_TGI3C, 163), INTC_IRQ(MTU2_TGI3D, 164),
+       INTC_IRQ(MTU0_ABCD, 146), INTC_IRQ(MTU0_ABCD, 147),
+       INTC_IRQ(MTU0_ABCD, 148), INTC_IRQ(MTU0_ABCD, 149),
+       INTC_IRQ(MTU0_VEF, 150),
+       INTC_IRQ(MTU0_VEF, 151), INTC_IRQ(MTU0_VEF, 152),
+       INTC_IRQ(MTU1_AB, 153), INTC_IRQ(MTU1_AB, 154),
+       INTC_IRQ(MTU1_VU, 155), INTC_IRQ(MTU1_VU, 156),
+       INTC_IRQ(MTU2_AB, 157), INTC_IRQ(MTU2_AB, 158),
+       INTC_IRQ(MTU2_VU, 159), INTC_IRQ(MTU2_VU, 160),
+       INTC_IRQ(MTU3_ABCD, 161), INTC_IRQ(MTU3_ABCD, 162),
+       INTC_IRQ(MTU3_ABCD, 163), INTC_IRQ(MTU3_ABCD, 164),
        INTC_IRQ(MTU2_TCI3V, 165),
-       INTC_IRQ(MTU2_TGI4A, 166), INTC_IRQ(MTU2_TGI4B, 167),
-       INTC_IRQ(MTU2_TGI4C, 168), INTC_IRQ(MTU2_TGI4D, 169),
+       INTC_IRQ(MTU4_ABCD, 166), INTC_IRQ(MTU4_ABCD, 167),
+       INTC_IRQ(MTU4_ABCD, 168), INTC_IRQ(MTU4_ABCD, 169),
        INTC_IRQ(MTU2_TCI4V, 170),
        INTC_IRQ(ADC_ADI, 171),
-       INTC_IRQ(IIC30_STPI, 172), INTC_IRQ(IIC30_NAKI, 173),
-       INTC_IRQ(IIC30_RXI, 174), INTC_IRQ(IIC30_TXI, 175),
-       INTC_IRQ(IIC30_TEI, 176),
-       INTC_IRQ(IIC31_STPI, 177), INTC_IRQ(IIC31_NAKI, 178),
-       INTC_IRQ(IIC31_RXI, 179), INTC_IRQ(IIC31_TXI, 180),
-       INTC_IRQ(IIC31_TEI, 181),
-       INTC_IRQ(IIC32_STPI, 182), INTC_IRQ(IIC32_NAKI, 183),
-       INTC_IRQ(IIC32_RXI, 184), INTC_IRQ(IIC32_TXI, 185),
-       INTC_IRQ(IIC32_TEI, 186),
-       INTC_IRQ(IIC33_STPI, 187), INTC_IRQ(IIC33_NAKI, 188),
-       INTC_IRQ(IIC33_RXI, 189), INTC_IRQ(IIC33_TXI, 190),
-       INTC_IRQ(IIC33_TEI, 191),
-       INTC_IRQ(SCIF0_BRI, 192), INTC_IRQ(SCIF0_ERI, 193),
-       INTC_IRQ(SCIF0_RXI, 194), INTC_IRQ(SCIF0_TXI, 195),
-       INTC_IRQ(SCIF1_BRI, 196), INTC_IRQ(SCIF1_ERI, 197),
-       INTC_IRQ(SCIF1_RXI, 198), INTC_IRQ(SCIF1_TXI, 199),
-       INTC_IRQ(SCIF2_BRI, 200), INTC_IRQ(SCIF2_ERI, 201),
-       INTC_IRQ(SCIF2_RXI, 202), INTC_IRQ(SCIF2_TXI, 203),
-       INTC_IRQ(SCIF3_BRI, 204), INTC_IRQ(SCIF3_ERI, 205),
-       INTC_IRQ(SCIF3_RXI, 206), INTC_IRQ(SCIF3_TXI, 207),
-       INTC_IRQ(SSU0_SSERI, 208), INTC_IRQ(SSU0_SSRXI, 209),
-       INTC_IRQ(SSU0_SSTXI, 210),
-       INTC_IRQ(SSU1_SSERI, 211), INTC_IRQ(SSU1_SSRXI, 212),
-       INTC_IRQ(SSU1_SSTXI, 213),
+       INTC_IRQ(IIC30, 172), INTC_IRQ(IIC30, 173),
+       INTC_IRQ(IIC30, 174), INTC_IRQ(IIC30, 175),
+       INTC_IRQ(IIC30, 176),
+       INTC_IRQ(IIC31, 177), INTC_IRQ(IIC31, 178),
+       INTC_IRQ(IIC31, 179), INTC_IRQ(IIC31, 180),
+       INTC_IRQ(IIC31, 181),
+       INTC_IRQ(IIC32, 182), INTC_IRQ(IIC32, 183),
+       INTC_IRQ(IIC32, 184), INTC_IRQ(IIC32, 185),
+       INTC_IRQ(IIC32, 186),
+       INTC_IRQ(IIC33, 187), INTC_IRQ(IIC33, 188),
+       INTC_IRQ(IIC33, 189), INTC_IRQ(IIC33, 190),
+       INTC_IRQ(IIC33, 191),
+       INTC_IRQ(SCIF0, 192), INTC_IRQ(SCIF0, 193),
+       INTC_IRQ(SCIF0, 194), INTC_IRQ(SCIF0, 195),
+       INTC_IRQ(SCIF1, 196), INTC_IRQ(SCIF1, 197),
+       INTC_IRQ(SCIF1, 198), INTC_IRQ(SCIF1, 199),
+       INTC_IRQ(SCIF2, 200), INTC_IRQ(SCIF2, 201),
+       INTC_IRQ(SCIF2, 202), INTC_IRQ(SCIF2, 203),
+       INTC_IRQ(SCIF3, 204), INTC_IRQ(SCIF3, 205),
+       INTC_IRQ(SCIF3, 206), INTC_IRQ(SCIF3, 207),
+       INTC_IRQ(SSU0, 208), INTC_IRQ(SSU0, 209),
+       INTC_IRQ(SSU0, 210),
+       INTC_IRQ(SSU1, 211), INTC_IRQ(SSU1, 212),
+       INTC_IRQ(SSU1, 213),
        INTC_IRQ(SSI0_SSII, 214), INTC_IRQ(SSI1_SSII, 215),
        INTC_IRQ(SSI2_SSII, 216), INTC_IRQ(SSI3_SSII, 217),
-       INTC_IRQ(FLCTL_FLSTEI, 224), INTC_IRQ(FLCTL_FLTENDI, 225),
-       INTC_IRQ(FLCTL_FLTREQ0I, 226), INTC_IRQ(FLCTL_FLTREQ1I, 227),
-       INTC_IRQ(RTC_ARM, 231), INTC_IRQ(RTC_PRD, 232),
-       INTC_IRQ(RTC_CUP, 233),
-       INTC_IRQ(RCAN0_ERS, 234), INTC_IRQ(RCAN0_OVR, 235),
-       INTC_IRQ(RCAN0_RM0, 236), INTC_IRQ(RCAN0_RM1, 237),
-       INTC_IRQ(RCAN0_SLE, 238),
-       INTC_IRQ(RCAN1_ERS, 239), INTC_IRQ(RCAN1_OVR, 240),
-       INTC_IRQ(RCAN1_RM0, 241), INTC_IRQ(RCAN1_RM1, 242),
-       INTC_IRQ(RCAN1_SLE, 243),
+       INTC_IRQ(FLCTL, 224), INTC_IRQ(FLCTL, 225),
+       INTC_IRQ(FLCTL, 226), INTC_IRQ(FLCTL, 227),
+       INTC_IRQ(RTC, 231), INTC_IRQ(RTC, 232),
+       INTC_IRQ(RTC, 233),
+       INTC_IRQ(RCAN0, 234), INTC_IRQ(RCAN0, 235),
+       INTC_IRQ(RCAN0, 236), INTC_IRQ(RCAN0, 237),
+       INTC_IRQ(RCAN0, 238),
+       INTC_IRQ(RCAN1, 239), INTC_IRQ(RCAN1, 240),
+       INTC_IRQ(RCAN1, 241), INTC_IRQ(RCAN1, 242),
+       INTC_IRQ(RCAN1, 243),
 
        /* SH7263-specific trash */
 #ifdef CONFIG_CPU_SUBTYPE_SH7263
-       INTC_IRQ(ROMDEC_ISY, 218), INTC_IRQ(ROMDEC_IERR, 219),
-       INTC_IRQ(ROMDEC_IARG, 220), INTC_IRQ(ROMDEC_ISEC, 221),
-       INTC_IRQ(ROMDEC_IBUF, 222), INTC_IRQ(ROMDEC_IREADY, 223),
+       INTC_IRQ(ROMDEC, 218), INTC_IRQ(ROMDEC, 219),
+       INTC_IRQ(ROMDEC, 220), INTC_IRQ(ROMDEC, 221),
+       INTC_IRQ(ROMDEC, 222), INTC_IRQ(ROMDEC, 223),
 
-       INTC_IRQ(SDHI3, 228), INTC_IRQ(SDHI0, 229), INTC_IRQ(SDHI1, 230),
+       INTC_IRQ(SDHI, 228), INTC_IRQ(SDHI, 229),
+       INTC_IRQ(SDHI, 230),
 
-       INTC_IRQ(SRC_OVF, 244), INTC_IRQ(SRC_ODFI, 245),
-       INTC_IRQ(SRC_IDEI, 246),
+       INTC_IRQ(SRC, 244), INTC_IRQ(SRC, 245),
+       INTC_IRQ(SRC, 246),
 
        INTC_IRQ(IEBI, 247),
 #endif
@@ -154,50 +132,6 @@ static struct intc_vect vectors[] __initdata = {
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
                   PINT4, PINT5, PINT6, PINT7),
-       INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
-       INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
-       INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
-       INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
-       INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
-       INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
-       INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
-       INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
-       INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
-       INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
-       INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
-       INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
-       INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
-       INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
-       INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
-       INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
-       INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI,
-                  IIC30_TEI),
-       INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI,
-                  IIC31_TEI),
-       INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI,
-                  IIC32_TEI),
-       INTC_GROUP(IIC33, IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI,
-                  IIC33_TEI),
-       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
-       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
-       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
-       INTC_GROUP(SSU0, SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI),
-       INTC_GROUP(SSU1, SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI),
-       INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I,
-                  FLCTL_FLTREQ1I),
-       INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP),
-       INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1,
-                  RCAN0_SLE),
-       INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1,
-                  RCAN1_SLE),
-
-#ifdef CONFIG_CPU_SUBTYPE_SH7263
-       INTC_GROUP(ROMDEC, ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG,
-                  ROMDEC_ISEC, ROMDEC_IBUF, ROMDEC_IREADY),
-       INTC_GROUP(SDHI, SDHI3, SDHI0, SDHI1),
-       INTC_GROUP(SRC, SRC_OVF, SRC_ODFI, SRC_IDEI),
-#endif
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -242,22 +176,22 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xfffe8000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 193, 194, 195, 192 },
+               .irqs           =  { 192, 192, 192, 192 },
        }, {
                .mapbase        = 0xfffe8800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 197, 198, 199, 196 },
+               .irqs           =  { 196, 196, 196, 196 },
        }, {
                .mapbase        = 0xfffe9000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 201, 202, 203, 200 },
+               .irqs           =  { 200, 200, 200, 200 },
        }, {
                .mapbase        = 0xfffe9800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 205, 206, 207, 204 },
+               .irqs           =  { 204, 204, 204, 204 },
        }, {
                .flags = 0,
        }
@@ -278,17 +212,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 232,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 233,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
+               /* Shared Period/Carry/Alarm IRQ */
                .start  = 231,
                .flags  = IORESOURCE_IRQ,
        },
index e6d4ec445dd885d693a39e9b3c4d273ace48db6c..c46a8355726d18f766dd8d5b92443ade34cdc059 100644 (file)
@@ -2,6 +2,7 @@
  * SH7206 Setup
  *
  *  Copyright (C) 2006  Yoshinori Sato
+ *  Copyright (C) 2009  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -19,34 +20,23 @@ enum {
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
        PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
        ADC_ADI0, ADC_ADI1,
-       DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
-       DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
-       DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
-       DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
+
+       DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+
+       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+       MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S,
+       IIC3,
+
        CMT0, CMT1, BSC, WDT,
-       MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
-       MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
-       MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
-       MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
-       MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
-       MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
-       MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
-       POE2_OEI1, POE2_OEI2,
-       MTU2S_TGI3A, MTU2S_TGI3B, MTU2S_TGI3C, MTU2S_TGI3D, MTU2S_TCI3V,
-       MTU2S_TGI4A, MTU2S_TGI4B, MTU2S_TGI4C, MTU2S_TGI4D, MTU2S_TCI4V,
-       MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W,
+
+       MTU2_TCI3V, MTU2_TCI4V, MTU2S_TCI3V, MTU2S_TCI4V,
+
        POE2_OEI3,
-       IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI,
-       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
-       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
-       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
-       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+
+       SCIF0, SCIF1, SCIF2, SCIF3,
 
        /* interrupt groups */
-       PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
-       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
-       MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S,
-       IIC3, SCIF0, SCIF1, SCIF2, SCIF3,
+       PINT,
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -59,86 +49,58 @@ static struct intc_vect vectors[] __initdata = {
        INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
        INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
        INTC_IRQ(ADC_ADI0, 92), INTC_IRQ(ADC_ADI1, 96),
-       INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
-       INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
-       INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
-       INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
-       INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
-       INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
-       INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
-       INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
+       INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+       INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+       INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+       INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+       INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+       INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+       INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+       INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
        INTC_IRQ(CMT0, 140), INTC_IRQ(CMT1, 144),
        INTC_IRQ(BSC, 148), INTC_IRQ(WDT, 152),
-       INTC_IRQ(MTU2_TGI0A, 156), INTC_IRQ(MTU2_TGI0B, 157),
-       INTC_IRQ(MTU2_TGI0C, 158), INTC_IRQ(MTU2_TGI0D, 159),
-       INTC_IRQ(MTU2_TCI0V, 160),
-       INTC_IRQ(MTU2_TGI0E, 161), INTC_IRQ(MTU2_TGI0F, 162),
-       INTC_IRQ(MTU2_TGI1A, 164), INTC_IRQ(MTU2_TGI1B, 165),
-       INTC_IRQ(MTU2_TCI1V, 168), INTC_IRQ(MTU2_TCI1U, 169),
-       INTC_IRQ(MTU2_TGI2A, 172), INTC_IRQ(MTU2_TGI2B, 173),
-       INTC_IRQ(MTU2_TCI2V, 176), INTC_IRQ(MTU2_TCI2U, 177),
-       INTC_IRQ(MTU2_TGI3A, 180), INTC_IRQ(MTU2_TGI3B, 181),
-       INTC_IRQ(MTU2_TGI3C, 182), INTC_IRQ(MTU2_TGI3D, 183),
+       INTC_IRQ(MTU0_ABCD, 156), INTC_IRQ(MTU0_ABCD, 157),
+       INTC_IRQ(MTU0_ABCD, 158), INTC_IRQ(MTU0_ABCD, 159),
+       INTC_IRQ(MTU0_VEF, 160), INTC_IRQ(MTU0_VEF, 161),
+       INTC_IRQ(MTU0_VEF, 162),
+       INTC_IRQ(MTU1_AB, 164), INTC_IRQ(MTU1_AB, 165),
+       INTC_IRQ(MTU1_VU, 168), INTC_IRQ(MTU1_VU, 169),
+       INTC_IRQ(MTU2_AB, 172), INTC_IRQ(MTU2_AB, 173),
+       INTC_IRQ(MTU2_VU, 176), INTC_IRQ(MTU2_VU, 177),
+       INTC_IRQ(MTU3_ABCD, 180), INTC_IRQ(MTU3_ABCD, 181),
+       INTC_IRQ(MTU3_ABCD, 182), INTC_IRQ(MTU3_ABCD, 183),
        INTC_IRQ(MTU2_TCI3V, 184),
-       INTC_IRQ(MTU2_TGI4A, 188), INTC_IRQ(MTU2_TGI4B, 189),
-       INTC_IRQ(MTU2_TGI4C, 190), INTC_IRQ(MTU2_TGI4D, 191),
+       INTC_IRQ(MTU4_ABCD, 188), INTC_IRQ(MTU4_ABCD, 189),
+       INTC_IRQ(MTU4_ABCD, 190), INTC_IRQ(MTU4_ABCD, 191),
        INTC_IRQ(MTU2_TCI4V, 192),
-       INTC_IRQ(MTU2_TGI5U, 196), INTC_IRQ(MTU2_TGI5V, 197),
-       INTC_IRQ(MTU2_TGI5W, 198),
-       INTC_IRQ(POE2_OEI1, 200), INTC_IRQ(POE2_OEI2, 201),
-       INTC_IRQ(MTU2S_TGI3A, 204), INTC_IRQ(MTU2S_TGI3B, 205),
-       INTC_IRQ(MTU2S_TGI3C, 206), INTC_IRQ(MTU2S_TGI3D, 207),
+       INTC_IRQ(MTU5, 196), INTC_IRQ(MTU5, 197),
+       INTC_IRQ(MTU5, 198),
+       INTC_IRQ(POE2_12, 200), INTC_IRQ(POE2_12, 201),
+       INTC_IRQ(MTU3S_ABCD, 204), INTC_IRQ(MTU3S_ABCD, 205),
+       INTC_IRQ(MTU3S_ABCD, 206), INTC_IRQ(MTU3S_ABCD, 207),
        INTC_IRQ(MTU2S_TCI3V, 208),
-       INTC_IRQ(MTU2S_TGI4A, 212), INTC_IRQ(MTU2S_TGI4B, 213),
-       INTC_IRQ(MTU2S_TGI4C, 214), INTC_IRQ(MTU2S_TGI4D, 215),
+       INTC_IRQ(MTU4S_ABCD, 212), INTC_IRQ(MTU4S_ABCD, 213),
+       INTC_IRQ(MTU4S_ABCD, 214), INTC_IRQ(MTU4S_ABCD, 215),
        INTC_IRQ(MTU2S_TCI4V, 216),
-       INTC_IRQ(MTU2S_TGI5U, 220), INTC_IRQ(MTU2S_TGI5V, 221),
-       INTC_IRQ(MTU2S_TGI5W, 222),
+       INTC_IRQ(MTU5S, 220), INTC_IRQ(MTU5S, 221),
+       INTC_IRQ(MTU5S, 222),
        INTC_IRQ(POE2_OEI3, 224),
-       INTC_IRQ(IIC3_STPI, 228), INTC_IRQ(IIC3_NAKI, 229),
-       INTC_IRQ(IIC3_RXI, 230), INTC_IRQ(IIC3_TXI, 231),
-       INTC_IRQ(IIC3_TEI, 232),
-       INTC_IRQ(SCIF0_BRI, 240), INTC_IRQ(SCIF0_ERI, 241),
-       INTC_IRQ(SCIF0_RXI, 242), INTC_IRQ(SCIF0_TXI, 243),
-       INTC_IRQ(SCIF1_BRI, 244), INTC_IRQ(SCIF1_ERI, 245),
-       INTC_IRQ(SCIF1_RXI, 246), INTC_IRQ(SCIF1_TXI, 247),
-       INTC_IRQ(SCIF2_BRI, 248), INTC_IRQ(SCIF2_ERI, 249),
-       INTC_IRQ(SCIF2_RXI, 250), INTC_IRQ(SCIF2_TXI, 251),
-       INTC_IRQ(SCIF3_BRI, 252), INTC_IRQ(SCIF3_ERI, 253),
-       INTC_IRQ(SCIF3_RXI, 254), INTC_IRQ(SCIF3_TXI, 255),
+       INTC_IRQ(IIC3, 228), INTC_IRQ(IIC3, 229),
+       INTC_IRQ(IIC3, 230), INTC_IRQ(IIC3, 231),
+       INTC_IRQ(IIC3, 232),
+       INTC_IRQ(SCIF0, 240), INTC_IRQ(SCIF0, 241),
+       INTC_IRQ(SCIF0, 242), INTC_IRQ(SCIF0, 243),
+       INTC_IRQ(SCIF1, 244), INTC_IRQ(SCIF1, 245),
+       INTC_IRQ(SCIF1, 246), INTC_IRQ(SCIF1, 247),
+       INTC_IRQ(SCIF2, 248), INTC_IRQ(SCIF2, 249),
+       INTC_IRQ(SCIF2, 250), INTC_IRQ(SCIF2, 251),
+       INTC_IRQ(SCIF3, 252), INTC_IRQ(SCIF3, 253),
+       INTC_IRQ(SCIF3, 254), INTC_IRQ(SCIF3, 255),
 };
 
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
                   PINT4, PINT5, PINT6, PINT7),
-       INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
-       INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
-       INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
-       INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
-       INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
-       INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
-       INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
-       INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
-       INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
-       INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
-       INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
-       INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
-       INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
-       INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
-       INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
-       INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
-       INTC_GROUP(MTU5, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
-       INTC_GROUP(POE2_12, POE2_OEI1, POE2_OEI2),
-       INTC_GROUP(MTU3S_ABCD, MTU2S_TGI3A, MTU2S_TGI3B,
-                  MTU2S_TGI3C, MTU2S_TGI3D),
-       INTC_GROUP(MTU4S_ABCD, MTU2S_TGI4A, MTU2S_TGI4B,
-                  MTU2S_TGI4C, MTU2S_TGI4D),
-       INTC_GROUP(MTU5S, MTU2S_TGI5U, MTU2S_TGI5V, MTU2S_TGI5W),
-       INTC_GROUP(IIC3, IIC3_STPI, IIC3_NAKI, IIC3_RXI, IIC3_TXI, IIC3_TEI),
-       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
-       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
-       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -174,22 +136,22 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xfffe8000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 241, 242, 243, 240 },
+               .irqs           = { 240, 240, 240, 240 },
        }, {
                .mapbase        = 0xfffe8800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 245, 246, 247, 244 },
+               .irqs           = { 244, 244, 244, 244 },
        }, {
                .mapbase        = 0xfffe9000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 249, 250, 251, 248 },
+               .irqs           = { 248, 248, 248, 248 },
        }, {
                .mapbase        = 0xfffe9800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 253, 254, 255, 252 },
+               .irqs           = { 252, 252, 252, 252 },
        }, {
                .flags = 0,
        }
index e07c69e16d9b5202fff76d06e90773df0f374d1b..ecab274141a8bbda716b5669e450636e851fa445 100644 (file)
@@ -4,6 +4,8 @@
 
 obj-y  := ex.o probe.o entry.o setup-sh3.o
 
+obj-$(CONFIG_HIBERNATION)              += swsusp.o
+
 # CPU subtype setup
 obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o
index b4106d0c68ec0e0c8fc3db9365b5c289b15a961d..55da0ff9848db392297c05d12773452c74bf1793 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/unistd.h>
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
+#include <asm/cache.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -187,44 +188,35 @@ call_dae:
 #if defined(CONFIG_SH_STANDARD_BIOS)
        /* Unwind the stack and jmp to the debug entry */
 ENTRY(sh_bios_handler)
-       mov.l   @r15+, r0
-       mov.l   @r15+, r1
-       mov.l   @r15+, r2
-       mov.l   @r15+, r3
-       mov.l   @r15+, r4
-       mov.l   @r15+, r5
-       mov.l   @r15+, r6
-       mov.l   @r15+, r7
-       stc     sr, r8
-       mov.l   1f, r9                  ! BL =1, RB=1, IMASK=0x0F
-       or      r9, r8
-       ldc     r8, sr                  ! here, change the register bank
-       mov.l   @r15+, r8
-       mov.l   @r15+, r9
-       mov.l   @r15+, r10
-       mov.l   @r15+, r11
-       mov.l   @r15+, r12
-       mov.l   @r15+, r13
-       mov.l   @r15+, r14
-       mov.l   @r15+, k0
-       ldc.l   @r15+, spc
-       lds.l   @r15+, pr
-       mov.l   @r15+, k1
-       ldc.l   @r15+, gbr
-       lds.l   @r15+, mach
-       lds.l   @r15+, macl
-       mov     k0, r15
+       mov.l   1f, r8
+       bsr     restore_regs
+        nop
+
+       lds     k2, pr                  ! restore pr
+       mov     k4, r15
        !
        mov.l   2f, k0
        mov.l   @k0, k0
        jmp     @k0
-        ldc    k1, ssr
+        ldc    k3, ssr
        .align  2
 1:     .long   0x300000f0
 2:     .long   gdb_vbr_vector
 #endif /* CONFIG_SH_STANDARD_BIOS */
 
-restore_all:
+! restore_regs()
+! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
+! - switch bank
+! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
+! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
+! k2 returns original pr
+! k3 returns original sr
+! k4 returns original stack pointer
+! r8 passes SR bitmask, overwritten with restored data on return
+! r9 trashed
+! BL=0 on entry, on exit BL=1 (depending on r8).
+
+ENTRY(restore_regs)
        mov.l   @r15+, r0
        mov.l   @r15+, r1
        mov.l   @r15+, r2
@@ -234,10 +226,9 @@ restore_all:
        mov.l   @r15+, r6
        mov.l   @r15+, r7
        !
-       stc     sr, r8
-       mov.l   7f, r9
-       or      r9, r8                  ! BL =1, RB=1
-       ldc     r8, sr                  ! here, change the register bank
+       stc     sr, r9
+       or      r8, r9
+       ldc     r9, sr
        !
        mov.l   @r15+, r8
        mov.l   @r15+, r9
@@ -248,12 +239,20 @@ restore_all:
        mov.l   @r15+, r14
        mov.l   @r15+, k4               ! original stack pointer
        ldc.l   @r15+, spc
-       lds.l   @r15+, pr
+       mov.l   @r15+, k2               ! original PR
        mov.l   @r15+, k3               ! original SR
        ldc.l   @r15+, gbr
        lds.l   @r15+, mach
        lds.l   @r15+, macl
-       add     #4, r15                 ! Skip syscall number
+       rts
+        add    #4, r15                 ! Skip syscall number
+
+restore_all:
+       mov.l   7f, r8
+       bsr     restore_regs
+        nop
+
+       lds     k2, pr                  ! restore pr
        !
 #ifdef CONFIG_SH_DSP
        mov.l   @r15+, k0               ! DSP mode marker
@@ -294,7 +293,7 @@ skip_restore:
        mov     #0xf0, k1
        extu.b  k1, k1
        not     k1, k1
-       and     k1, k2                  ! Mask orignal SR value
+       and     k1, k2                  ! Mask original SR value
        !
        mov     k3, k0                  ! Calculate IMASK-bits
        shlr2   k0
@@ -313,7 +312,6 @@ skip_restore:
        mov     #0, k1
        mov.b   k1, @k0
 #endif
-       mov.l   @r15+, k2               ! restore EXPEVT
        mov     k4, r15
        rte
         nop
@@ -335,82 +333,56 @@ skip_restore:
        .balign         4096,0,4096
 ENTRY(vbr_base)
        .long   0
+!
+! 0x100: General exception vector
 !
        .balign         256,0,256
 general_exception:
-       mov.l   1f, k2
-       mov.l   2f, k3
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
-       mov.l   @k2, k2
+#ifndef CONFIG_CPU_SUBTYPE_SHX3
+       bra     handle_exception
+        sts    pr, k3          ! save original pr value in k3
+#else
+       mov.l   1f, k4
+       mov.l   @k4, k4
 
        ! Is EXPEVT larger than 0x800?
        mov     #0x8, k0
        shll8   k0
-       cmp/hs  k0, k2
+       cmp/hs  k0, k4
        bf      0f
 
        ! then add 0x580 (k2 is 0xd80 or 0xda0)
        mov     #0x58, k0
        shll2   k0
        shll2   k0
-       add     k0, k2
+       add     k0, k4
 0:
-       bra     handle_exception
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
         nop
-#else
-       bra     handle_exception
-        mov.l  @k2, k2
-#endif
-       .align  2
-1:     .long   EXPEVT
-2:     .long   ret_from_exception
-!
-!
 
-       .balign         1024,0,1024
-tlb_miss:
-       mov.l   1f, k2
-       mov.l   4f, k3
-       bra     handle_exception
-        mov.l  @k2, k2
-!
-       .balign         512,0,512
-interrupt:
-       mov.l   3f, k3
-#if defined(CONFIG_KGDB)
-       mov.l   2f, k2
-       ! Debounce (filter nested NMI)
-       mov.l   @k2, k0
-       mov.l   5f, k1
-       cmp/eq  k1, k0
-       bf      0f
-       mov.l   6f, k1
-       tas.b   @k1
-       bt      0f
-       rte
+       ! Save registers / Switch to bank 0
+       mov             k4, k2          ! keep vector in k2
+       mov.l   1f, k4          ! SR bits to clear in k4
+       bsr     save_regs       ! needs original pr value in k3
+        nop
+
+       bra     handle_exception_special
         nop
-       .align  2
-2:     .long   INTEVT
-5:     .long   NMI_VEC
-6:     .long   in_nmi
-0:
-#endif /* defined(CONFIG_KGDB) */
-       bra     handle_exception
-        mov    #-1, k2         ! interrupt exception marker
 
        .align  2
 1:     .long   EXPEVT
-3:     .long   ret_from_irq
-4:     .long   ret_from_exception
+#endif
 
-!
-!
-       .align  2
-ENTRY(handle_exception)
-       ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
-       ! save all registers onto stack.
-       !
+! prepare_stack_save_dsp()
+! - roll back gRB
+! - switch to kernel stack
+! - save DSP
+! k0 returns original sp (after roll back)
+! k1 trashed
+! k2 trashed
 
+prepare_stack_save_dsp:
 #ifdef CONFIG_GUSA
        ! Check for roll back gRB (User and Kernel)
        mov     r15, k0
@@ -430,7 +402,7 @@ ENTRY(handle_exception)
 2:     mov     k1, r15         ! SP = r1
 1:
 #endif
-
+       ! Switch to kernel stack if needed
        stc     ssr, k0         ! Is it from kernel space?
        shll    k0              ! Check MD bit (bit30) by shifting it into...
        shll    k0              !       ...the T bit
@@ -443,18 +415,17 @@ ENTRY(handle_exception)
        add     current, k1
        mov     k1, r15         ! change to kernel stack
        !
-1:     mov.l   2f, k1
-       !
+1:
 #ifdef CONFIG_SH_DSP
-       mov.l   r2, @-r15               ! Save r2, we need another reg
-       stc     sr, k4
-       mov.l   1f, r2
-       tst     r2, k4                  ! Check if in DSP mode
-       mov.l   @r15+, r2               ! Restore r2 now
+       ! Save DSP context if needed
+       stc     sr, k1
+       mov     #0x10, k2
+       shll8   k2                      ! DSP=1 (0x00001000)
+       tst     k2, k1                  ! Check if in DSP mode (passed in k2)
        bt/s    skip_save
-        mov    #0, k4                  ! Set marker for no stack frame
+        mov    #0, k1                  ! Set marker for no stack frame
 
-       mov     r2, k4                  ! Backup r2 (in k4) for later
+       mov     k2, k1                  ! Save has-frame marker
 
        ! Save DSP registers on stack
        stc.l   mod, @-r15
@@ -473,35 +444,74 @@ ENTRY(handle_exception)
        ! as we're not at all interested in supporting ancient toolchains at
        ! this point. -- PFM.
 
-       mov     r15, r2
+       mov     r15, k2
        .word   0xf653                  ! movs.l        a1, @-r2
        .word   0xf6f3                  ! movs.l        a0g, @-r2
        .word   0xf6d3                  ! movs.l        a1g, @-r2
        .word   0xf6c3                  ! movs.l        m0, @-r2
        .word   0xf6e3                  ! movs.l        m1, @-r2
-       mov     r2, r15
+       mov     k2, r15
 
-       mov     k4, r2                  ! Restore r2
-       mov.l   1f, k4                  ! Force DSP stack frame
 skip_save:
-       mov.l   k4, @-r15               ! Push DSP mode marker onto stack
+       mov.l   k1, @-r15               ! Push DSP mode marker onto stack
 #endif
-       ! Save the user registers on the stack.
-       mov.l   k2, @-r15       ! EXPEVT
-
-       mov     #-1, k4
-       mov.l   k4, @-r15       ! set TRA (default: -1)
-       !
+       rts
+        nop
+!
+! 0x400: Instruction and Data TLB miss exception vector
+!
+       .balign         1024,0,1024
+tlb_miss:
+       sts     pr, k3          ! save original pr value in k3
+
+handle_exception:
+       mova    exception_data, k0
+
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
+        PREF(k0)
+
+       ! Save registers / Switch to bank 0
+       mov.l   5f, k2          ! vector register address
+       mov.l   1f, k4          ! SR bits to clear in k4
+       bsr     save_regs       ! needs original pr value in k3
+        mov.l  @k2, k2         ! read out vector and keep in k2
+
+handle_exception_special:
+       ! Setup return address and jump to exception handler
+       mov.l   7f, r9          ! fetch return address
+       stc     r2_bank, r0     ! k2 (vector)
+       mov.l   6f, r10
+       shlr2   r0
+       shlr    r0
+       mov.l   @(r0, r10), r10
+       jmp     @r10
+        lds    r9, pr          ! put return address in pr
+
+       .align  L1_CACHE_SHIFT
+
+! save_regs()
+! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
+! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
+! - switch bank
+! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
+! k0 contains original stack pointer*
+! k1 trashed
+! k3 passes original pr*
+! k4 passes SR bitmask
+! BL=1 on entry, on exit BL=0.
+
+ENTRY(save_regs)
+       mov     #-1, r1
+       mov.l   k1, @-r15       ! set TRA (default: -1)
        sts.l   macl, @-r15
        sts.l   mach, @-r15
        stc.l   gbr, @-r15
        stc.l   ssr, @-r15
-       sts.l   pr, @-r15
+       mov.l   k3, @-r15       ! original pr in k3
        stc.l   spc, @-r15
-       !
-       lds     k3, pr          ! Set the return address to pr
-       !
-       mov.l   k0, @-r15       ! save orignal stack
+
+       mov.l   k0, @-r15       ! original stack pointer in k0
        mov.l   r14, @-r15
        mov.l   r13, @-r15
        mov.l   r12, @-r15
@@ -509,13 +519,23 @@ skip_save:
        mov.l   r10, @-r15
        mov.l   r9, @-r15
        mov.l   r8, @-r15
-       !
-       stc     sr, r8          ! Back to normal register bank, and
-       or      k1, r8          ! Block all interrupts
-       mov.l   3f, k1
-       and     k1, r8          ! ...
-       ldc     r8, sr          ! ...changed here.
-       !
+
+       mov.l   0f, k3          ! SR bits to set in k3
+
+       ! fall-through
+
+! save_low_regs()
+! - modify SR for bank switch
+! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
+! k3 passes bits to set in SR
+! k4 passes bits to clear in SR
+
+ENTRY(save_low_regs)
+       stc     sr, r8
+       or      k3, r8
+       and     k4, r8
+       ldc     r8, sr
+
        mov.l   r7, @-r15
        mov.l   r6, @-r15
        mov.l   r5, @-r15
@@ -523,52 +543,63 @@ skip_save:
        mov.l   r3, @-r15
        mov.l   r2, @-r15
        mov.l   r1, @-r15
-       mov.l   r0, @-r15
-
-       /*
-        * This gets a bit tricky.. in the INTEVT case we don't want to use
-        * the VBR offset as a destination in the jump call table, since all
-        * of the destinations are the same. In this case, (interrupt) sets
-        * a marker in r2 (now r2_bank since SR.RB changed), which we check
-        * to determine the exception type. For all other exceptions, we
-        * forcibly read EXPEVT from memory and fix up the jump address, in
-        * the interrupt exception case we jump to do_IRQ() and defer the
-        * INTEVT read until there. As a bonus, we can also clean up the SR.RB
-        * checks that do_IRQ() was doing..
-        */
-       stc     r2_bank, r8
-       cmp/pz  r8
-       bf      interrupt_exception
-       shlr2   r8
-       shlr    r8
-       mov.l   4f, r9
-       add     r8, r9
-       mov.l   @r9, r9
-       jmp     @r9
-        nop
        rts
-        nop
+        mov.l  r0, @-r15
 
+!
+! 0x600: Interrupt / NMI vector
+!
+       .balign         512,0,512
+ENTRY(handle_interrupt)
+#if defined(CONFIG_KGDB)
+       mov.l   2f, k2
+       ! Debounce (filter nested NMI)
+       mov.l   @k2, k0
+       mov.l   9f, k1
+       cmp/eq  k1, k0
+       bf      11f
+       mov.l   10f, k1
+       tas.b   @k1
+       bt      11f
+       rte
+        nop
        .align  2
-1:     .long   0x00001000      ! DSP=1
-2:     .long   0x000080f0      ! FD=1, IMASK=15
-3:     .long   0xcfffffff      ! RB=0, BL=0
-4:     .long   exception_handling_table
+9:     .long   NMI_VEC
+10:    .long   in_nmi
+11:
+#endif /* defined(CONFIG_KGDB) */
+       sts     pr, k3          ! save original pr value in k3
+       mova    exception_data, k0
 
-interrupt_exception:
-       mov.l   1f, r9
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
+        PREF(k0)
+
+       ! Save registers / Switch to bank 0
+       mov.l   1f, k4          ! SR bits to clear in k4
+       bsr     save_regs       ! needs original pr value in k3
+        mov    #-1, k2         ! default vector kept in k2
+
+       ! Setup return address and jump to do_IRQ
+       mov.l   4f, r9          ! fetch return address
+       lds     r9, pr          ! put return address in pr
        mov.l   2f, r4
-       mov.l   @r4, r4
+       mov.l   3f, r9
+       mov.l   @r4, r4         ! pass INTEVT vector as arg0
        jmp     @r9
-        mov    r15, r5
-       rts
-        nop
-
-       .align 2
-1:     .long   do_IRQ
-2:     .long   INTEVT
+        mov    r15, r5         ! pass saved registers as arg1
 
-       .align  2
 ENTRY(exception_none)
        rts
         nop
+
+       .align  L1_CACHE_SHIFT
+exception_data:
+0:     .long   0x000080f0      ! FD=1, IMASK=15
+1:     .long   0xcfffffff      ! RB=0, BL=0
+2:     .long   INTEVT
+3:     .long   do_IRQ
+4:     .long   ret_from_irq
+5:     .long   EXPEVT
+6:     .long   exception_handling_table
+7:     .long   ret_from_exception
index 6468ae86b9443fd53bf0310fc3e97092f641786e..63b67badd67e630ded46a1ccbfa59afc607fe635 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH7705 Setup
  *
- *  Copyright (C) 2006, 2007  Paul Mundt
+ *  Copyright (C) 2006 - 2009  Paul Mundt
  *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -21,51 +21,36 @@ enum {
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
        PINT07, PINT815,
-       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
-       SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
-       ADC_ADI,
-       USB_USI0, USB_USI1,
+
+       DMAC, SCIF0, SCIF2, ADC_ADI, USB,
+
        TPU0, TPU1, TPU2, TPU3,
-       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT,
-       REF_RCMI,
+       TMU0, TMU1, TMU2,
 
-       /* interrupt groups */
-       RTC, TMU2, DMAC, USB, SCIF2, SCIF0,
+       RTC, WDT, REF_RCMI,
 };
 
 static struct intc_vect vectors[] __initdata = {
        /* IRQ0->5 are handled in setup-sh3.c */
        INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
-       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
-       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
-       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
-       INTC_VECT(SCIF0_TXI, 0x8e0),
-       INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
-       INTC_VECT(SCIF2_TXI, 0x960),
+       INTC_VECT(DMAC, 0x800), INTC_VECT(DMAC, 0x820),
+       INTC_VECT(DMAC, 0x840), INTC_VECT(DMAC, 0x860),
+       INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
+       INTC_VECT(SCIF0, 0x8e0),
+       INTC_VECT(SCIF2, 0x900), INTC_VECT(SCIF2, 0x920),
+       INTC_VECT(SCIF2, 0x960),
        INTC_VECT(ADC_ADI, 0x980),
-       INTC_VECT(USB_USI0, 0xa20), INTC_VECT(USB_USI1, 0xa40),
+       INTC_VECT(USB, 0xa20), INTC_VECT(USB, 0xa40),
        INTC_VECT(TPU0, 0xc00), INTC_VECT(TPU1, 0xc20),
        INTC_VECT(TPU2, 0xc80), INTC_VECT(TPU3, 0xca0),
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
-       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
        INTC_VECT(WDT, 0x560),
        INTC_VECT(REF_RCMI, 0x580),
 };
 
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
-       INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
-       INTC_GROUP(USB, USB_USI0, USB_USI1),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
-       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
-};
-
 static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
        { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
@@ -78,7 +63,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
 
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, NULL,
                         NULL, prio_registers, NULL);
 
 static struct plat_sci_port sci_platform_data[] = {
@@ -86,12 +71,12 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xa4410000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 56, 57, 59 },
+               .irqs           = { 56, 56, 56 },
        }, {
                .mapbase        = 0xa4400000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 52, 53, 55 },
+               .irqs           = { 52, 52, 52 },
        }, {
                .flags = 0,
        }
@@ -115,14 +100,6 @@ static struct resource rtc_resources[] = {
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] =   {
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] =   {
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
 };
 
 static struct sh_rtc_platform_info rtc_info = {
index 93c55e2ed952484fead5128b91509a851c28a887..a74f960b5e79a5df1aa578a1e30fc4bbfe0a1590 100644 (file)
@@ -2,6 +2,7 @@
  * SH3 Setup code for SH7706, SH7707, SH7708, SH7709
  *
  *  Copyright (C) 2007  Magnus Damm
+ *  Copyright (C) 2009  Paul Mundt
  *
  * Based on setup-sh7709.c
  *
@@ -24,46 +25,37 @@ enum {
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
        PINT07, PINT815,
-       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
-       SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI,
-       ADC_ADI,
+       DMAC, SCIF0, SCIF2, SCI, ADC_ADI,
        LCDC, PCC0, PCC1,
-       TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT,
-       REF_RCMI, REF_ROVI,
-
-       /* interrupt groups */
-       RTC, REF, TMU2, DMAC, SCI, SCIF2, SCIF0,
+       TMU0, TMU1, TMU2,
+       RTC, WDT, REF,
 };
 
 static struct intc_vect vectors[] __initdata = {
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
-       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
-       INTC_VECT(SCI_ERI, 0x4e0), INTC_VECT(SCI_RXI, 0x500),
-       INTC_VECT(SCI_TXI, 0x520), INTC_VECT(SCI_TEI, 0x540),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
+       INTC_VECT(SCI, 0x4e0), INTC_VECT(SCI, 0x500),
+       INTC_VECT(SCI, 0x520), INTC_VECT(SCI, 0x540),
        INTC_VECT(WDT, 0x560),
-       INTC_VECT(REF_RCMI, 0x580),
-       INTC_VECT(REF_ROVI, 0x5a0),
+       INTC_VECT(REF, 0x580),
+       INTC_VECT(REF, 0x5a0),
 #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
     defined(CONFIG_CPU_SUBTYPE_SH7709)
        /* IRQ0->5 are handled in setup-sh3.c */
-       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
-       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
+       INTC_VECT(DMAC, 0x800), INTC_VECT(DMAC, 0x820),
+       INTC_VECT(DMAC, 0x840), INTC_VECT(DMAC, 0x860),
        INTC_VECT(ADC_ADI, 0x980),
-       INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920),
-       INTC_VECT(SCIF2_BRI, 0x940), INTC_VECT(SCIF2_TXI, 0x960),
+       INTC_VECT(SCIF2, 0x900), INTC_VECT(SCIF2, 0x920),
+       INTC_VECT(SCIF2, 0x940), INTC_VECT(SCIF2, 0x960),
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
     defined(CONFIG_CPU_SUBTYPE_SH7709)
        INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
-       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
-       INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
+       INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
+       INTC_VECT(SCIF0, 0x8c0), INTC_VECT(SCIF0, 0x8e0),
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7707)
        INTC_VECT(LCDC, 0x9a0),
@@ -71,16 +63,6 @@ static struct intc_vect vectors[] __initdata = {
 #endif
 };
 
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
-       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
-       INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
-       INTC_GROUP(SCI, SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
-};
-
 static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
        { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
@@ -101,7 +83,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
 #endif
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, NULL,
                         NULL, prio_registers, NULL);
 
 static struct resource rtc_resources[] = {
@@ -111,14 +93,6 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] =   {
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] =   {
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] =   {
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
@@ -136,7 +110,7 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xfffffe80,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCI,
-               .irqs           = { 23, 24, 25, 0 },
+               .irqs           = { 23, 23, 23, 0 },
        },
 #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
@@ -145,7 +119,7 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xa4000150,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 56, 57, 59, 58 },
+               .irqs           = { 56, 56, 56, 56 },
        },
 #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
@@ -154,7 +128,7 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xa4000140,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_IRDA,
-               .irqs           = { 52, 53, 55, 54 },
+               .irqs           = { 52, 52, 52, 52 },
        },
 #endif
        {
index 77eee481de474fc23d2c2d7b387ff29758d8ba59..335098b66e2f6771a3934aa5babc08adc35dc552 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH3 Setup code for SH7710, SH7712
  *
- *  Copyright (C) 2006, 2007  Paul Mundt
+ *  Copyright (C) 2006 - 2009  Paul Mundt
  *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -20,59 +20,40 @@ enum {
 
        /* interrupt sources */
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
-       DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
-       DMAC_DEI4, DMAC_DEI5,
-       IPSEC,
+       DMAC1, SCIF0, SCIF1, DMAC2, IPSEC,
        EDMAC0, EDMAC1, EDMAC2,
-       SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI,
-       SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI,
-       TMU0, TMU1, TMU2,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT,
-       REF,
+       SIOF0, SIOF1,
 
-       /* interrupt groups */
-       RTC, DMAC1, SCIF0, SCIF1, DMAC2, SIOF0, SIOF1,
+       TMU0, TMU1, TMU2,
+       RTC, WDT, REF,
 };
 
 static struct intc_vect vectors[] __initdata = {
        /* IRQ0->5 are handled in setup-sh3.c */
-       INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820),
-       INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860),
-       INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
-       INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
-       INTC_VECT(SCIF1_ERI, 0x900), INTC_VECT(SCIF1_RXI, 0x920),
-       INTC_VECT(SCIF1_BRI, 0x940), INTC_VECT(SCIF1_TXI, 0x960),
-       INTC_VECT(DMAC_DEI4, 0xb80), INTC_VECT(DMAC_DEI5, 0xba0),
+       INTC_VECT(DMAC1, 0x800), INTC_VECT(DMAC1, 0x820),
+       INTC_VECT(DMAC1, 0x840), INTC_VECT(DMAC1, 0x860),
+       INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
+       INTC_VECT(SCIF0, 0x8c0), INTC_VECT(SCIF0, 0x8e0),
+       INTC_VECT(SCIF1, 0x900), INTC_VECT(SCIF1, 0x920),
+       INTC_VECT(SCIF1, 0x940), INTC_VECT(SCIF1, 0x960),
+       INTC_VECT(DMAC2, 0xb80), INTC_VECT(DMAC2, 0xba0),
 #ifdef CONFIG_CPU_SUBTYPE_SH7710
        INTC_VECT(IPSEC, 0xbe0),
 #endif
        INTC_VECT(EDMAC0, 0xc00), INTC_VECT(EDMAC1, 0xc20),
        INTC_VECT(EDMAC2, 0xc40),
-       INTC_VECT(SIOF0_ERI, 0xe00), INTC_VECT(SIOF0_TXI, 0xe20),
-       INTC_VECT(SIOF0_RXI, 0xe40), INTC_VECT(SIOF0_CCI, 0xe60),
-       INTC_VECT(SIOF1_ERI, 0xe80), INTC_VECT(SIOF1_TXI, 0xea0),
-       INTC_VECT(SIOF1_RXI, 0xec0), INTC_VECT(SIOF1_CCI, 0xee0),
+       INTC_VECT(SIOF0, 0xe00), INTC_VECT(SIOF0, 0xe20),
+       INTC_VECT(SIOF0, 0xe40), INTC_VECT(SIOF0, 0xe60),
+       INTC_VECT(SIOF1, 0xe80), INTC_VECT(SIOF1, 0xea0),
+       INTC_VECT(SIOF1, 0xec0), INTC_VECT(SIOF1, 0xee0),
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
        INTC_VECT(TMU2, 0x440),
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
        INTC_VECT(WDT, 0x560),
        INTC_VECT(REF, 0x580),
 };
 
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(DMAC1, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
-       INTC_GROUP(DMAC2, DMAC_DEI4, DMAC_DEI5),
-       INTC_GROUP(SIOF0, SIOF0_ERI, SIOF0_TXI, SIOF0_RXI, SIOF0_CCI),
-       INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI),
-};
-
 static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
        { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
@@ -85,7 +66,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xa4080006, 0, 16, 4, /* IPRI */ { 0, 0, SIOF1 } },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, NULL,
                         NULL, prio_registers, NULL);
 
 static struct resource rtc_resources[] = {
@@ -98,14 +79,6 @@ static struct resource rtc_resources[] = {
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] =   {
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] =   {
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
 };
 
 static struct sh_rtc_platform_info rtc_info = {
@@ -127,12 +100,12 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xa4400000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 52, 53, 55, 54 },
+               .irqs           = { 52, 52, 52, 52 },
        }, {
                .mapbase        = 0xa4410000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 56, 57, 59, 58 },
+               .irqs           = { 56, 56, 56, 56 },
        }, {
 
                .flags = 0,
index f807a21b066c629e8e4ea636aa3021ffeddccae1..003874a2fd2a1b191303d91f5708966e286380a1 100644 (file)
@@ -2,6 +2,7 @@
  * SH7720 Setup
  *
  *  Copyright (C) 2007  Markus Brunner, Mark Jonas
+ *  Copyright (C) 2009  Paul Mundt
  *
  *  Based on arch/sh/kernel/cpu/sh4/setup-sh7750.c:
  *
@@ -26,17 +27,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
+               /* Shared Period/Carry/Alarm IRQ */
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
@@ -150,62 +141,49 @@ enum {
        UNUSED = 0,
 
        /* interrupt sources */
-       TMU0, TMU1, TMU2, RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT, REF_RCMI, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
+       TMU0, TMU1, TMU2, RTC,
+       WDT, REF_RCMI, SIM,
        IRQ0, IRQ1, IRQ2, IRQ3,
        USBF_SPD, TMU_SUNI, IRQ5, IRQ4,
-       DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3, LCDC, SSL,
-       ADC, DMAC2_DEI4, DMAC2_DEI5, USBFI0, USBFI1, CMT,
+       DMAC1, LCDC, SSL,
+       ADC, DMAC2, USBFI, CMT,
        SCIF0, SCIF1,
-       PINT07, PINT815, TPU0, TPU1, TPU2, TPU3, IIC,
-       SIOF0, SIOF1, MMCI0, MMCI1, MMCI2, MMCI3, PCC,
+       PINT07, PINT815, TPU, IIC,
+       SIOF0, SIOF1, MMC, PCC,
        USBHI, AFEIF,
        H_UDI,
-       /* interrupt groups */
-       TMU, RTC, SIM, DMAC1, USBFI, DMAC2, USB, TPU, MMC,
 };
 
 static struct intc_vect vectors[] __initdata = {
        /* IRQ0->5 are handled in setup-sh3.c */
        INTC_VECT(TMU0, 0x400),       INTC_VECT(TMU1, 0x420),
-       INTC_VECT(TMU2, 0x440),       INTC_VECT(RTC_ATI, 0x480),
-       INTC_VECT(RTC_PRI, 0x4a0),    INTC_VECT(RTC_CUI, 0x4c0),
-       INTC_VECT(SIM_ERI, 0x4e0),    INTC_VECT(SIM_RXI, 0x500),
-       INTC_VECT(SIM_TXI, 0x520),    INTC_VECT(SIM_TEND, 0x540),
+       INTC_VECT(TMU2, 0x440),       INTC_VECT(RTC, 0x480),
+       INTC_VECT(RTC, 0x4a0),        INTC_VECT(RTC, 0x4c0),
+       INTC_VECT(SIM, 0x4e0),        INTC_VECT(SIM, 0x500),
+       INTC_VECT(SIM, 0x520),        INTC_VECT(SIM, 0x540),
        INTC_VECT(WDT, 0x560),        INTC_VECT(REF_RCMI, 0x580),
        /* H_UDI cannot be masked */  INTC_VECT(TMU_SUNI, 0x6c0),
-       INTC_VECT(USBF_SPD, 0x6e0),   INTC_VECT(DMAC1_DEI0, 0x800),
-       INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840),
-       INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900),
+       INTC_VECT(USBF_SPD, 0x6e0),   INTC_VECT(DMAC1, 0x800),
+       INTC_VECT(DMAC1, 0x820),      INTC_VECT(DMAC1, 0x840),
+       INTC_VECT(DMAC1, 0x860),      INTC_VECT(LCDC, 0x900),
 #if defined(CONFIG_CPU_SUBTYPE_SH7720)
        INTC_VECT(SSL, 0x980),
 #endif
-       INTC_VECT(USBFI0, 0xa20),     INTC_VECT(USBFI1, 0xa40),
+       INTC_VECT(USBFI, 0xa20),      INTC_VECT(USBFI, 0xa40),
        INTC_VECT(USBHI, 0xa60),
-       INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0),
+       INTC_VECT(DMAC2, 0xb80),      INTC_VECT(DMAC2, 0xba0),
        INTC_VECT(ADC, 0xbe0),        INTC_VECT(SCIF0, 0xc00),
        INTC_VECT(SCIF1, 0xc20),      INTC_VECT(PINT07, 0xc80),
        INTC_VECT(PINT815, 0xca0),    INTC_VECT(SIOF0, 0xd00),
-       INTC_VECT(SIOF1, 0xd20),      INTC_VECT(TPU0, 0xd80),
-       INTC_VECT(TPU1, 0xda0),       INTC_VECT(TPU2, 0xdc0),
-       INTC_VECT(TPU3, 0xde0),       INTC_VECT(IIC, 0xe00),
-       INTC_VECT(MMCI0, 0xe80),      INTC_VECT(MMCI1, 0xea0),
-       INTC_VECT(MMCI2, 0xec0),      INTC_VECT(MMCI3, 0xee0),
+       INTC_VECT(SIOF1, 0xd20),      INTC_VECT(TPU, 0xd80),
+       INTC_VECT(TPU, 0xda0),        INTC_VECT(TPU, 0xdc0),
+       INTC_VECT(TPU, 0xde0),        INTC_VECT(IIC, 0xe00),
+       INTC_VECT(MMC, 0xe80),        INTC_VECT(MMC, 0xea0),
+       INTC_VECT(MMC, 0xec0),        INTC_VECT(MMC, 0xee0),
        INTC_VECT(CMT, 0xf00),        INTC_VECT(PCC, 0xf60),
        INTC_VECT(AFEIF, 0xfe0),
 };
 
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(TMU, TMU0, TMU1, TMU2),
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
-       INTC_GROUP(DMAC1, DMAC1_DEI0, DMAC1_DEI1, DMAC1_DEI2, DMAC1_DEI3),
-       INTC_GROUP(USBFI, USBFI0, USBFI1),
-       INTC_GROUP(DMAC2, DMAC2_DEI4, DMAC2_DEI5),
-       INTC_GROUP(TPU, TPU0, TPU1, TPU2, TPU3),
-       INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3),
-};
-
 static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
        { 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
@@ -219,7 +197,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
        { 0xA4080008UL, 0, 16, 4, /* IPRJ */ { 0, USBHI, 0, AFEIF } },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, NULL,
                NULL, prio_registers, NULL);
 
 void __init plat_irq_setup(void)
diff --git a/arch/sh/kernel/cpu/sh3/swsusp.S b/arch/sh/kernel/cpu/sh3/swsusp.S
new file mode 100644 (file)
index 0000000..0114542
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * arch/sh/kernel/cpu/sh3/swsusp.S
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+
+#define k0     r0
+#define k1     r1
+#define k2     r2
+#define k3     r3
+#define k4     r4
+
+! swsusp_arch_resume()
+! - copy restore_pblist pages
+! - restore registers from swsusp_arch_regs_cpu0
+
+ENTRY(swsusp_arch_resume)
+       mov.l   1f, r15
+       mov.l   2f, r4
+       mov.l   @r4, r4
+
+swsusp_copy_loop:
+       mov     r4, r0
+       cmp/eq  #0, r0
+       bt      swsusp_restore_regs
+
+       mov.l   @(PBE_ADDRESS, r4), r2
+       mov.l   @(PBE_ORIG_ADDRESS, r4), r5
+
+       mov     #(PAGE_SIZE >> 10), r3
+       shll8   r3
+       shlr2   r3 /* PAGE_SIZE / 16 */
+swsusp_copy_page:
+       dt      r3
+       mov.l   @r2+,r1   /*  16n+0 */
+       mov.l   r1,@r5
+       add     #4,r5
+       mov.l   @r2+,r1   /*  16n+4 */
+       mov.l   r1,@r5
+       add     #4,r5
+       mov.l   @r2+,r1   /*  16n+8 */
+       mov.l   r1,@r5
+       add     #4,r5
+       mov.l   @r2+,r1   /*  16n+12 */
+       mov.l   r1,@r5
+       bf/s    swsusp_copy_page
+        add    #4,r5
+
+       bra     swsusp_copy_loop
+        mov.l  @(PBE_NEXT, r4), r4
+
+swsusp_restore_regs:
+       ! BL=0: R7->R0 is bank0
+       mov.l   3f, r8
+       mov.l   4f, r5
+       jsr     @r5
+        nop
+
+       ! BL=1: R7->R0 is bank1
+       lds     k2, pr
+       ldc     k3, ssr
+
+       mov.l   @r15+, r0
+       mov.l   @r15+, r1
+       mov.l   @r15+, r2
+       mov.l   @r15+, r3
+       mov.l   @r15+, r4
+       mov.l   @r15+, r5
+       mov.l   @r15+, r6
+       mov.l   @r15+, r7
+
+       rte
+        nop
+       ! BL=0: R7->R0 is bank0
+
+       .align  2
+1:     .long   swsusp_arch_regs_cpu0
+2:     .long   restore_pblist
+3:     .long   0x20000000 ! RB=1
+4:     .long   restore_regs
+
+! swsusp_arch_suspend()
+! - prepare pc for resume, return from function without swsusp_save on resume
+! - save registers in swsusp_arch_regs_cpu0
+! - call swsusp_save write suspend image
+
+ENTRY(swsusp_arch_suspend)
+       sts     pr, r0          ! save pr in r0
+       mov     r15, r2         ! save sp in r2
+       mov     r8, r5          ! save r8 in r5
+       stc     sr, r1
+       ldc     r1, ssr         ! save sr in ssr
+       mov.l   1f, r1
+       ldc     r1, spc         ! setup pc value for resuming
+       mov.l   5f, r15         ! use swsusp_arch_regs_cpu0 as stack
+       mov.l   6f, r3
+       add     r3, r15         ! save from top of structure
+
+       ! BL=0: R7->R0 is bank0
+       mov.l   2f, r3          ! get new SR value for bank1
+       mov     #0, r4
+       mov.l   7f, r1
+       jsr     @r1             ! switch to bank1 and save bank1 r7->r0
+        not    r4, r4
+
+       ! BL=1: R7->R0 is bank1
+       stc     r2_bank, k0     ! fetch old sp from r2_bank0
+       mov.l   3f, k4          ! SR bits to clear in k4
+       mov.l   8f, k1
+       jsr     @k1             ! switch to bank0 and save all regs
+        stc    r0_bank, k3     ! fetch old pr from r0_bank0
+
+       ! BL=0: R7->R0 is bank0
+       mov     r2, r15         ! restore old sp
+       mov     r5, r8          ! restore old r8
+       stc     ssr, r1
+       ldc     r1, sr          ! restore old sr
+       lds     r0, pr          ! restore old pr
+       mov.l   4f, r0
+       jmp     @r0
+        nop
+
+swsusp_call_save:
+       mov     r2, r15         ! restore old sp
+       mov     r5, r8          ! restore old r8
+       lds     r0, pr          ! restore old pr
+       rts
+        mov    #0, r0
+
+       .align  2
+1:     .long   swsusp_call_save
+2:     .long   0x20000000 ! RB=1
+3:     .long   0xdfffffff ! RB=0
+4:     .long   swsusp_save
+5:     .long   swsusp_arch_regs_cpu0
+6:     .long   SWSUSP_ARCH_REGS_SIZE
+7:     .long   save_low_regs
+8:     .long   save_regs
index d608557c7a3f7246dee6797d2c1836230a29a8ff..203b18347b831e2d2b63d3b0df06f2f7d7af1b20 100644 (file)
@@ -5,6 +5,7 @@
 obj-y  := probe.o common.o
 common-y       += $(addprefix ../sh3/, entry.o ex.o)
 
+obj-$(CONFIG_HIBERNATION)              += $(addprefix ../sh3/, swsusp.o)
 obj-$(CONFIG_SH_FPU)                   += fpu.o softfloat.o
 obj-$(CONFIG_SH_STORE_QUEUES)          += sq.o
 
index 2e42572b1b119aa832c50a104d8f4fd5c1fe0acf..3d3a3c4425a94a6edad883271ae771e617a13c1b 100644 (file)
@@ -129,6 +129,13 @@ int __init detect_cpu_and_cache_system(void)
                boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
                                          CPU_HAS_LLSC;
                break;
+       case 0x4004:
+               boot_cpu_data.type = CPU_SH7786;
+               boot_cpu_data.icache.ways = 4;
+               boot_cpu_data.dcache.ways = 4;
+               boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+                       CPU_HAS_LLSC | CPU_HAS_PTEAEX;
+               break;
        case 0x3008:
                boot_cpu_data.icache.ways = 4;
                boot_cpu_data.dcache.ways = 4;
index ec884039b914cb5d424a544da7c41bd67e8a655b..a1c80d909cd634c1b8a2459c5d239fa600c8285b 100644 (file)
@@ -21,17 +21,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
+               /* Shared Period/Carry/Alarm IRQ */
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
@@ -50,13 +40,13 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCI,
-               .irqs           = { 23, 24, 25, 0 },
+               .irqs           = { 23, 23, 23, 0 },
        }, {
 #endif
                .mapbase        = 0xffe80000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 40, 41, 43, 42 },
+               .irqs           = { 40, 40, 40, 40 },
        }, {
                .flags = 0,
        }
@@ -87,43 +77,27 @@ enum {
 
        /* interrupt sources */
        IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
-       HUDI, GPIOI,
-       DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
-       DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
-       DMAC_DMAE,
+       HUDI, GPIOI, DMAC,
        PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
        PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
-       TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
-       SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
-       WDT,
-       REF_RCMI, REF_ROVI,
+       TMU3, TMU4, TMU0, TMU1, TMU2, RTC, SCI1, SCIF, WDT, REF,
 
        /* interrupt groups */
-       DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
+       PCIC1,
 };
 
 static struct intc_vect vectors[] __initdata = {
        INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
        INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
-       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
-       INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
-       INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
-       INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
-       INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
+       INTC_VECT(SCI1, 0x4e0), INTC_VECT(SCI1, 0x500),
+       INTC_VECT(SCI1, 0x520), INTC_VECT(SCI1, 0x540),
+       INTC_VECT(SCIF, 0x700), INTC_VECT(SCIF, 0x720),
+       INTC_VECT(SCIF, 0x740), INTC_VECT(SCIF, 0x760),
        INTC_VECT(WDT, 0x560),
-       INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
-};
-
-static struct intc_group groups[] __initdata = {
-       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
-       INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
-       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+       INTC_VECT(REF, 0x580), INTC_VECT(REF, 0x5a0),
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -136,7 +110,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
                                                 PCIC1, PCIC0_PCISERR } },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, NULL,
                         NULL, prio_registers, NULL);
 
 /* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
@@ -145,39 +119,28 @@ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
        defined(CONFIG_CPU_SUBTYPE_SH7751) || \
        defined(CONFIG_CPU_SUBTYPE_SH7091)
 static struct intc_vect vectors_dma4[] __initdata = {
-       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
-       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
-       INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma4[] __initdata = {
-       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
-                  DMAC_DMTE3, DMAC_DMAE),
+       INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+       INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+       INTC_VECT(DMAC, 0x6c0),
 };
 
 static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
-                        vectors_dma4, groups_dma4,
+                        vectors_dma4, NULL,
                         NULL, prio_registers, NULL);
 #endif
 
 /* SH7750R and SH7751R both have 8-channel DMA controllers */
 #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
 static struct intc_vect vectors_dma8[] __initdata = {
-       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
-       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
-       INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
-       INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
-       INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma8[] __initdata = {
-       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
-                  DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
-                  DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+       INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+       INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+       INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
+       INTC_VECT(DMAC, 0x7c0), INTC_VECT(DMAC, 0x7e0),
+       INTC_VECT(DMAC, 0x6c0),
 };
 
 static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
-                        vectors_dma8, groups_dma8,
+                        vectors_dma8, NULL,
                         NULL, prio_registers, NULL);
 #endif
 
index 8e344ec5847e4e21d1d60de374dcd8871c9caae9..1a92361feeb9db95e50e4f97d5d06a076a66f28e 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7763)        += setup-sh7763.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7770)       += setup-sh7770.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += setup-sh7780.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += setup-sh7785.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += setup-sh7786.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
@@ -21,6 +22,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7763)    := clock-sh7763.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7770)     := clock-sh7770.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7780)     := clock-sh7780.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7785)     := clock-sh7785.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7786)     := clock-sh7786.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7722.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7722.o
@@ -31,6 +33,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SHX3)      := clock-shx3.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7722)    := pinmux-sh7722.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)    := pinmux-sh7723.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)    := pinmux-sh7785.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)    := pinmux-sh7786.o
 
 obj-y                  += $(clock-y)
 obj-$(CONFIG_SMP)      += $(smp-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
new file mode 100644 (file)
index 0000000..f84a9c1
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7786.c
+ *
+ * SH7786 support for the clock framework
+ *
+ * Copyright (C) 2008, 2009  Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7785
+ *  Copyright (C) 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4, 1 };
+static int sfc_divisors[] = { 1, 1, 4, 1 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1,
+                            24, 32, 1, 1, 1, 1, 1, 1 };
+static int mfc_divisors[] = { 1, 1, 4, 1 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1,
+                             24, 32, 1, 48, 1, 1, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+       clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f];
+}
+
+static struct clk_ops sh7786_master_clk_ops = {
+       .init           = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inl(FRQMR1) & 0x000f);
+       clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7786_module_clk_ops = {
+       .recalc         = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+       int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
+       clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops sh7786_bus_clk_ops = {
+       .recalc         = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+       int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
+       clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7786_cpu_clk_ops = {
+       .recalc         = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7786_clk_ops[] = {
+       &sh7786_master_clk_ops,
+       &sh7786_module_clk_ops,
+       &sh7786_bus_clk_ops,
+       &sh7786_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+       if (idx < ARRAY_SIZE(sh7786_clk_ops))
+               *ops = sh7786_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+       int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
+       clk->rate = clk->parent->rate / sfc_divisors[idx];
+}
+
+static struct clk_ops sh7786_shyway_clk_ops = {
+       .recalc         = shyway_clk_recalc,
+};
+
+static struct clk sh7786_shyway_clk = {
+       .name           = "shyway_clk",
+       .flags          = CLK_ALWAYS_ENABLED,
+       .ops            = &sh7786_shyway_clk_ops,
+};
+
+static void ddr_clk_recalc(struct clk *clk)
+{
+       int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
+       clk->rate = clk->parent->rate / mfc_divisors[idx];
+}
+
+static struct clk_ops sh7786_ddr_clk_ops = {
+       .recalc         = ddr_clk_recalc,
+};
+
+static struct clk sh7786_ddr_clk = {
+       .name           = "ddr_clk",
+       .flags          = CLK_ALWAYS_ENABLED,
+       .ops            = &sh7786_ddr_clk_ops,
+};
+
+/*
+ * Additional SH7786-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *sh7786_onchip_clocks[] = {
+       &sh7786_shyway_clk,
+       &sh7786_ddr_clk,
+};
+
+static int __init sh7786_clk_init(void)
+{
+       struct clk *clk = clk_get(NULL, "master_clk");
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) {
+               struct clk *clkp = sh7786_onchip_clocks[i];
+
+               clkp->parent = clk;
+               clk_register(clkp);
+               clk_enable(clkp);
+       }
+
+       /*
+        * Now that we have the rest of the clocks registered, we need to
+        * force the parent clock to propagate so that these clocks will
+        * automatically figure out their rate. We cheat by handing the
+        * parent clock its current rate and forcing child propagation.
+        */
+       clk_set_rate(clk, clk_get_rate(clk));
+
+       clk_put(clk);
+
+       return 0;
+}
+arch_initcall(sh7786_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c
new file mode 100644 (file)
index 0000000..373b344
--- /dev/null
@@ -0,0 +1,950 @@
+/*
+ * SH7786 Pinmux
+ *
+ * Copyright (C) 2008, 2009  Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ *  Based on SH7785 pinmux
+ *
+ *  Copyright (C) 2008  Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7786.h>
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+       PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+       PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+       PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+       PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+       PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+       PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+       PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+       PE7_DATA, PE6_DATA,
+       PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+       PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+       PG7_DATA, PG6_DATA, PG5_DATA,
+       PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+       PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+       PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+       PJ3_DATA, PJ2_DATA, PJ1_DATA,
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+       PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+       PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+       PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+       PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+       PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+       PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+       PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+       PE7_IN, PE6_IN,
+       PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+       PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+       PG7_IN, PG6_IN, PG5_IN,
+       PH7_IN, PH6_IN, PH5_IN, PH4_IN,
+       PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+       PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+       PJ3_IN, PJ2_IN, PJ1_IN,
+       PINMUX_INPUT_END,
+
+       PINMUX_INPUT_PULLUP_BEGIN,
+       PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+       PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+       PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+       PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+       PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+       PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+       PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+       PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+       PE7_IN_PU, PE6_IN_PU,
+       PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+       PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+       PG7_IN_PU, PG6_IN_PU, PG5_IN_PU,
+       PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
+       PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+       PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
+       PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU,
+       PINMUX_INPUT_PULLUP_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+       PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+       PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+       PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+       PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+       PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+       PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+       PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+       PE7_OUT, PE6_OUT,
+       PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+       PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+       PG7_OUT, PG6_OUT, PG5_OUT,
+       PH7_OUT, PH6_OUT, PH5_OUT, PH4_OUT,
+       PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+       PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+       PJ3_OUT, PJ2_OUT, PJ1_OUT,
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+       PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+       PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+       PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+       PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+       PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+       PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+       PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+       PE7_FN, PE6_FN,
+       PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+       PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+       PG7_FN, PG6_FN, PG5_FN,
+       PH7_FN, PH6_FN, PH5_FN, PH4_FN,
+       PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+       PJ7_FN, PJ6_FN, PJ5_FN, PJ4_FN,
+       PJ3_FN, PJ2_FN, PJ1_FN,
+       P1MSEL14_0, P1MSEL14_1,
+       P1MSEL13_0, P1MSEL13_1,
+       P1MSEL12_0, P1MSEL12_1,
+       P1MSEL11_0, P1MSEL11_1,
+       P1MSEL10_0, P1MSEL10_1,
+       P1MSEL9_0, P1MSEL9_1,
+       P1MSEL8_0, P1MSEL8_1,
+       P1MSEL7_0, P1MSEL7_1,
+       P1MSEL6_0, P1MSEL6_1,
+       P1MSEL5_0, P1MSEL5_1,
+       P1MSEL4_0, P1MSEL4_1,
+       P1MSEL3_0, P1MSEL3_1,
+       P1MSEL2_0, P1MSEL2_1,
+       P1MSEL1_0, P1MSEL1_1,
+       P1MSEL0_0, P1MSEL0_1,
+
+       P2MSEL15_0, P2MSEL15_1,
+       P2MSEL14_0, P2MSEL14_1,
+       P2MSEL13_0, P2MSEL13_1,
+       P2MSEL12_0, P2MSEL12_1,
+       P2MSEL11_0, P2MSEL11_1,
+       P2MSEL10_0, P2MSEL10_1,
+       P2MSEL9_0, P2MSEL9_1,
+       P2MSEL8_0, P2MSEL8_1,
+       P2MSEL7_0, P2MSEL7_1,
+       P2MSEL6_0, P2MSEL6_1,
+       P2MSEL5_0, P2MSEL5_1,
+       P2MSEL4_0, P2MSEL4_1,
+       P2MSEL3_0, P2MSEL3_1,
+       P2MSEL2_0, P2MSEL2_1,
+       P2MSEL1_0, P2MSEL1_1,
+       P2MSEL0_0, P2MSEL0_1,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+       CDE_MARK,
+       ETH_MAGIC_MARK,
+       DISP_MARK,
+       ETH_LINK_MARK,
+       DR5_MARK,
+       ETH_TX_ER_MARK,
+       DR4_MARK,
+       ETH_TX_EN_MARK,
+       DR3_MARK,
+       ETH_TXD3_MARK,
+       DR2_MARK,
+       ETH_TXD2_MARK,
+       DR1_MARK,
+       ETH_TXD1_MARK,
+       DR0_MARK,
+       ETH_TXD0_MARK,
+
+       VSYNC_MARK,
+       HSPI_CLK_MARK,
+       ODDF_MARK,
+       HSPI_CS_MARK,
+       DG5_MARK,
+       ETH_MDIO_MARK,
+       DG4_MARK,
+       ETH_RX_CLK_MARK,
+       DG3_MARK,
+       ETH_MDC_MARK,
+       DG2_MARK,
+       ETH_COL_MARK,
+       DG1_MARK,
+       ETH_TX_CLK_MARK,
+       DG0_MARK,
+       ETH_CRS_MARK,
+
+       DCLKIN_MARK,
+       HSPI_RX_MARK,
+       HSYNC_MARK,
+       HSPI_TX_MARK,
+       DB5_MARK,
+       ETH_RXD3_MARK,
+       DB4_MARK,
+       ETH_RXD2_MARK,
+       DB3_MARK,
+       ETH_RXD1_MARK,
+       DB2_MARK,
+       ETH_RXD0_MARK,
+       DB1_MARK,
+       ETH_RX_DV_MARK,
+       DB0_MARK,
+       ETH_RX_ER_MARK,
+
+       DCLKOUT_MARK,
+       SCIF1_SLK_MARK,
+       SCIF1_RXD_MARK,
+       SCIF1_TXD_MARK,
+       DACK1_MARK,
+       BACK_MARK,
+       FALE_MARK,
+       DACK0_MARK,
+       FCLE_MARK,
+       DREQ1_MARK,
+       BREQ_MARK,
+       USB_OVC1_MARK,
+       DREQ0_MARK,
+       USB_OVC0_MARK,
+
+       USB_PENC1_MARK,
+       USB_PENC0_MARK,
+
+       HAC1_SDOUT_MARK,
+       SSI1_SDATA_MARK,
+       SDIF1CMD_MARK,
+       HAC1_SDIN_MARK,
+       SSI1_SCK_MARK,
+       SDIF1CD_MARK,
+       HAC1_SYNC_MARK,
+       SSI1_WS_MARK,
+       SDIF1WP_MARK,
+       HAC1_BITCLK_MARK,
+       SSI1_CLK_MARK,
+       SDIF1CLK_MARK,
+       HAC0_SDOUT_MARK,
+       SSI0_SDATA_MARK,
+       SDIF1D3_MARK,
+       HAC0_SDIN_MARK,
+       SSI0_SCK_MARK,
+       SDIF1D2_MARK,
+       HAC0_SYNC_MARK,
+       SSI0_WS_MARK,
+       SDIF1D1_MARK,
+       HAC0_BITCLK_MARK,
+       SSI0_CLK_MARK,
+       SDIF1D0_MARK,
+
+       SCIF3_SCK_MARK,
+       SSI2_SDATA_MARK,
+       SCIF3_RXD_MARK,
+       TCLK_MARK,
+       SSI2_SCK_MARK,
+       SCIF3_TXD_MARK,
+       HAC_RES_MARK,
+       SSI2_WS_MARK,
+
+       DACK3_MARK,
+       SDIF0CMD_MARK,
+       DACK2_MARK,
+       SDIF0CD_MARK,
+       DREQ3_MARK,
+       SDIF0WP_MARK,
+       SCIF0_CTS_MARK,
+       DREQ2_MARK,
+       SDIF0CLK_MARK,
+       SCIF0_RTS_MARK,
+       IRL7_MARK,
+       SDIF0D3_MARK,
+       SCIF0_SCK_MARK,
+       IRL6_MARK,
+       SDIF0D2_MARK,
+       SCIF0_RXD_MARK,
+       IRL5_MARK,
+       SDIF0D1_MARK,
+       SCIF0_TXD_MARK,
+       IRL4_MARK,
+       SDIF0D0_MARK,
+
+       SCIF5_SCK_MARK,
+       FRB_MARK,
+       SCIF5_RXD_MARK,
+       IOIS16_MARK,
+       SCIF5_TXD_MARK,
+       CE2B_MARK,
+       DRAK3_MARK,
+       CE2A_MARK,
+       SCIF4_SCK_MARK,
+       DRAK2_MARK,
+       SSI3_WS_MARK,
+       SCIF4_RXD_MARK,
+       DRAK1_MARK,
+       SSI3_SDATA_MARK,
+       FSTATUS_MARK,
+       SCIF4_TXD_MARK,
+       DRAK0_MARK,
+       SSI3_SCK_MARK,
+       FSE_MARK,
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+       /* PA GPIO */
+       PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+       PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+       PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+       PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+       PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+       PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+       PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+       PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+       /* PB GPIO */
+       PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+       PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+       PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+       PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+       PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+       PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+       PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+       PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+       /* PC GPIO */
+       PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+       PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+       PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+       PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+       PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+       PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+       PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+       PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+       /* PD GPIO */
+       PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+       PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+       PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+       PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+       PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+       PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+       PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+       PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+       /* PE GPIO */
+       PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+       PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+
+       /* PF GPIO */
+       PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+       PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+       PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+       PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+       PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+       PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+       PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+       PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+       /* PG GPIO */
+       PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+       PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+       PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+
+       /* PH GPIO */
+       PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
+       PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
+       PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+       PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+       PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+       PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+       PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+       PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+       /* PJ GPIO */
+       PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
+       PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
+       PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
+       PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
+       PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
+       PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
+       PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
+
+       /* PA FN */
+       PINMUX_MARK_BEGIN,
+       PINMUX_DATA(CDE_MARK,           P1MSEL2_0, PA7_FN),
+       PINMUX_DATA(DISP_MARK,          P1MSEL2_0, PA6_FN),
+       PINMUX_DATA(DR5_MARK,           P1MSEL2_0, PA5_FN),
+       PINMUX_DATA(DR4_MARK,           P1MSEL2_0, PA4_FN),
+       PINMUX_DATA(DR3_MARK,           P1MSEL2_0, PA3_FN),
+       PINMUX_DATA(DR2_MARK,           P1MSEL2_0, PA2_FN),
+       PINMUX_DATA(DR1_MARK,           P1MSEL2_0, PA1_FN),
+       PINMUX_DATA(DR0_MARK,           P1MSEL2_0, PA0_FN),
+       PINMUX_DATA(ETH_MAGIC_MARK,     P1MSEL2_1, PA7_FN),
+       PINMUX_DATA(ETH_LINK_MARK,      P1MSEL2_1, PA6_FN),
+       PINMUX_DATA(ETH_TX_ER_MARK,     P1MSEL2_1, PA5_FN),
+       PINMUX_DATA(ETH_TX_EN_MARK,     P1MSEL2_1, PA4_FN),
+       PINMUX_DATA(ETH_TXD3_MARK,      P1MSEL2_1, PA3_FN),
+       PINMUX_DATA(ETH_TXD2_MARK,      P1MSEL2_1, PA2_FN),
+       PINMUX_DATA(ETH_TXD1_MARK,      P1MSEL2_1, PA1_FN),
+       PINMUX_DATA(ETH_TXD0_MARK,      P1MSEL2_1, PA0_FN),
+
+       /* PB FN */
+       PINMUX_DATA(VSYNC_MARK,         P1MSEL3_0, PB7_FN),
+       PINMUX_DATA(ODDF_MARK,          P1MSEL3_0, PB6_FN),
+       PINMUX_DATA(DG5_MARK,           P1MSEL2_0, PB5_FN),
+       PINMUX_DATA(DG4_MARK,           P1MSEL2_0, PB4_FN),
+       PINMUX_DATA(DG3_MARK,           P1MSEL2_0, PB3_FN),
+       PINMUX_DATA(DG2_MARK,           P1MSEL2_0, PB2_FN),
+       PINMUX_DATA(DG1_MARK,           P1MSEL2_0, PB1_FN),
+       PINMUX_DATA(DG0_MARK,           P1MSEL2_0, PB0_FN),
+       PINMUX_DATA(HSPI_CLK_MARK,      P1MSEL3_1, PB7_FN),
+       PINMUX_DATA(HSPI_CS_MARK,       P1MSEL3_1, PB6_FN),
+       PINMUX_DATA(ETH_MDIO_MARK,      P1MSEL2_1, PB5_FN),
+       PINMUX_DATA(ETH_RX_CLK_MARK,    P1MSEL2_1, PB4_FN),
+       PINMUX_DATA(ETH_MDC_MARK,       P1MSEL2_1, PB3_FN),
+       PINMUX_DATA(ETH_COL_MARK,       P1MSEL2_1, PB2_FN),
+       PINMUX_DATA(ETH_TX_CLK_MARK,    P1MSEL2_1, PB1_FN),
+       PINMUX_DATA(ETH_CRS_MARK,       P1MSEL2_1, PB0_FN),
+
+       /* PC FN */
+       PINMUX_DATA(DCLKIN_MARK,        P1MSEL3_0, PC7_FN),
+       PINMUX_DATA(HSYNC_MARK,         P1MSEL3_0, PC6_FN),
+       PINMUX_DATA(DB5_MARK,           P1MSEL2_0, PC5_FN),
+       PINMUX_DATA(DB4_MARK,           P1MSEL2_0, PC4_FN),
+       PINMUX_DATA(DB3_MARK,           P1MSEL2_0, PC3_FN),
+       PINMUX_DATA(DB2_MARK,           P1MSEL2_0, PC2_FN),
+       PINMUX_DATA(DB1_MARK,           P1MSEL2_0, PC1_FN),
+       PINMUX_DATA(DB0_MARK,           P1MSEL2_0, PC0_FN),
+
+       PINMUX_DATA(HSPI_RX_MARK,       P1MSEL3_1, PC7_FN),
+       PINMUX_DATA(HSPI_TX_MARK,       P1MSEL3_1, PC6_FN),
+       PINMUX_DATA(ETH_RXD3_MARK,      P1MSEL2_1, PC5_FN),
+       PINMUX_DATA(ETH_RXD2_MARK,      P1MSEL2_1, PC4_FN),
+       PINMUX_DATA(ETH_RXD1_MARK,      P1MSEL2_1, PC3_FN),
+       PINMUX_DATA(ETH_RXD0_MARK,      P1MSEL2_1, PC2_FN),
+       PINMUX_DATA(ETH_RX_DV_MARK,     P1MSEL2_1, PC1_FN),
+       PINMUX_DATA(ETH_RX_ER_MARK,     P1MSEL2_1, PC0_FN),
+
+       /* PD FN */
+       PINMUX_DATA(DCLKOUT_MARK,       PD7_FN),
+       PINMUX_DATA(SCIF1_SLK_MARK,     PD6_FN),
+       PINMUX_DATA(SCIF1_RXD_MARK,     PD5_FN),
+       PINMUX_DATA(SCIF1_TXD_MARK,     PD4_FN),
+       PINMUX_DATA(DACK1_MARK,         P1MSEL13_1, P1MSEL12_0, PD3_FN),
+       PINMUX_DATA(BACK_MARK,          P1MSEL13_0, P1MSEL12_1, PD3_FN),
+       PINMUX_DATA(FALE_MARK,          P1MSEL13_0, P1MSEL12_0, PD3_FN),
+       PINMUX_DATA(DACK0_MARK,         P1MSEL14_1, PD2_FN),
+       PINMUX_DATA(FCLE_MARK,          P1MSEL14_0, PD2_FN),
+       PINMUX_DATA(DREQ1_MARK,         P1MSEL10_0, P1MSEL9_1, PD1_FN),
+       PINMUX_DATA(BREQ_MARK,          P1MSEL10_1, P1MSEL9_0, PD1_FN),
+       PINMUX_DATA(USB_OVC1_MARK,      P1MSEL10_0, P1MSEL9_0, PD1_FN),
+       PINMUX_DATA(DREQ0_MARK,         P1MSEL11_1, PD0_FN),
+       PINMUX_DATA(USB_OVC0_MARK,      P1MSEL11_0, PD0_FN),
+
+       /* PE FN */
+       PINMUX_DATA(USB_PENC1_MARK,     PE7_FN),
+       PINMUX_DATA(USB_PENC0_MARK,     PE6_FN),
+
+       /* PF FN */
+       PINMUX_DATA(HAC1_SDOUT_MARK,    P2MSEL15_0, P2MSEL14_0, PF7_FN),
+       PINMUX_DATA(HAC1_SDIN_MARK,     P2MSEL15_0, P2MSEL14_0, PF6_FN),
+       PINMUX_DATA(HAC1_SYNC_MARK,     P2MSEL15_0, P2MSEL14_0, PF5_FN),
+       PINMUX_DATA(HAC1_BITCLK_MARK,   P2MSEL15_0, P2MSEL14_0, PF4_FN),
+       PINMUX_DATA(HAC0_SDOUT_MARK,    P2MSEL13_0, P2MSEL12_0, PF3_FN),
+       PINMUX_DATA(HAC0_SDIN_MARK,     P2MSEL13_0, P2MSEL12_0, PF2_FN),
+       PINMUX_DATA(HAC0_SYNC_MARK,     P2MSEL13_0, P2MSEL12_0, PF1_FN),
+       PINMUX_DATA(HAC0_BITCLK_MARK,   P2MSEL13_0, P2MSEL12_0, PF0_FN),
+       PINMUX_DATA(SSI1_SDATA_MARK,    P2MSEL15_0, P2MSEL14_1, PF7_FN),
+       PINMUX_DATA(SSI1_SCK_MARK,      P2MSEL15_0, P2MSEL14_1, PF6_FN),
+       PINMUX_DATA(SSI1_WS_MARK,       P2MSEL15_0, P2MSEL14_1, PF5_FN),
+       PINMUX_DATA(SSI1_CLK_MARK,      P2MSEL15_0, P2MSEL14_1, PF4_FN),
+       PINMUX_DATA(SSI0_SDATA_MARK,    P2MSEL13_0, P2MSEL12_1, PF3_FN),
+       PINMUX_DATA(SSI0_SCK_MARK,      P2MSEL13_0, P2MSEL12_1, PF2_FN),
+       PINMUX_DATA(SSI0_WS_MARK,       P2MSEL13_0, P2MSEL12_1, PF1_FN),
+       PINMUX_DATA(SSI0_CLK_MARK,      P2MSEL13_0, P2MSEL12_1, PF0_FN),
+       PINMUX_DATA(SDIF1CMD_MARK,      P2MSEL15_1, P2MSEL14_0, PF7_FN),
+       PINMUX_DATA(SDIF1CD_MARK,       P2MSEL15_1, P2MSEL14_0, PF6_FN),
+       PINMUX_DATA(SDIF1WP_MARK,       P2MSEL15_1, P2MSEL14_0, PF5_FN),
+       PINMUX_DATA(SDIF1CLK_MARK,      P2MSEL15_1, P2MSEL14_0, PF4_FN),
+       PINMUX_DATA(SDIF1D3_MARK,       P2MSEL13_1, P2MSEL12_0, PF3_FN),
+       PINMUX_DATA(SDIF1D2_MARK,       P2MSEL13_1, P2MSEL12_0, PF2_FN),
+       PINMUX_DATA(SDIF1D1_MARK,       P2MSEL13_1, P2MSEL12_0, PF1_FN),
+       PINMUX_DATA(SDIF1D0_MARK,       P2MSEL13_1, P2MSEL12_0, PF0_FN),
+
+       /* PG FN */
+       PINMUX_DATA(SCIF3_SCK_MARK,     P1MSEL8_0, PG7_FN),
+       PINMUX_DATA(SSI2_SDATA_MARK,    P1MSEL8_1, PG7_FN),
+       PINMUX_DATA(SCIF3_RXD_MARK,     P1MSEL7_0, P1MSEL6_0, PG6_FN),
+       PINMUX_DATA(SSI2_SCK_MARK,      P1MSEL7_1, P1MSEL6_0, PG6_FN),
+       PINMUX_DATA(TCLK_MARK,          P1MSEL7_0, P1MSEL6_1, PG6_FN),
+       PINMUX_DATA(SCIF3_TXD_MARK,     P1MSEL5_0, P1MSEL4_0, PG5_FN),
+       PINMUX_DATA(SSI2_WS_MARK,       P1MSEL5_1, P1MSEL4_0, PG5_FN),
+       PINMUX_DATA(HAC_RES_MARK,       P1MSEL5_0, P1MSEL4_1, PG5_FN),
+
+       /* PH FN */
+       PINMUX_DATA(DACK3_MARK,         P2MSEL4_0, PH7_FN),
+       PINMUX_DATA(SDIF0CMD_MARK,      P2MSEL4_1, PH7_FN),
+       PINMUX_DATA(DACK2_MARK,         P2MSEL4_0, PH6_FN),
+       PINMUX_DATA(SDIF0CD_MARK,       P2MSEL4_1, PH6_FN),
+       PINMUX_DATA(DREQ3_MARK,         P2MSEL4_0, PH5_FN),
+       PINMUX_DATA(SDIF0WP_MARK,       P2MSEL4_1, PH5_FN),
+       PINMUX_DATA(DREQ2_MARK,         P2MSEL3_0, P2MSEL2_1, PH4_FN),
+       PINMUX_DATA(SDIF0CLK_MARK,      P2MSEL3_1, P2MSEL2_0, PH4_FN),
+       PINMUX_DATA(SCIF0_CTS_MARK,     P2MSEL3_0, P2MSEL2_0, PH4_FN),
+       PINMUX_DATA(SDIF0D3_MARK,       P2MSEL1_1, P2MSEL0_0, PH3_FN),
+       PINMUX_DATA(SCIF0_RTS_MARK,     P2MSEL1_0, P2MSEL0_0, PH3_FN),
+       PINMUX_DATA(IRL7_MARK,          P2MSEL1_0, P2MSEL0_1, PH3_FN),
+       PINMUX_DATA(SDIF0D2_MARK,       P2MSEL1_1, P2MSEL0_0, PH2_FN),
+       PINMUX_DATA(SCIF0_SCK_MARK,     P2MSEL1_0, P2MSEL0_0, PH2_FN),
+       PINMUX_DATA(IRL6_MARK,          P2MSEL1_0, P2MSEL0_1, PH2_FN),
+       PINMUX_DATA(SDIF0D1_MARK,       P2MSEL1_1, P2MSEL0_0, PH1_FN),
+       PINMUX_DATA(SCIF0_RXD_MARK,     P2MSEL1_0, P2MSEL0_0, PH1_FN),
+       PINMUX_DATA(IRL5_MARK,          P2MSEL1_0, P2MSEL0_1, PH1_FN),
+       PINMUX_DATA(SDIF0D0_MARK,       P2MSEL1_1, P2MSEL0_0, PH0_FN),
+       PINMUX_DATA(SCIF0_TXD_MARK,     P2MSEL1_0, P2MSEL0_0, PH0_FN),
+       PINMUX_DATA(IRL4_MARK,          P2MSEL1_0, P2MSEL0_1, PH0_FN),
+
+       /* PJ FN */
+       PINMUX_DATA(SCIF5_SCK_MARK,     P2MSEL11_1, PJ7_FN),
+       PINMUX_DATA(FRB_MARK,           P2MSEL11_0, PJ7_FN),
+       PINMUX_DATA(SCIF5_RXD_MARK,     P2MSEL10_0, PJ6_FN),
+       PINMUX_DATA(IOIS16_MARK,        P2MSEL10_1, PJ6_FN),
+       PINMUX_DATA(SCIF5_TXD_MARK,     P2MSEL10_0, PJ5_FN),
+       PINMUX_DATA(CE2B_MARK,          P2MSEL10_1, PJ5_FN),
+       PINMUX_DATA(DRAK3_MARK,         P2MSEL7_0, PJ4_FN),
+       PINMUX_DATA(CE2A_MARK,          P2MSEL7_1, PJ4_FN),
+       PINMUX_DATA(SCIF4_SCK_MARK,     P2MSEL9_0, P2MSEL8_0, PJ3_FN),
+       PINMUX_DATA(DRAK2_MARK,         P2MSEL9_0, P2MSEL8_1, PJ3_FN),
+       PINMUX_DATA(SSI3_WS_MARK,       P2MSEL9_1, P2MSEL8_0, PJ3_FN),
+       PINMUX_DATA(SCIF4_RXD_MARK,     P2MSEL6_1, P2MSEL5_0, PJ2_FN),
+       PINMUX_DATA(DRAK1_MARK,         P2MSEL6_0, P2MSEL5_1, PJ2_FN),
+       PINMUX_DATA(FSTATUS_MARK,       P2MSEL6_0, P2MSEL5_0, PJ2_FN),
+       PINMUX_DATA(SSI3_SDATA_MARK,    P2MSEL6_1, P2MSEL5_1, PJ2_FN),
+       PINMUX_DATA(SCIF4_TXD_MARK,     P2MSEL6_1, P2MSEL5_0, PJ1_FN),
+       PINMUX_DATA(DRAK0_MARK,         P2MSEL6_0, P2MSEL5_1, PJ1_FN),
+       PINMUX_DATA(FSE_MARK,           P2MSEL6_0, P2MSEL5_0, PJ1_FN),
+       PINMUX_DATA(SSI3_SCK_MARK,      P2MSEL6_1, P2MSEL5_1, PJ1_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+       /* PA */
+       PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+       PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+       PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+       PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+       PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+       PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+       PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+       PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+       /* PB */
+       PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+       PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+       PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+       PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+       PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+       PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+       PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+       PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+       /* PC */
+       PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+       PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+       PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+       PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+       PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+       PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+       PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+       PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+       /* PD */
+       PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+       PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+       PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+       PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+       PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+       PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+       PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+       PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+       /* PE */
+       PINMUX_GPIO(GPIO_PE5, PE7_DATA),
+       PINMUX_GPIO(GPIO_PE4, PE6_DATA),
+
+       /* PF */
+       PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+       PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+       PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+       PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+       PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+       PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+       PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+       PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+       /* PG */
+       PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+       PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+       PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+
+       /* PH */
+       PINMUX_GPIO(GPIO_PH7, PH7_DATA),
+       PINMUX_GPIO(GPIO_PH6, PH6_DATA),
+       PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+       PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+       PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+       PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+       PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+       PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+       /* PJ */
+       PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+       PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+       PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+       PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+       PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+       PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+       PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+
+       /* FN */
+       PINMUX_GPIO(GPIO_FN_CDE,                CDE_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_MAGIC,          ETH_MAGIC_MARK),
+       PINMUX_GPIO(GPIO_FN_DISP,               DISP_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_LINK,           ETH_LINK_MARK),
+       PINMUX_GPIO(GPIO_FN_DR5,                DR5_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TX_ER,          ETH_TX_ER_MARK),
+       PINMUX_GPIO(GPIO_FN_DR4,                DR4_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TX_EN,          ETH_TX_EN_MARK),
+       PINMUX_GPIO(GPIO_FN_DR3,                DR3_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TXD3,           ETH_TXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_DR2,                DR2_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TXD2,           ETH_TXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_DR1,                DR1_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TXD1,           ETH_TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_DR0,                DR0_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TXD0,           ETH_TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_VSYNC,              VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_HSPI_CLK,           HSPI_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_ODDF,               ODDF_MARK),
+       PINMUX_GPIO(GPIO_FN_HSPI_CS,            HSPI_CS_MARK),
+       PINMUX_GPIO(GPIO_FN_DG5,                DG5_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_MDIO,           ETH_MDIO_MARK),
+       PINMUX_GPIO(GPIO_FN_DG4,                DG4_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RX_CLK,         ETH_RX_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_DG3,                DG3_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_MDC,            ETH_MDC_MARK),
+       PINMUX_GPIO(GPIO_FN_DG2,                DG2_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_COL,            ETH_COL_MARK),
+       PINMUX_GPIO(GPIO_FN_DG1,                DG1_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_TX_CLK,         ETH_TX_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_DG0,                DG0_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_CRS,            ETH_CRS_MARK),
+       PINMUX_GPIO(GPIO_FN_DCLKIN,             DCLKIN_MARK),
+       PINMUX_GPIO(GPIO_FN_HSPI_RX,            HSPI_RX_MARK),
+       PINMUX_GPIO(GPIO_FN_HSYNC,              HSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_HSPI_TX,            HSPI_TX_MARK),
+       PINMUX_GPIO(GPIO_FN_DB5,                DB5_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RXD3,           ETH_RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_DB4,                DB4_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RXD2,           ETH_RXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_DB3,                DB3_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RXD1,           ETH_RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_DB2,                DB2_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RXD0,           ETH_RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_DB1,                DB1_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RX_DV,          ETH_RX_DV_MARK),
+       PINMUX_GPIO(GPIO_FN_DB0,                DB0_MARK),
+       PINMUX_GPIO(GPIO_FN_ETH_RX_ER,          ETH_RX_ER_MARK),
+       PINMUX_GPIO(GPIO_FN_DCLKOUT,            DCLKOUT_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF1_SLK,          SCIF1_SLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF1_RXD,          SCIF1_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF1_TXD,          SCIF1_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK1,              DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_BACK,               BACK_MARK),
+       PINMUX_GPIO(GPIO_FN_FALE,               FALE_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK0,              DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_FCLE,               FCLE_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ1,              DREQ1_MARK),
+       PINMUX_GPIO(GPIO_FN_BREQ,               BREQ_MARK),
+       PINMUX_GPIO(GPIO_FN_USB_OVC1,           USB_OVC1_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ0,              DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_USB_OVC0,           USB_OVC0_MARK),
+       PINMUX_GPIO(GPIO_FN_USB_PENC1,          USB_PENC1_MARK),
+       PINMUX_GPIO(GPIO_FN_USB_PENC0,          USB_PENC0_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC1_SDOUT,         HAC1_SDOUT_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI1_SDATA,         SSI1_SDATA_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1CMD,           SDIF1CMD_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC1_SDIN,          HAC1_SDIN_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI1_SCK,           SSI1_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1CD,            SDIF1CD_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC1_SYNC,          HAC1_SYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI1_WS,            SSI1_WS_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1WP,            SDIF1WP_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC1_BITCLK,        HAC1_BITCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI1_CLK,           SSI1_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1CLK,           SDIF1CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC0_SDOUT,         HAC0_SDOUT_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI0_SDATA,         SSI0_SDATA_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1D3,            SDIF1D3_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC0_SDIN,          HAC0_SDIN_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI0_SCK,           SSI0_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1D2,            SDIF1D2_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC0_SYNC,          HAC0_SYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI0_WS,            SSI0_WS_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1D1,            SDIF1D1_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC0_BITCLK,        HAC0_BITCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI0_CLK,           SSI0_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF1D0,            SDIF1D0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_SCK,          SCIF3_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI2_SDATA,         SSI2_SDATA_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_RXD,          SCIF3_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLK,               TCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI2_SCK,           SSI2_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF3_TXD,          SCIF3_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_HAC_RES,            HAC_RES_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI2_WS,            SSI2_WS_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK3,              DACK3_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0CMD,           SDIF0CMD_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK2,              DACK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0CD,            SDIF0CD_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ3,              DREQ3_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0WP,            SDIF0WP_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_CTS,          SCIF0_CTS_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ2,              DREQ2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0CLK,           SDIF0CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_RTS,          SCIF0_RTS_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL7,               IRL7_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0D3,            SDIF0D3_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_SCK,          SCIF0_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL6,               IRL6_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0D2,            SDIF0D2_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_RXD,          SCIF0_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL5,               IRL5_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0D1,            SDIF0D1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF0_TXD,          SCIF0_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_IRL4,               IRL4_MARK),
+       PINMUX_GPIO(GPIO_FN_SDIF0D0,            SDIF0D0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF5_SCK,          SCIF5_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FRB,                FRB_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF5_RXD,          SCIF5_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_IOIS16,             IOIS16_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF5_TXD,          SCIF5_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2B,               CE2B_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK3,              DRAK3_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2A,               CE2A_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF4_SCK,          SCIF4_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK2,              DRAK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI3_WS,            SSI3_WS_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF4_RXD,          SCIF4_RXD_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK1,              DRAK1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI3_SDATA,         SSI3_SDATA_MARK),
+       PINMUX_GPIO(GPIO_FN_FSTATUS,            FSTATUS_MARK),
+       PINMUX_GPIO(GPIO_FN_SCIF4_TXD,          SCIF4_TXD_MARK),
+       PINMUX_GPIO(GPIO_FN_DRAK0,              DRAK0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSI3_SCK,           SSI3_SCK_MARK),
+       PINMUX_GPIO(GPIO_FN_FSE,                FSE_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("PACR", 0xffcc0000, 16, 2) {
+               PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+               PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+               PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+               PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+               PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+               PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+               PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+               PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PBCR", 0xffcc0002, 16, 2) {
+               PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+               PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+               PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+               PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+               PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+               PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+               PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+               PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PCCR", 0xffcc0004, 16, 2) {
+               PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+               PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+               PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+               PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+               PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+               PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+               PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+               PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PDCR", 0xffcc0006, 16, 2) {
+               PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+               PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+               PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+               PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+               PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+               PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+               PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+               PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PECR", 0xffcc0008, 16, 2) {
+               PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+               PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0, }
+       },
+       { PINMUX_CFG_REG("PFCR", 0xffcc000a, 16, 2) {
+               PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+               PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+               PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+               PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+               PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+               PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+               PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+               PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PGCR", 0xffcc000c, 16, 2) {
+               PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+               PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+               PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0, }
+       },
+       { PINMUX_CFG_REG("PHCR", 0xffcc000e, 16, 2) {
+               PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
+               PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
+               PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+               PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+               PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+               PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+               PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+               PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
+       },
+       { PINMUX_CFG_REG("PJCR", 0xffcc0010, 16, 2) {
+               PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
+               PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
+               PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
+               PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
+               PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
+               PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
+               PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
+               0, 0, 0, 0, }
+       },
+       { PINMUX_CFG_REG("P1MSELR", 0xffcc0080, 16, 1) {
+               0, 0,
+               P1MSEL14_0, P1MSEL14_1,
+               P1MSEL13_0, P1MSEL13_1,
+               P1MSEL12_0, P1MSEL12_1,
+               P1MSEL11_0, P1MSEL11_1,
+               P1MSEL10_0, P1MSEL10_1,
+               P1MSEL9_0,  P1MSEL9_1,
+               P1MSEL8_0,  P1MSEL8_1,
+               P1MSEL7_0,  P1MSEL7_1,
+               P1MSEL6_0,  P1MSEL6_1,
+               P1MSEL5_0,  P1MSEL5_1,
+               P1MSEL4_0,  P1MSEL4_1,
+               P1MSEL3_0,  P1MSEL3_1,
+               P1MSEL2_0,  P1MSEL2_1,
+               P1MSEL1_0,  P1MSEL1_1,
+               P1MSEL0_0,  P1MSEL0_1 }
+       },
+       { PINMUX_CFG_REG("P2MSELR", 0xffcc0082, 16, 1) {
+               P2MSEL15_0, P2MSEL15_1,
+               P2MSEL14_0, P2MSEL14_1,
+               P2MSEL13_0, P2MSEL13_1,
+               P2MSEL12_0, P2MSEL12_1,
+               P2MSEL11_0, P2MSEL11_1,
+               P2MSEL10_0, P2MSEL10_1,
+               P2MSEL9_0,  P2MSEL9_1,
+               P2MSEL8_0,  P2MSEL8_1,
+               P2MSEL7_0,  P2MSEL7_1,
+               P2MSEL6_0,  P2MSEL6_1,
+               P2MSEL5_0,  P2MSEL5_1,
+               P2MSEL4_0,  P2MSEL4_1,
+               P2MSEL3_0,  P2MSEL3_1,
+               P2MSEL2_0,  P2MSEL2_1,
+               P2MSEL1_0,  P2MSEL1_1,
+               P2MSEL0_0,  P2MSEL0_1 }
+       },
+       {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PADR", 0xffcc0020, 8) {
+               PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+               PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
+       },
+       { PINMUX_DATA_REG("PBDR", 0xffcc0022, 8) {
+               PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+               PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
+       },
+       { PINMUX_DATA_REG("PCDR", 0xffcc0024, 8) {
+               PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+               PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+       },
+       { PINMUX_DATA_REG("PDDR", 0xffcc0026, 8) {
+               PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+               PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+       },
+       { PINMUX_DATA_REG("PEDR", 0xffcc0028, 8) {
+               PE7_DATA, PE6_DATA,
+               0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_DATA_REG("PFDR", 0xffcc002a, 8) {
+               PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+               PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+       },
+       { PINMUX_DATA_REG("PGDR", 0xffcc002c, 8) {
+               PG7_DATA, PG6_DATA, PG5_DATA, 0,
+               0, 0, 0, 0 }
+       },
+       { PINMUX_DATA_REG("PHDR", 0xffcc002e, 8) {
+               PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+               PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA }
+       },
+       { PINMUX_DATA_REG("PJDR", 0xffcc0030, 8) {
+               PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+               PJ3_DATA, PJ2_DATA, PJ1_DATA, 0 }
+       },
+       { },
+};
+
+static struct pinmux_info sh7786_pinmux_info = {
+       .name = "sh7786_pfc",
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+       .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_PA7,
+       .last_gpio = GPIO_FN_FSE,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+       return register_pinmux(&sh7786_pinmux_info);
+}
+
+arch_initcall(plat_pinmux_setup);
index 4ff4dc64520c1ed68dedd3f9b0de33a1cff8ece5..c1549382c87c01070b0467ea5771bfa25205a7ba 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic0_resources[] = {
@@ -140,6 +141,38 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -175,6 +208,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7343_devices[] __initdata = {
+       &cmt_device,
        &iic0_device,
        &iic1_device,
        &sci_device,
index 839ae97a7fd2de8e708bd7fa82f484d012edae42..93ecf8ed5c6c346a60c166624c9278a134de46ac 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic_resources[] = {
@@ -147,6 +148,38 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -167,6 +200,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7366_devices[] __initdata = {
+       &cmt_device,
        &iic_device,
        &sci_device,
        &usb_host_device,
index 5146afc156e0d3d6185c7ed9c63e4cd2430e8c92..0e5d204bc79287bf4fc00197a7b3e38593ddab1e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/mm.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -176,6 +177,38 @@ static struct platform_device jpu_device = {
        .num_resources  = ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -209,6 +242,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7722_devices[] __initdata = {
+       &cmt_device,
        &rtc_device,
        &usbf_device,
        &iic_device,
index 849770d780aed9e5b2de0479b32887c80f374ebf..5338dacbcfba7c00481cf5fe6424192cb07d8b9e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -100,6 +101,38 @@ static struct platform_device veu1_device = {
        .num_resources  = ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+       .name = "CMT",
+       .channel_offset = 0x60,
+       .timer_bit = 5,
+       .clk = "cmt0",
+       .clockevent_rating = 125,
+       .clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+       [0] = {
+               .name   = "CMT",
+               .start  = 0x044a0060,
+               .end    = 0x044a006b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 104,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt_platform_data,
+       },
+       .resource       = cmt_resources,
+       .num_resources  = ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -221,6 +254,7 @@ static struct platform_device iic_device = {
 };
 
 static struct platform_device *sh7723_devices[] __initdata = {
+       &cmt_device,
        &sci_device,
        &rtc_device,
        &iic_device,
index 3c5b629887a8e3a54fa2a0cb5a2b886e7e9271ee..bdf0f61ae1eddd436d1326f1cddfbe19d3bf26b7 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2006  Paul Mundt
  *  Copyright (C) 2007  Yoshihiro Shimoda
- *  Copyright (C) 2008  Nobuhiro Iwamatsu
+ *  Copyright (C) 2008, 2009  Nobuhiro Iwamatsu
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -22,18 +22,8 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
-               .start  = 20,
+               /* Shared Period/Carry/Alarm IRQ */
+               .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -50,17 +40,17 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 40, 41, 43, 42 },
+               .irqs           = { 40, 40, 40, 40 },
        }, {
                .mapbase        = 0xffe08000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 76, 77, 79, 78 },
+               .irqs           = { 76, 76, 76, 76 },
        }, {
                .mapbase        = 0xffe10000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 104, 105, 107, 106 },
+               .irqs           = { 104, 104, 104, 104 },
        }, {
                .flags = 0,
        }
@@ -148,93 +138,65 @@ enum {
        IRL_HHLL, IRL_HHLH, IRL_HHHL,
 
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
-       HUDI, LCDC,
-       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       DMAC0_DMINT4, DMAC0_DMINT5,
-       IIC0, IIC1,
-       CMT,
-       GEINT0, GEINT1, GEINT2,
-       HAC,
-       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
-       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
-       STIF0, STIF1,
-       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
-       SIOF0, SIOF1, SIOF2,
-       USBH, USBFI0, USBFI1,
-       TPU, PCC,
-       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
-       SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
+       RTC, WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI, LCDC, DMAC, SCIF0, IIC0, IIC1, CMT, GETHER, HAC,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD, PCIC5,
+       STIF0, STIF1, SCIF1, SIOF0, SIOF1, SIOF2,
+       USBH, USBF, TPU, PCC, MMCIF, SIM,
        TMU3, TMU4, TMU5, ADC, SSI0, SSI1, SSI2, SSI3,
-       SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
-       GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3,
+       SCIF2, GPIO,
 
        /* interrupt groups */
 
-       TMU012, TMU345, RTC, DMAC, SCIF0, GETHER, PCIC5,
-       SCIF1, USBF, MMCIF, SIM, SCIF2, GPIO,
+       TMU012, TMU345,
 };
 
 static struct intc_vect vectors[] __initdata = {
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
        INTC_VECT(WDT, 0x560), INTC_VECT(TMU0, 0x580),
        INTC_VECT(TMU1, 0x5a0), INTC_VECT(TMU2, 0x5c0),
        INTC_VECT(TMU2_TICPI, 0x5e0), INTC_VECT(HUDI, 0x600),
        INTC_VECT(LCDC, 0x620),
-       INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
-       INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
-       INTC_VECT(DMAC0_DMAE, 0x6c0),
-       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
-       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
-       INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+       INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+       INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+       INTC_VECT(DMAC, 0x6c0),
+       INTC_VECT(SCIF0, 0x700), INTC_VECT(SCIF0, 0x720),
+       INTC_VECT(SCIF0, 0x740), INTC_VECT(SCIF0, 0x760),
+       INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
        INTC_VECT(IIC0, 0x8A0), INTC_VECT(IIC1, 0x8C0),
-       INTC_VECT(CMT, 0x900), INTC_VECT(GEINT0, 0x920),
-       INTC_VECT(GEINT1, 0x940), INTC_VECT(GEINT2, 0x960),
+       INTC_VECT(CMT, 0x900), INTC_VECT(GETHER, 0x920),
+       INTC_VECT(GETHER, 0x940), INTC_VECT(GETHER, 0x960),
        INTC_VECT(HAC, 0x980),
        INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
        INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
-       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
-       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
-       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIC5, 0xaa0),
+       INTC_VECT(PCIC5, 0xac0), INTC_VECT(PCIC5, 0xae0),
+       INTC_VECT(PCIC5, 0xb00), INTC_VECT(PCIC5, 0xb20),
        INTC_VECT(STIF0, 0xb40), INTC_VECT(STIF1, 0xb60),
-       INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
-       INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+       INTC_VECT(SCIF1, 0xb80), INTC_VECT(SCIF1, 0xba0),
+       INTC_VECT(SCIF1, 0xbc0), INTC_VECT(SCIF1, 0xbe0),
        INTC_VECT(SIOF0, 0xc00), INTC_VECT(SIOF1, 0xc20),
-       INTC_VECT(USBH, 0xc60), INTC_VECT(USBFI0, 0xc80),
-       INTC_VECT(USBFI1, 0xca0),
+       INTC_VECT(USBH, 0xc60), INTC_VECT(USBF, 0xc80),
+       INTC_VECT(USBF, 0xca0),
        INTC_VECT(TPU, 0xcc0), INTC_VECT(PCC, 0xce0),
-       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
-       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
-       INTC_VECT(SIM_ERI, 0xd80), INTC_VECT(SIM_RXI, 0xda0),
-       INTC_VECT(SIM_TXI, 0xdc0), INTC_VECT(SIM_TEND, 0xde0),
+       INTC_VECT(MMCIF, 0xd00), INTC_VECT(MMCIF, 0xd20),
+       INTC_VECT(MMCIF, 0xd40), INTC_VECT(MMCIF, 0xd60),
+       INTC_VECT(SIM, 0xd80), INTC_VECT(SIM, 0xda0),
+       INTC_VECT(SIM, 0xdc0), INTC_VECT(SIM, 0xde0),
        INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
        INTC_VECT(TMU5, 0xe40), INTC_VECT(ADC, 0xe60),
        INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
        INTC_VECT(SSI2, 0xec0), INTC_VECT(SSI3, 0xee0),
-       INTC_VECT(SCIF2_ERI, 0xf00), INTC_VECT(SCIF2_RXI, 0xf20),
-       INTC_VECT(SCIF2_BRI, 0xf40), INTC_VECT(SCIF2_TXI, 0xf60),
-       INTC_VECT(GPIO_CH0, 0xf80), INTC_VECT(GPIO_CH1, 0xfa0),
-       INTC_VECT(GPIO_CH2, 0xfc0), INTC_VECT(GPIO_CH3, 0xfe0),
+       INTC_VECT(SCIF2, 0xf00), INTC_VECT(SCIF2, 0xf20),
+       INTC_VECT(SCIF2, 0xf40), INTC_VECT(SCIF2, 0xf60),
+       INTC_VECT(GPIO, 0xf80), INTC_VECT(GPIO, 0xfa0),
+       INTC_VECT(GPIO, 0xfc0), INTC_VECT(GPIO, 0xfe0),
 };
 
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
        INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-       INTC_GROUP(DMAC, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
-                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(GETHER, GEINT0, GEINT1, GEINT2),
-       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
-       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
-       INTC_GROUP(USBF, USBFI0, USBFI1),
-       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
-       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
-       INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
-       INTC_GROUP(GPIO, GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3),
 };
 
 static struct intc_mask_reg mask_registers[] __initdata = {
index fb8200cc74409db26b27051d12c2dc77e2da1dde..6f7227cd65bffb6933d8395a0267b540b9959c6e 100644 (file)
@@ -20,17 +20,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] = {
-               /* Period IRQ */
-               .start  = 21,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               /* Carry IRQ */
-               .start  = 22,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               /* Alarm IRQ */
+               /* Shared Period/Carry/Alarm IRQ */
                .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
@@ -48,12 +38,12 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 40, 41, 43, 42 },
+               .irqs           = { 40, 40, 40, 40 },
        }, {
                .mapbase        = 0xffe10000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 76, 77, 79, 78 },
+               .irqs           = { 76, 76, 76, 76 },
        }, {
                .flags = 0,
        }
@@ -90,82 +80,55 @@ enum {
        IRL_HHLL, IRL_HHLH, IRL_HHHL,
 
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
-       RTC_ATI, RTC_PRI, RTC_CUI,
-       WDT,
-       TMU0, TMU1, TMU2, TMU2_TICPI,
-       HUDI,
-       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       DMAC0_DMINT4, DMAC0_DMINT5, DMAC1_DMINT6, DMAC1_DMINT7,
-       CMT, HAC,
-       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
-       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
-       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
-       SIOF, HSPI,
-       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
-       DMAC1_DMINT8, DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11,
-       TMU3, TMU4, TMU5,
-       SSI,
-       FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
-       GPIOI0, GPIOI1, GPIOI2, GPIOI3,
+       RTC, WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI, DMAC0, SCIF0, DMAC1, CMT, HAC,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD, PCIC5,
+       SCIF1, SIOF, HSPI, MMCIF, TMU3, TMU4, TMU5, SSI, FLCTL, GPIO,
 
        /* interrupt groups */
 
-       RTC, TMU012, DMAC0, SCIF0, DMAC45, DMAC1,
-       PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
+       TMU012, TMU345,
 };
 
 static struct intc_vect vectors[] __initdata = {
-       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+       INTC_VECT(RTC, 0x4c0),
        INTC_VECT(WDT, 0x560),
        INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
        INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
        INTC_VECT(HUDI, 0x600),
-       INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
-       INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
-       INTC_VECT(DMAC0_DMAE, 0x6c0),
-       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
-       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
-       INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
-       INTC_VECT(DMAC1_DMINT6, 0x7c0), INTC_VECT(DMAC1_DMINT7, 0x7e0),
+       INTC_VECT(DMAC0, 0x640), INTC_VECT(DMAC0, 0x660),
+       INTC_VECT(DMAC0, 0x680), INTC_VECT(DMAC0, 0x6a0),
+       INTC_VECT(DMAC0, 0x6c0),
+       INTC_VECT(SCIF0, 0x700), INTC_VECT(SCIF0, 0x720),
+       INTC_VECT(SCIF0, 0x740), INTC_VECT(SCIF0, 0x760),
+       INTC_VECT(DMAC0, 0x780), INTC_VECT(DMAC0, 0x7a0),
+       INTC_VECT(DMAC1, 0x7c0), INTC_VECT(DMAC1, 0x7e0),
        INTC_VECT(CMT, 0x900), INTC_VECT(HAC, 0x980),
        INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
        INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
-       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
-       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
-       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
-       INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
-       INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIC5, 0xaa0),
+       INTC_VECT(PCIC5, 0xac0), INTC_VECT(PCIC5, 0xae0),
+       INTC_VECT(PCIC5, 0xb00), INTC_VECT(PCIC5, 0xb20),
+       INTC_VECT(SCIF1, 0xb80), INTC_VECT(SCIF1, 0xba0),
+       INTC_VECT(SCIF1, 0xbc0), INTC_VECT(SCIF1, 0xbe0),
        INTC_VECT(SIOF, 0xc00), INTC_VECT(HSPI, 0xc80),
-       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
-       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
-       INTC_VECT(DMAC1_DMINT8, 0xd80), INTC_VECT(DMAC1_DMINT9, 0xda0),
-       INTC_VECT(DMAC1_DMINT10, 0xdc0), INTC_VECT(DMAC1_DMINT11, 0xde0),
+       INTC_VECT(MMCIF, 0xd00), INTC_VECT(MMCIF, 0xd20),
+       INTC_VECT(MMCIF, 0xd40), INTC_VECT(MMCIF, 0xd60),
+       INTC_VECT(DMAC1, 0xd80), INTC_VECT(DMAC1, 0xda0),
+       INTC_VECT(DMAC1, 0xdc0), INTC_VECT(DMAC1, 0xde0),
        INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
        INTC_VECT(TMU5, 0xe40),
        INTC_VECT(SSI, 0xe80),
-       INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
-       INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
-       INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
-       INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+       INTC_VECT(FLCTL, 0xf00), INTC_VECT(FLCTL, 0xf20),
+       INTC_VECT(FLCTL, 0xf40), INTC_VECT(FLCTL, 0xf60),
+       INTC_VECT(GPIO, 0xf80), INTC_VECT(GPIO, 0xfa0),
+       INTC_VECT(GPIO, 0xfc0), INTC_VECT(GPIO, 0xfe0),
 };
 
 static struct intc_group groups[] __initdata = {
-       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
        INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
-       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
-                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
-                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
-       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
-       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
-       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
        INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
-       INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
-                  FLCTL_FLTRQ0, FLCTL_FLTRQ1),
-       INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
 };
 
 static struct intc_mask_reg mask_registers[] __initdata = {
index 30baa63b24c8e728b7d0763d36709938b8388cdc..d80802a49dbd1bd7c881ab572419f9ed9e9881ab 100644 (file)
@@ -20,18 +20,13 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffea0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 40, 41, 43, 42 },
+               .irqs           = { 40, 40, 40, 40 },
        }, {
                .mapbase        = 0xffeb0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 44, 45, 47, 46 },
-       },
-
-       /*
-        * The rest of these all have multiplexed IRQs
-        */
-       {
+               .irqs           = { 44, 44, 44, 44 },
+       }, {
                .mapbase        = 0xffec0000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
@@ -91,33 +86,19 @@ enum {
        IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
 
        IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
-       WDT,
-       TMU0, TMU1, TMU2, TMU2_TICPI,
-       HUDI,
-       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3,
-       DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE,
-       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
-       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
-       DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8, DMAC1_DMINT9,
-       DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE,
-       HSPI,
+       WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI, DMAC0, SCIF0, SCIF1, DMAC1, HSPI,
        SCIF2, SCIF3, SCIF4, SCIF5,
-       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
-       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
-       SIOF,
-       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
-       DU,
-       GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD, PCIC5,
+       SIOF, MMCIF, DU, GDTA,
        TMU3, TMU4, TMU5,
        SSI0, SSI1,
        HAC0, HAC1,
-       FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
-       GPIOI0, GPIOI1, GPIOI2, GPIOI3,
+       FLCTL, GPIO,
 
        /* interrupt groups */
 
-       TMU012, DMAC0, SCIF0, SCIF1, DMAC1,
-       PCIC5, MMCIF, GDTA, TMU345, FLCTL, GPIO
+       TMU012, TMU345
 };
 
 static struct intc_vect vectors[] __initdata = {
@@ -125,57 +106,45 @@ static struct intc_vect vectors[] __initdata = {
        INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
        INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
        INTC_VECT(HUDI, 0x600),
-       INTC_VECT(DMAC0_DMINT0, 0x620), INTC_VECT(DMAC0_DMINT1, 0x640),
-       INTC_VECT(DMAC0_DMINT2, 0x660), INTC_VECT(DMAC0_DMINT3, 0x680),
-       INTC_VECT(DMAC0_DMINT4, 0x6a0), INTC_VECT(DMAC0_DMINT5, 0x6c0),
-       INTC_VECT(DMAC0_DMAE, 0x6e0),
-       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
-       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
-       INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
-       INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
-       INTC_VECT(DMAC1_DMINT6, 0x880), INTC_VECT(DMAC1_DMINT7, 0x8a0),
-       INTC_VECT(DMAC1_DMINT8, 0x8c0), INTC_VECT(DMAC1_DMINT9, 0x8e0),
-       INTC_VECT(DMAC1_DMINT10, 0x900), INTC_VECT(DMAC1_DMINT11, 0x920),
-       INTC_VECT(DMAC1_DMAE, 0x940),
+       INTC_VECT(DMAC0, 0x620), INTC_VECT(DMAC0, 0x640),
+       INTC_VECT(DMAC0, 0x660), INTC_VECT(DMAC0, 0x680),
+       INTC_VECT(DMAC0, 0x6a0), INTC_VECT(DMAC0, 0x6c0),
+       INTC_VECT(DMAC0, 0x6e0),
+       INTC_VECT(SCIF0, 0x700), INTC_VECT(SCIF0, 0x720),
+       INTC_VECT(SCIF0, 0x740), INTC_VECT(SCIF0, 0x760),
+       INTC_VECT(SCIF1, 0x780), INTC_VECT(SCIF1, 0x7a0),
+       INTC_VECT(SCIF1, 0x7c0), INTC_VECT(SCIF1, 0x7e0),
+       INTC_VECT(DMAC1, 0x880), INTC_VECT(DMAC1, 0x8a0),
+       INTC_VECT(DMAC1, 0x8c0), INTC_VECT(DMAC1, 0x8e0),
+       INTC_VECT(DMAC1, 0x900), INTC_VECT(DMAC1, 0x920),
+       INTC_VECT(DMAC1, 0x940),
        INTC_VECT(HSPI, 0x960),
        INTC_VECT(SCIF2, 0x980), INTC_VECT(SCIF3, 0x9a0),
        INTC_VECT(SCIF4, 0x9c0), INTC_VECT(SCIF5, 0x9e0),
        INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
        INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
-       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
-       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
-       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIC5, 0xaa0),
+       INTC_VECT(PCIC5, 0xac0), INTC_VECT(PCIC5, 0xae0),
+       INTC_VECT(PCIC5, 0xb00), INTC_VECT(PCIC5, 0xb20),
        INTC_VECT(SIOF, 0xc00),
-       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
-       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+       INTC_VECT(MMCIF, 0xd00), INTC_VECT(MMCIF, 0xd20),
+       INTC_VECT(MMCIF, 0xd40), INTC_VECT(MMCIF, 0xd60),
        INTC_VECT(DU, 0xd80),
-       INTC_VECT(GDTA_GACLI, 0xda0), INTC_VECT(GDTA_GAMCI, 0xdc0),
-       INTC_VECT(GDTA_GAERI, 0xde0),
+       INTC_VECT(GDTA, 0xda0), INTC_VECT(GDTA, 0xdc0),
+       INTC_VECT(GDTA, 0xde0),
        INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
        INTC_VECT(TMU5, 0xe40),
        INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
        INTC_VECT(HAC0, 0xec0), INTC_VECT(HAC1, 0xee0),
-       INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
-       INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
-       INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
-       INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+       INTC_VECT(FLCTL, 0xf00), INTC_VECT(FLCTL, 0xf20),
+       INTC_VECT(FLCTL, 0xf40), INTC_VECT(FLCTL, 0xf60),
+       INTC_VECT(GPIO, 0xf80), INTC_VECT(GPIO, 0xfa0),
+       INTC_VECT(GPIO, 0xfc0), INTC_VECT(GPIO, 0xfe0),
 };
 
 static struct intc_group groups[] __initdata = {
        INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
-       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
-                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
-       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
-       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
-       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
-                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11, DMAC1_DMAE),
-       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
-       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
-       INTC_GROUP(GDTA, GDTA_GACLI, GDTA_GAMCI, GDTA_GAERI),
        INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
-       INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
-                  FLCTL_FLTRQ0, FLCTL_FLTRQ1),
-       INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
 };
 
 static struct intc_mask_reg mask_registers[] __initdata = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
new file mode 100644 (file)
index 0000000..5a47e1c
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * SH7786 Setup
+ *
+ * Copyright (C) 2009  Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7785 Setup
+ *
+ *  Copyright (C) 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <asm/mmzone.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = 0xffea0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 40, 41, 43, 42 },
+       },
+       /*
+        * The rest of these all have multiplexed IRQs
+        */
+       {
+               .mapbase        = 0xffeb0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 44, 44, 44, 44 },
+       }, {
+               .mapbase        = 0xffec0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 50, 50, 50, 50 },
+       }, {
+               .mapbase        = 0xffed0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 51, 51, 51, 51 },
+       }, {
+               .mapbase        = 0xffee0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 52, 52, 52, 52 },
+       }, {
+               .mapbase        = 0xffef0000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 53, 53, 53, 53 },
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct resource usb_ohci_resources[] = {
+       [0] = {
+               .start  = 0xffe70400,
+               .end    = 0xffe704ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 77,
+               .end    = 77,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 usb_ohci_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device usb_ohci_device = {
+       .name           = "sh_ohci",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = &usb_ohci_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(usb_ohci_resources),
+       .resource       = usb_ohci_resources,
+};
+
+static struct platform_device *sh7786_devices[] __initdata = {
+       &sci_device,
+       &usb_ohci_device,
+};
+
+
+/*
+ * Please call this function if your platform board
+ * use external clock for USB
+ * */
+#define USBCTL0                0xffe70858
+#define CLOCK_MODE_MASK 0xffffff7f
+#define EXT_CLOCK_MODE  0x00000080
+void __init sh7786_usb_use_exclock(void)
+{
+       u32 val = __raw_readl(USBCTL0) & CLOCK_MODE_MASK;
+       __raw_writel(val | EXT_CLOCK_MODE, USBCTL0);
+}
+
+#define USBINITREG1    0xffe70094
+#define USBINITREG2    0xffe7009c
+#define USBINITVAL1    0x00ff0040
+#define USBINITVAL2    0x00000001
+
+#define USBPCTL1       0xffe70804
+#define USBST          0xffe70808
+#define PHY_ENB                0x00000001
+#define PLL_ENB                0x00000002
+#define PHY_RST                0x00000004
+#define ACT_PLL_STATUS 0xc0000000
+static void __init sh7786_usb_setup(void)
+{
+       int i = 1000000;
+
+       /*
+        * USB initial settings
+        *
+        * The following settings are necessary
+        * for using the USB modules.
+        *
+        * see "USB Inital Settings" for detail
+        */
+       __raw_writel(USBINITVAL1, USBINITREG1);
+       __raw_writel(USBINITVAL2, USBINITREG2);
+
+       /*
+        * Set the PHY and PLL enable bit
+        */
+       __raw_writel(PHY_ENB | PLL_ENB, USBPCTL1);
+       while (i-- &&
+              ((__raw_readl(USBST) & ACT_PLL_STATUS) != ACT_PLL_STATUS))
+               cpu_relax();
+
+       if (i) {
+               /* Set the PHY RST bit */
+               __raw_writel(PHY_ENB | PLL_ENB | PHY_RST, USBPCTL1);
+               printk(KERN_INFO "sh7786 usb setup done\n");
+       }
+}
+
+static int __init sh7786_devices_setup(void)
+{
+       sh7786_usb_setup();
+       return platform_add_devices(sh7786_devices,
+                                   ARRAY_SIZE(sh7786_devices));
+}
+device_initcall(sh7786_devices_setup);
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+
+       IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+       IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+       IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+       IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+       IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+       IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+       IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+       IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
+
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       WDT,
+       TMU0_0, TMU0_1, TMU0_2, TMU0_3,
+       TMU1_0, TMU1_1, TMU1_2,
+       DMAC0_0, DMAC0_1, DMAC0_2, DMAC0_3, DMAC0_4, DMAC0_5, DMAC0_6,
+       HUDI1, HUDI0,
+       DMAC1_0, DMAC1_1, DMAC1_2, DMAC1_3,
+       HPB_0, HPB_1, HPB_2,
+       SCIF0_0, SCIF0_1, SCIF0_2, SCIF0_3,
+       SCIF1,
+       TMU2, TMU3,
+       SCIF2, SCIF3, SCIF4, SCIF5,
+       Eth_0, Eth_1,
+       PCIeC0_0, PCIeC0_1, PCIeC0_2,
+       PCIeC1_0, PCIeC1_1, PCIeC1_2,
+       USB,
+       I2C0, I2C1,
+       DU,
+       SSI0, SSI1, SSI2, SSI3,
+       PCIeC2_0, PCIeC2_1, PCIeC2_2,
+       HAC0, HAC1,
+       FLCTL,
+       HSPI,
+       GPIO0, GPIO1,
+       Thermal,
+       INTC0, INTC1, INTC2, INTC3, INTC4, INTC5, INTC6, INTC7,
+
+       /* interrupt groups */
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(WDT, 0x3e0),
+       INTC_VECT(TMU0_0, 0x400), INTC_VECT(TMU0_1, 0x420),
+       INTC_VECT(TMU0_2, 0x440), INTC_VECT(TMU0_3, 0x460),
+       INTC_VECT(TMU1_0, 0x480), INTC_VECT(TMU1_1, 0x4a0),
+       INTC_VECT(TMU1_2, 0x4c0),
+       INTC_VECT(DMAC0_0, 0x500), INTC_VECT(DMAC0_1, 0x520),
+       INTC_VECT(DMAC0_2, 0x540), INTC_VECT(DMAC0_3, 0x560),
+       INTC_VECT(DMAC0_4, 0x580), INTC_VECT(DMAC0_5, 0x5a0),
+       INTC_VECT(DMAC0_6, 0x5c0),
+       INTC_VECT(HUDI1, 0x5e0), INTC_VECT(HUDI0, 0x600),
+       INTC_VECT(DMAC1_0, 0x620), INTC_VECT(DMAC1_1, 0x640),
+       INTC_VECT(DMAC1_2, 0x660), INTC_VECT(DMAC1_3, 0x680),
+       INTC_VECT(HPB_0, 0x6a0), INTC_VECT(HPB_1, 0x6c0),
+       INTC_VECT(HPB_2, 0x6e0),
+       INTC_VECT(SCIF0_0, 0x700), INTC_VECT(SCIF0_1, 0x720),
+       INTC_VECT(SCIF0_2, 0x740), INTC_VECT(SCIF0_3, 0x760),
+       INTC_VECT(SCIF1, 0x780),
+       INTC_VECT(TMU2, 0x7a0), INTC_VECT(TMU3, 0x7c0),
+       INTC_VECT(SCIF2, 0x840), INTC_VECT(SCIF3, 0x860),
+       INTC_VECT(SCIF4, 0x880), INTC_VECT(SCIF5, 0x8a0),
+       INTC_VECT(Eth_0, 0x8c0), INTC_VECT(Eth_1, 0x8e0),
+       INTC_VECT(PCIeC0_0, 0xae0), INTC_VECT(PCIeC0_1, 0xb00),
+       INTC_VECT(PCIeC0_2, 0xb20),
+       INTC_VECT(PCIeC1_0, 0xb40), INTC_VECT(PCIeC1_1, 0xb60),
+       INTC_VECT(PCIeC1_2, 0xb80),
+       INTC_VECT(USB, 0xba0),
+       INTC_VECT(I2C0, 0xcc0), INTC_VECT(I2C1, 0xce0),
+       INTC_VECT(DU, 0xd00),
+       INTC_VECT(SSI0, 0xd20), INTC_VECT(SSI1, 0xd40),
+       INTC_VECT(SSI2, 0xd60), INTC_VECT(SSI3, 0xd80),
+       INTC_VECT(PCIeC2_0, 0xda0), INTC_VECT(PCIeC2_1, 0xdc0),
+       INTC_VECT(PCIeC2_2, 0xde0),
+       INTC_VECT(HAC0, 0xe00), INTC_VECT(HAC1, 0xe20),
+       INTC_VECT(FLCTL, 0xe40),
+       INTC_VECT(HSPI, 0xe80),
+       INTC_VECT(GPIO0, 0xea0), INTC_VECT(GPIO1, 0xec0),
+       INTC_VECT(Thermal, 0xee0),
+};
+
+/* FIXME: Main CPU support only now */
+#if 1 /* Main CPU */
+#define CnINTMSK0      0xfe410030
+#define CnINTMSK1      0xfe410040
+#define CnINTMSKCLR0   0xfe410050
+#define CnINTMSKCLR1   0xfe410060
+#define CnINT2MSKR0    0xfe410a20
+#define CnINT2MSKR1    0xfe410a24
+#define CnINT2MSKR2    0xfe410a28
+#define CnINT2MSKR3    0xfe410a2c
+#define CnINT2MSKCR0   0xfe410a30
+#define CnINT2MSKCR1   0xfe410a34
+#define CnINT2MSKCR2   0xfe410a38
+#define CnINT2MSKCR3   0xfe410a3c
+#else /* Sub CPU */
+#define CnINTMSK0      0xfe410034
+#define CnINTMSK1      0xfe410044
+#define CnINTMSKCLR0   0xfe410054
+#define CnINTMSKCLR1   0xfe410064
+#define CnINT2MSKR0    0xfe410b20
+#define CnINT2MSKR1    0xfe410b24
+#define CnINT2MSKR2    0xfe410b28
+#define CnINT2MSKR3    0xfe410b2c
+#define CnINT2MSKCR0   0xfe410b30
+#define CnINT2MSKCR1   0xfe410b34
+#define CnINT2MSKCR2   0xfe410b38
+#define CnINT2MSKCR3   0xfe410b3c
+#endif
+
+#define INTMSK2                0xfe410068
+#define INTMSKCLR2     0xfe41006c
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { CnINTMSK0, CnINTMSKCLR0, 32,
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { INTMSK2, INTMSKCLR2, 32,
+         { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+           IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+           IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+           IRL0_HHLL, IRL0_HHLH, IRL0_HHHL, 0,
+           IRL4_LLLL, IRL4_LLLH, IRL4_LLHL, IRL4_LLHH,
+           IRL4_LHLL, IRL4_LHLH, IRL4_LHHL, IRL4_LHHH,
+           IRL4_HLLL, IRL4_HLLH, IRL4_HLHL, IRL4_HLHH,
+           IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } },
+       { CnINT2MSKR0, CnINT2MSKCR0 , 32,
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WDT } },
+       { CnINT2MSKR1, CnINT2MSKCR1, 32,
+         { TMU0_0, TMU0_1, TMU0_2, TMU0_3, TMU1_0, TMU1_1, TMU1_2, 0,
+           DMAC0_0, DMAC0_1, DMAC0_2, DMAC0_3, DMAC0_4, DMAC0_5, DMAC0_6,
+           HUDI1, HUDI0,
+           DMAC1_0, DMAC1_1, DMAC1_2, DMAC1_3,
+           HPB_0, HPB_1, HPB_2,
+           SCIF0_0, SCIF0_1, SCIF0_2, SCIF0_3,
+           SCIF1,
+           TMU2, TMU3, 0, } },
+       { CnINT2MSKR2, CnINT2MSKCR2, 32,
+         { 0, 0, SCIF2, SCIF3, SCIF4, SCIF5,
+           Eth_0, Eth_1,
+           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           PCIeC0_0, PCIeC0_1, PCIeC0_2,
+           PCIeC1_0, PCIeC1_1, PCIeC1_2,
+           USB, 0, 0 } },
+       { CnINT2MSKR3, CnINT2MSKCR3, 32,
+         { 0, 0, 0, 0, 0, 0,
+           I2C0, I2C1,
+           DU, SSI0, SSI1, SSI2, SSI3,
+           PCIeC2_0, PCIeC2_1, PCIeC2_2,
+           HAC0, HAC1,
+           FLCTL, 0,
+           HSPI, GPIO0, GPIO1, Thermal,
+           0, 0, 0, 0, 0, 0, 0, 0 } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfe410010, 0, 32, 4, /* INTPRI */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                                IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xfe410800, 0, 32, 8, /* INT2PRI0 */ { 0, 0, 0, WDT } },
+       { 0xfe410804, 0, 32, 8, /* INT2PRI1 */ { TMU0_0, TMU0_1,
+                                                TMU0_2, TMU0_3 } },
+       { 0xfe410808, 0, 32, 8, /* INT2PRI2 */ { TMU1_0, TMU1_1,
+                                                TMU1_2, 0 } },
+       { 0xfe41080c, 0, 32, 8, /* INT2PRI3 */ { DMAC0_0, DMAC0_1,
+                                                DMAC0_2, DMAC0_3 } },
+       { 0xfe410810, 0, 32, 8, /* INT2PRI4 */ { DMAC0_4, DMAC0_5,
+                                                DMAC0_6, HUDI1 } },
+       { 0xfe410814, 0, 32, 8, /* INT2PRI5 */ { HUDI0, DMAC1_0,
+                                                DMAC1_1, DMAC1_2 } },
+       { 0xfe410818, 0, 32, 8, /* INT2PRI6 */ { DMAC1_3, HPB_0,
+                                                HPB_1, HPB_2 } },
+       { 0xfe41081c, 0, 32, 8, /* INT2PRI7 */ { SCIF0_0, SCIF0_1,
+                                                SCIF0_2, SCIF0_3 } },
+       { 0xfe410820, 0, 32, 8, /* INT2PRI8 */ { SCIF1, TMU2, TMU3, 0 } },
+       { 0xfe410824, 0, 32, 8, /* INT2PRI9 */ { 0, 0, SCIF2, SCIF3 } },
+       { 0xfe410828, 0, 32, 8, /* INT2PRI10 */ { SCIF4, SCIF5,
+                                                 Eth_0, Eth_1 } },
+       { 0xfe41082c, 0, 32, 8, /* INT2PRI11 */ { 0, 0, 0, 0 } },
+       { 0xfe410830, 0, 32, 8, /* INT2PRI12 */ { 0, 0, 0, 0 } },
+       { 0xfe410834, 0, 32, 8, /* INT2PRI13 */ { 0, 0, 0, 0 } },
+       { 0xfe410838, 0, 32, 8, /* INT2PRI14 */ { 0, 0, 0, PCIeC0_0 } },
+       { 0xfe41083c, 0, 32, 8, /* INT2PRI15 */ { PCIeC0_1, PCIeC0_2,
+                                                 PCIeC1_0, PCIeC1_1 } },
+       { 0xfe410840, 0, 32, 8, /* INT2PRI16 */ { PCIeC1_2, USB, 0, 0 } },
+       { 0xfe410844, 0, 32, 8, /* INT2PRI17 */ { 0, 0, 0, 0 } },
+       { 0xfe410848, 0, 32, 8, /* INT2PRI18 */ { 0, 0, I2C0, I2C1 } },
+       { 0xfe41084c, 0, 32, 8, /* INT2PRI19 */ { DU, SSI0, SSI1, SSI2 } },
+       { 0xfe410850, 0, 32, 8, /* INT2PRI20 */ { SSI3, PCIeC2_0,
+                                                 PCIeC2_1, PCIeC2_2 } },
+       { 0xfe410854, 0, 32, 8, /* INT2PRI21 */ { HAC0, HAC1, FLCTL, 0 } },
+       { 0xfe410858, 0, 32, 8, /* INT2PRI22 */ { HSPI, GPIO0,
+                                                 GPIO1, Thermal } },
+       { 0xfe41085c, 0, 32, 8, /* INT2PRI23 */ { 0, 0, 0, 0 } },
+       { 0xfe410860, 0, 32, 8, /* INT2PRI24 */ { 0, 0, 0, 0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7786", vectors, NULL,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect vectors_irq0123[] __initdata = {
+       INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
+       INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
+};
+
+static struct intc_vect vectors_irq4567[] __initdata = {
+       INTC_VECT(IRQ4, 0x300), INTC_VECT(IRQ5, 0x340),
+       INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
+};
+
+static struct intc_sense_reg sense_registers[] __initdata = {
+       { 0xfe41001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_mask_reg ack_registers[] __initdata = {
+       { 0xfe410024, 0, 32, /* INTREQ */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh7786-irq0123",
+                            vectors_irq0123, NULL, mask_registers,
+                            prio_registers, sense_registers, ack_registers);
+
+static DECLARE_INTC_DESC_ACK(intc_desc_irq4567, "sh7786-irq4567",
+                            vectors_irq4567, NULL, mask_registers,
+                            prio_registers, sense_registers, ack_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl0123[] __initdata = {
+       INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+       INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+       INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+       INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+       INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+       INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+       INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+       INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static struct intc_vect vectors_irl4567[] __initdata = {
+       INTC_VECT(IRL4_LLLL, 0x900), INTC_VECT(IRL4_LLLH, 0x920),
+       INTC_VECT(IRL4_LLHL, 0x940), INTC_VECT(IRL4_LLHH, 0x960),
+       INTC_VECT(IRL4_LHLL, 0x980), INTC_VECT(IRL4_LHLH, 0x9a0),
+       INTC_VECT(IRL4_LHHL, 0x9c0), INTC_VECT(IRL4_LHHH, 0x9e0),
+       INTC_VECT(IRL4_HLLL, 0xa00), INTC_VECT(IRL4_HLLH, 0xa20),
+       INTC_VECT(IRL4_HLHL, 0xa40), INTC_VECT(IRL4_HLHH, 0xa60),
+       INTC_VECT(IRL4_HHLL, 0xa80), INTC_VECT(IRL4_HHLH, 0xaa0),
+       INTC_VECT(IRL4_HHHL, 0xac0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7786-irl0123", vectors_irl0123,
+                        NULL, mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
+                        NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0      0xfe410000
+#define INTC_INTMSK0   CnINTMSK0
+#define INTC_INTMSK1   CnINTMSK1
+#define INTC_INTMSK2   INTMSK2
+#define INTC_INTMSKCLR1        CnINTMSKCLR1
+#define INTC_INTMSKCLR2        INTMSKCLR2
+
+void __init plat_irq_setup(void)
+{
+       /* disable IRQ3-0 + IRQ7-4 */
+       ctrl_outl(0xff000000, INTC_INTMSK0);
+
+       /* disable IRL3-0 + IRL7-4 */
+       ctrl_outl(0xc0000000, INTC_INTMSK1);
+       ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+       /* select IRL mode for IRL3-0 + IRL7-4 */
+       ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
+
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ7654:
+               /* select IRQ mode for IRL7-4 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0);
+               register_intc_controller(&intc_desc_irq4567);
+               break;
+       case IRQ_MODE_IRQ3210:
+               /* select IRQ mode for IRL3-0 */
+               ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+               register_intc_controller(&intc_desc_irq0123);
+               break;
+       case IRQ_MODE_IRL7654:
+               /* enable IRL7-4 but don't provide any masking */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL3210:
+               /* enable IRL0-3 but don't provide any masking */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+               break;
+       case IRQ_MODE_IRL7654_MASK:
+               /* enable IRL7-4 and mask using cpu intc controller */
+               ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_desc_irl4567);
+               break;
+       case IRQ_MODE_IRL3210_MASK:
+               /* enable IRL0-3 and mask using cpu intc controller */
+               ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+               register_intc_controller(&intc_desc_irl0123);
+               break;
+       default:
+               BUG();
+       }
+}
+
+void __init plat_mem_setup(void)
+{
+}
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile
new file mode 100644 (file)
index 0000000..08bfa7c
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux/SuperH SH-Mobile backends.
+#
+
+# Power Management & Sleep mode
+obj-$(CONFIG_PM)       += pm.o sleep.o
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
new file mode 100644 (file)
index 0000000..8c067ad
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ *
+ * Power management support code for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+
+/*
+ * Sleep modes available on SuperH Mobile:
+ *
+ * Sleep mode is just plain "sleep" instruction
+ * Sleep Self-Refresh mode is above plus RAM put in Self-Refresh
+ * Standby Self-Refresh mode is above plus stopped clocks
+ */
+#define SUSP_MODE_SLEEP                (SUSP_SH_SLEEP)
+#define SUSP_MODE_SLEEP_SF     (SUSP_SH_SLEEP | SUSP_SH_SF)
+#define SUSP_MODE_STANDBY_SF   (SUSP_SH_STANDBY | SUSP_SH_SF)
+
+/*
+ * The following modes are not there yet:
+ *
+ * R-standby mode is unsupported, but will be added in the future
+ * U-standby mode is low priority since it needs bootloader hacks
+ *
+ * All modes should be tied in with cpuidle. But before that can
+ * happen we need to keep track of enabled hardware blocks so we
+ * can avoid entering sleep modes that stop clocks to hardware
+ * blocks that are in use even though the cpu core is idle.
+ */
+
+extern const unsigned char sh_mobile_standby[];
+extern const unsigned int sh_mobile_standby_size;
+
+static void sh_mobile_call_standby(unsigned long mode)
+{
+       extern void *vbr_base;
+       void *onchip_mem = (void *)0xe5200000; /* ILRAM */
+       void (*standby_onchip_mem)(unsigned long) = onchip_mem;
+
+       /* Note: Wake up from sleep may generate exceptions!
+        * Setup VBR to point to on-chip ram if self-refresh is
+        * going to be used.
+        */
+       if (mode & SUSP_SH_SF)
+               asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
+
+       /* Copy the assembly snippet to the otherwise ununsed ILRAM */
+       memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
+       wmb();
+       ctrl_barrier();
+
+       /* Let assembly snippet in on-chip memory handle the rest */
+       standby_onchip_mem(mode);
+
+       /* Put VBR back in System RAM again */
+       if (mode & SUSP_SH_SF)
+               asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
+}
+
+static int sh_pm_enter(suspend_state_t state)
+{
+       local_irq_disable();
+       set_bl_bit();
+       sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
+       local_irq_disable();
+       clear_bl_bit();
+       return 0;
+}
+
+static struct platform_suspend_ops sh_pm_ops = {
+       .enter          = sh_pm_enter,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int __init sh_pm_init(void)
+{
+       suspend_set_ops(&sh_pm_ops);
+       return 0;
+}
+
+late_initcall(sh_pm_init);
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S
new file mode 100644 (file)
index 0000000..5d888ef
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
+ *
+ * Sleep mode and Standby modes support for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+
+/* manage self-refresh and enter standby mode.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+
+       .balign         4096,0,4096
+ENTRY(sh_mobile_standby)
+       mov     r4, r0
+
+       tst     #SUSP_SH_SF, r0
+       bt      skip_set_sf
+
+       /* SDRAM: disable power down and put in self-refresh mode */
+       mov.l   1f, r4
+       mov.l   2f, r1
+       mov.l   @r4, r2
+       or      r1, r2
+       mov.l   3f, r3
+       and     r3, r2
+       mov.l   r2, @r4
+
+skip_set_sf:
+       tst     #SUSP_SH_SLEEP, r0
+       bt      test_standby
+
+       /* set mode to "sleep mode" */
+       bra     do_sleep
+        mov    #0x00, r1
+
+test_standby:
+       tst     #SUSP_SH_STANDBY, r0
+       bt      test_rstandby
+
+       /* set mode to "software standby mode" */
+       bra     do_sleep
+        mov    #0x80, r1
+
+test_rstandby:
+       tst     #SUSP_SH_RSTANDBY, r0
+       bt      test_ustandby
+
+       /* set mode to "r-standby mode" */
+       bra     do_sleep
+        mov    #0x20, r1
+
+test_ustandby:
+       tst     #SUSP_SH_USTANDBY, r0
+       bt      done_sleep
+
+       /* set mode to "u-standby mode" */
+       mov     #0x10, r1
+
+       /* fall-through */
+
+do_sleep:
+       /* setup and enter selected standby mode */
+       mov.l   5f, r4
+       mov.l   r1, @r4
+       sleep
+
+done_sleep:
+       /* reset standby mode to sleep mode */
+       mov.l   5f, r4
+       mov     #0x00, r1
+       mov.l   r1, @r4
+
+       tst     #SUSP_SH_SF, r0
+       bt      skip_restore_sf
+
+       /* SDRAM: set auto-refresh mode */
+       mov.l   1f, r4
+       mov.l   @r4, r2
+       mov.l   4f, r3
+       and     r3, r2
+       mov.l   r2, @r4
+       mov.l   6f, r4
+       mov.l   7f, r1
+       mov.l   8f, r2
+       mov.l   @r4, r3
+       mov     #-1, r4
+       add     r4, r3
+       or      r2, r3
+       mov.l   r3, @r1
+skip_restore_sf:
+       rts
+        nop
+
+       .balign 4
+1:     .long   0xfe400008 /* SDCR0 */
+2:     .long   0x00000400
+3:     .long   0xffff7fff
+4:     .long   0xfffffbff
+5:     .long   0xa4150020 /* STBCR */
+6:     .long   0xfe40001c /* RTCOR */
+7:     .long   0xfe400018 /* RTCNT */
+8:     .long   0xa55a0000
+
+/* interrupt vector @ 0x600 */
+       .balign         0x400,0,0x400
+       .long   0xdeadbeef
+       .balign         0x200,0,0x200
+       /* sh7722 will end up here in sleep mode */
+       rte
+        nop
+sh_mobile_standby_end:
+
+ENTRY(sh_mobile_standby_size)
+       .long sh_mobile_standby_end - sh_mobile_standby
index d371653610348313dc4b6481764b9b0ea4a08988..d22e5af699f9839233a78065356ae174ab9d837b 100644 (file)
 #include <linux/bitops.h>
 #include <linux/gpio.h>
 
-static struct pinmux_info *registered_gpio;
+static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+{
+       if (enum_id < r->begin)
+               return 0;
 
-static struct pinmux_info *gpio_controller(unsigned gpio)
+       if (enum_id > r->end)
+               return 0;
+
+       return 1;
+}
+
+static unsigned long gpio_read_raw_reg(unsigned long reg,
+                                      unsigned long reg_width)
 {
-       if (!registered_gpio)
-               return NULL;
+       switch (reg_width) {
+       case 8:
+               return ctrl_inb(reg);
+       case 16:
+               return ctrl_inw(reg);
+       case 32:
+               return ctrl_inl(reg);
+       }
 
-       if (gpio < registered_gpio->first_gpio)
-               return NULL;
+       BUG();
+       return 0;
+}
 
-       if (gpio > registered_gpio->last_gpio)
-               return NULL;
+static void gpio_write_raw_reg(unsigned long reg,
+                              unsigned long reg_width,
+                              unsigned long data)
+{
+       switch (reg_width) {
+       case 8:
+               ctrl_outb(data, reg);
+               return;
+       case 16:
+               ctrl_outw(data, reg);
+               return;
+       case 32:
+               ctrl_outl(data, reg);
+               return;
+       }
 
-       return registered_gpio;
+       BUG();
 }
 
-static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+static void gpio_write_bit(struct pinmux_data_reg *dr,
+                          unsigned long in_pos, unsigned long value)
 {
-       if (enum_id < r->begin)
-               return 0;
+       unsigned long pos;
 
-       if (enum_id > r->end)
-               return 0;
+       pos = dr->reg_width - (in_pos + 1);
 
-       return 1;
+#ifdef DEBUG
+       pr_info("write_bit addr = %lx, value = %ld, pos = %ld, "
+               "r_width = %ld\n",
+               dr->reg, !!value, pos, dr->reg_width);
+#endif
+
+       if (value)
+               set_bit(pos, &dr->reg_shadow);
+       else
+               clear_bit(pos, &dr->reg_shadow);
+
+       gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
 }
 
-static int read_write_reg(unsigned long reg, unsigned long reg_width,
-                         unsigned long field_width, unsigned long in_pos,
-                         unsigned long value, int do_write)
+static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
+                        unsigned long field_width, unsigned long in_pos)
 {
        unsigned long data, mask, pos;
 
@@ -57,52 +96,53 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width,
        pos = reg_width - ((in_pos + 1) * field_width);
 
 #ifdef DEBUG
-       pr_info("%s, addr = %lx, value = %ld, pos = %ld, "
+       pr_info("read_reg: addr = %lx, pos = %ld, "
                "r_width = %ld, f_width = %ld\n",
-               do_write ? "write" : "read", reg, value, pos,
-               reg_width, field_width);
+               reg, pos, reg_width, field_width);
 #endif
 
-       switch (reg_width) {
-       case 8:
-               data = ctrl_inb(reg);
-               break;
-       case 16:
-               data = ctrl_inw(reg);
-               break;
-       case 32:
-               data = ctrl_inl(reg);
-               break;
-       }
+       data = gpio_read_raw_reg(reg, reg_width);
+       return (data >> pos) & mask;
+}
 
-       if (!do_write)
-               return (data >> pos) & mask;
+static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
+                          unsigned long field_width, unsigned long in_pos,
+                          unsigned long value)
+{
+       unsigned long mask, pos;
 
-       data &= ~(mask << pos);
-       data |= value << pos;
+       mask = (1 << field_width) - 1;
+       pos = reg_width - ((in_pos + 1) * field_width);
+
+#ifdef DEBUG
+       pr_info("write_reg addr = %lx, value = %ld, pos = %ld, "
+               "r_width = %ld, f_width = %ld\n",
+               reg, value, pos, reg_width, field_width);
+#endif
+
+       mask = ~(mask << pos);
+       value = value << pos;
 
        switch (reg_width) {
        case 8:
-               ctrl_outb(data, reg);
+               ctrl_outb((ctrl_inb(reg) & mask) | value, reg);
                break;
        case 16:
-               ctrl_outw(data, reg);
+               ctrl_outw((ctrl_inw(reg) & mask) | value, reg);
                break;
        case 32:
-               ctrl_outl(data, reg);
+               ctrl_outl((ctrl_inl(reg) & mask) | value, reg);
                break;
        }
-       return 0;
 }
 
-static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
-                       struct pinmux_data_reg **drp, int *bitp)
+static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
 {
-       pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
+       struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
        struct pinmux_data_reg *data_reg;
        int k, n;
 
-       if (!enum_in_range(enum_id, &gpioc->data))
+       if (!enum_in_range(gpiop->enum_id, &gpioc->data))
                return -1;
 
        k = 0;
@@ -113,19 +153,58 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
                        break;
 
                for (n = 0; n < data_reg->reg_width; n++) {
-                       if (data_reg->enum_ids[n] == enum_id) {
-                               *drp = data_reg;
-                               *bitp = n;
+                       if (data_reg->enum_ids[n] == gpiop->enum_id) {
+                               gpiop->flags &= ~PINMUX_FLAG_DREG;
+                               gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
+                               gpiop->flags &= ~PINMUX_FLAG_DBIT;
+                               gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
                                return 0;
-
                        }
                }
                k++;
        }
 
+       BUG();
+
        return -1;
 }
 
+static void setup_data_regs(struct pinmux_info *gpioc)
+{
+       struct pinmux_data_reg *drp;
+       int k;
+
+       for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
+               setup_data_reg(gpioc, k);
+
+       k = 0;
+       while (1) {
+               drp = gpioc->data_regs + k;
+
+               if (!drp->reg_width)
+                       break;
+
+               drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
+               k++;
+       }
+}
+
+static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
+                       struct pinmux_data_reg **drp, int *bitp)
+{
+       struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+       int k, n;
+
+       if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+               return -1;
+
+       k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
+       n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
+       *drp = gpioc->data_regs + k;
+       *bitp = n;
+       return 0;
+}
+
 static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
                          struct pinmux_cfg_reg **crp, int *indexp,
                          unsigned long **cntp)
@@ -187,9 +266,9 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
        return -1;
 }
 
-static int write_config_reg(struct pinmux_info *gpioc,
-                           struct pinmux_cfg_reg *crp,
-                           int index)
+static void write_config_reg(struct pinmux_info *gpioc,
+                            struct pinmux_cfg_reg *crp,
+                            int index)
 {
        unsigned long ncomb, pos, value;
 
@@ -197,8 +276,7 @@ static int write_config_reg(struct pinmux_info *gpioc,
        pos = index / ncomb;
        value = index % ncomb;
 
-       return read_write_reg(crp->reg, crp->reg_width,
-                             crp->field_width, pos, value, 1);
+       gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
 }
 
 static int check_config_reg(struct pinmux_info *gpioc,
@@ -211,8 +289,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
        pos = index / ncomb;
        value = index % ncomb;
 
-       if (read_write_reg(crp->reg, crp->reg_width,
-                          crp->field_width, pos, 0, 0) == value)
+       if (gpio_read_reg(crp->reg, crp->reg_width,
+                         crp->field_width, pos) == value)
                return 0;
 
        return -1;
@@ -220,8 +298,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
 
 enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
 
-int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
-                      int pinmux_type, int cfg_mode)
+static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
+                             int pinmux_type, int cfg_mode)
 {
        struct pinmux_cfg_reg *cr = NULL;
        pinmux_enum_t enum_id;
@@ -287,8 +365,7 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
                        break;
 
                case GPIO_CFG_REQ:
-                       if (write_config_reg(gpioc, cr, index) != 0)
-                               goto out_err;
+                       write_config_reg(gpioc, cr, index);
                        *cntp = *cntp + 1;
                        break;
 
@@ -305,9 +382,14 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 
 static DEFINE_SPINLOCK(gpio_lock);
 
-int __gpio_request(unsigned gpio)
+static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       return container_of(chip, struct pinmux_info, chip);
+}
+
+static int sh_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        struct pinmux_data_reg *dummy;
        unsigned long flags;
        int i, ret, pinmux_type;
@@ -319,29 +401,30 @@ int __gpio_request(unsigned gpio)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
+       if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
                goto err_unlock;
 
        /* setup pin function here if no data is associated with pin */
 
-       if (get_data_reg(gpioc, gpio, &dummy, &i) != 0)
+       if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
                pinmux_type = PINMUX_TYPE_FUNCTION;
        else
                pinmux_type = PINMUX_TYPE_GPIO;
 
        if (pinmux_type == PINMUX_TYPE_FUNCTION) {
-               if (pinmux_config_gpio(gpioc, gpio,
+               if (pinmux_config_gpio(gpioc, offset,
                                       pinmux_type,
                                       GPIO_CFG_DRYRUN) != 0)
                        goto err_unlock;
 
-               if (pinmux_config_gpio(gpioc, gpio,
+               if (pinmux_config_gpio(gpioc, offset,
                                       pinmux_type,
                                       GPIO_CFG_REQ) != 0)
                        BUG();
        }
 
-       gpioc->gpios[gpio].flags = pinmux_type;
+       gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[offset].flags |= pinmux_type;
 
        ret = 0;
  err_unlock:
@@ -349,11 +432,10 @@ int __gpio_request(unsigned gpio)
  err_out:
        return ret;
 }
-EXPORT_SYMBOL(__gpio_request);
 
-void gpio_free(unsigned gpio)
+static void sh_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
        int pinmux_type;
 
@@ -362,20 +444,23 @@ void gpio_free(unsigned gpio)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
-       pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
-       gpioc->gpios[gpio].flags = PINMUX_TYPE_NONE;
+       pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+       pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
+       gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 }
-EXPORT_SYMBOL(gpio_free);
 
 static int pinmux_direction(struct pinmux_info *gpioc,
                            unsigned gpio, int new_pinmux_type)
 {
-       int ret, pinmux_type;
+       int pinmux_type;
+       int ret = -EINVAL;
+
+       if (!gpioc)
+               goto err_out;
 
-       ret = -EINVAL;
        pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
 
        switch (pinmux_type) {
@@ -401,102 +486,99 @@ static int pinmux_direction(struct pinmux_info *gpioc,
                               GPIO_CFG_REQ) != 0)
                BUG();
 
-       gpioc->gpios[gpio].flags = new_pinmux_type;
+       gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+       gpioc->gpios[gpio].flags |= new_pinmux_type;
 
        ret = 0;
  err_out:
        return ret;
 }
 
-int gpio_direction_input(unsigned gpio)
+static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
-       int ret = -EINVAL;
-
-       if (!gpioc)
-               goto err_out;
+       int ret;
 
        spin_lock_irqsave(&gpio_lock, flags);
-       ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT);
+       ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
        spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
        return ret;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-static int __gpio_get_set_value(struct pinmux_info *gpioc,
-                               unsigned gpio, int value,
-                               int do_write)
+static void sh_gpio_set_value(struct pinmux_info *gpioc,
+                            unsigned gpio, int value)
 {
        struct pinmux_data_reg *dr = NULL;
        int bit = 0;
 
-       if (get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
                BUG();
        else
-               value = read_write_reg(dr->reg, dr->reg_width,
-                                      1, bit, !!value, do_write);
-
-       return value;
+               gpio_write_bit(dr, bit, value);
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                   int value)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
+       struct pinmux_info *gpioc = chip_to_pinmux(chip);
        unsigned long flags;
-       int ret = -EINVAL;
-
-       if (!gpioc)
-               goto err_out;
+       int ret;
 
+       sh_gpio_set_value(gpioc, offset, value);
        spin_lock_irqsave(&gpio_lock, flags);
-       __gpio_get_set_value(gpioc, gpio, value, 1);
-       ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
+       ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
        spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
        return ret;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
-int gpio_get_value(unsigned gpio)
+static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
-       unsigned long flags;
-       int value = 0;
+       struct pinmux_data_reg *dr = NULL;
+       int bit = 0;
 
-       if (!gpioc)
+       if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
                BUG();
-       else {
-               spin_lock_irqsave(&gpio_lock, flags);
-               value = __gpio_get_set_value(gpioc, gpio, 0, 0);
-               spin_unlock_irqrestore(&gpio_lock, flags);
+               return 0;
        }
 
-       return value;
+       return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
 }
-EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_set_value(unsigned gpio, int value)
+static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-       struct pinmux_info *gpioc = gpio_controller(gpio);
-       unsigned long flags;
+       return sh_gpio_get_value(chip_to_pinmux(chip), offset);
+}
 
-       if (!gpioc)
-               BUG();
-       else {
-               spin_lock_irqsave(&gpio_lock, flags);
-               __gpio_get_set_value(gpioc, gpio, value, 1);
-               spin_unlock_irqrestore(&gpio_lock, flags);
-       }
+static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       sh_gpio_set_value(chip_to_pinmux(chip), offset, value);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
 int register_pinmux(struct pinmux_info *pip)
 {
-       registered_gpio = pip;
-       pr_info("pinmux: %s handling gpio %d -> %d\n",
+       struct gpio_chip *chip = &pip->chip;
+
+       pr_info("sh pinmux: %s handling gpio %d -> %d\n",
                pip->name, pip->first_gpio, pip->last_gpio);
 
-       return 0;
+       setup_data_regs(pip);
+
+       chip->request = sh_gpio_request;
+       chip->free = sh_gpio_free;
+       chip->direction_input = sh_gpio_direction_input;
+       chip->get = sh_gpio_get;
+       chip->direction_output = sh_gpio_direction_output;
+       chip->set = sh_gpio_set;
+
+       WARN_ON(pip->first_gpio != 0); /* needs testing */
+
+       chip->label = pip->name;
+       chip->owner = THIS_MODULE;
+       chip->base = pip->first_gpio;
+       chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
+
+       return gpiochip_add(chip);
 }
index 64b7690c664cb9ac1cabe09c30dfee042451a3b1..90d63aefd2755907d66932d42e4ac30629d277b5 100644 (file)
@@ -106,7 +106,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
        }
 #endif
 
-       irq = irq_demux(evt2irq(irq));
+       irq = irq_demux(intc_evt2irq(irq));
 
 #ifdef CONFIG_IRQSTACKS
        curctx = (union irq_ctx *)current_thread_info();
index 94df56b0d1f65612d76196ec8ef1bfbb1fb4eeae..7ea2704ea03326bd67ec5b85b85e41433abbe55c 100644 (file)
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/numa.h>
+#include <linux/ftrace.h>
+#include <linux/suspend.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
 
-typedef NORET_TYPE void (*relocate_new_kernel_t)(
-                               unsigned long indirection_page,
-                               unsigned long reboot_code_buffer,
-                               unsigned long start_address,
-                               unsigned long vbr_reg) ATTRIB_NORET;
+typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
+                                     unsigned long reboot_code_buffer,
+                                     unsigned long start_address);
 
 extern const unsigned char relocate_new_kernel[];
 extern const unsigned int relocate_new_kernel_size;
 extern void *gdb_vbr_vector;
+extern void *vbr_base;
 
 void machine_shutdown(void)
 {
@@ -45,6 +46,12 @@ void machine_crash_shutdown(struct pt_regs *regs)
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+       /* older versions of kexec-tools are passing
+        * the zImage entry point as a virtual address.
+        */
+       if (image->start != PHYSADDR(image->start))
+               return -EINVAL; /* upgrade your kexec-tools */
+
        return 0;
 }
 
@@ -73,17 +80,33 @@ static void kexec_info(struct kimage *image)
  */
 void machine_kexec(struct kimage *image)
 {
-
        unsigned long page_list;
        unsigned long reboot_code_buffer;
-       unsigned long vbr_reg;
        relocate_new_kernel_t rnk;
+       unsigned long entry;
+       unsigned long *ptr;
+       int save_ftrace_enabled;
+
+       /*
+        * Nicked from the mips version of machine_kexec():
+        * The generic kexec code builds a page list with physical
+        * addresses. Use phys_to_virt() to convert them to virtual.
+        */
+       for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+            ptr = (entry & IND_INDIRECTION) ?
+              phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+               if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
+                   *ptr & IND_DESTINATION)
+                       *ptr = (unsigned long) phys_to_virt(*ptr);
+       }
 
-#if defined(CONFIG_SH_STANDARD_BIOS)
-       vbr_reg = ((unsigned long )gdb_vbr_vector) - 0x100;
-#else
-       vbr_reg = 0x80000000;  // dummy
+#ifdef CONFIG_KEXEC_JUMP
+       if (image->preserve_context)
+               save_processor_state();
 #endif
+
+       save_ftrace_enabled = __ftrace_enabled_save();
+
        /* Interrupts aren't acceptable while we reboot */
        local_irq_disable();
 
@@ -97,12 +120,37 @@ void machine_kexec(struct kimage *image)
        memcpy((void *)reboot_code_buffer, relocate_new_kernel,
                                                relocate_new_kernel_size);
 
-        kexec_info(image);
+       kexec_info(image);
        flush_cache_all();
 
+#if defined(CONFIG_SH_STANDARD_BIOS)
+       asm volatile("ldc %0, vbr" :
+                    : "r" (((unsigned long) gdb_vbr_vector) - 0x100)
+                    : "memory");
+#endif
+
        /* now call it */
        rnk = (relocate_new_kernel_t) reboot_code_buffer;
-       (*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg);
+       (*rnk)(page_list, reboot_code_buffer,
+              (unsigned long)phys_to_virt(image->start));
+
+#ifdef CONFIG_KEXEC_JUMP
+       asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
+
+       if (image->preserve_context)
+               restore_processor_state();
+
+       /* Convert page list back to physical addresses, what a mess. */
+       for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+            ptr = (*ptr & IND_INDIRECTION) ?
+              phys_to_virt(*ptr & PAGE_MASK) : ptr + 1) {
+               if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
+                   *ptr & IND_DESTINATION)
+                       *ptr = virt_to_phys(*ptr);
+       }
+#endif
+
+       __ftrace_enabled_restore(save_ftrace_enabled);
 }
 
 void arch_crash_save_vmcoreinfo(void)
index c66cb3209db50ea6d43a38346fdcefe2e1e7dc0c..fcc9934fb97b8fd24932ee034f88a1c1042fd1f4 100644 (file)
@@ -4,6 +4,8 @@
  *
  * LANDISK/sh4 is supported. Maybe, SH archtecture works well.
  *
+ * 2009-03-18 Magnus Damm - Added Kexec Jump support
+ *
  * This source code is licensed under the GNU General Public License,
  * Version 2.  See the file COPYING for more details.
  */
@@ -16,23 +18,141 @@ relocate_new_kernel:
        /* r4 = indirection_page   */
        /* r5 = reboot_code_buffer */
        /* r6 = start_address      */
-       /* r7 = vbr_reg            */
 
-       mov.l   10f,r8    /* PAGE_SIZE */
-       mov.l   11f,r9    /* P2SEG */
+       mov.l   10f, r0         /* PAGE_SIZE */
+       add     r5, r0          /* setup new stack at end of control page */
+
+       /* save r15->r8 to new stack */
+       mov.l   r15, @-r0
+       mov     r0, r15
+       mov.l   r14, @-r15
+       mov.l   r13, @-r15
+       mov.l   r12, @-r15
+       mov.l   r11, @-r15
+       mov.l   r10, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+
+       /* save other random registers */
+       sts.l   macl, @-r15
+       sts.l   mach, @-r15
+       stc.l   gbr, @-r15
+       stc.l   ssr, @-r15
+       stc.l   sr, @-r15
+       sts.l   pr, @-r15
+       stc.l   spc, @-r15
+
+       /* switch to bank1 and save r7->r0 */
+       mov.l   12f, r9
+       stc     sr, r8
+       or      r9, r8
+       ldc     r8, sr
+       mov.l   r7, @-r15
+       mov.l   r6, @-r15
+       mov.l   r5, @-r15
+       mov.l   r4, @-r15
+       mov.l   r3, @-r15
+       mov.l   r2, @-r15
+       mov.l   r1, @-r15
+       mov.l   r0, @-r15
+
+       /* switch to bank0 and save r7->r0 */
+       mov.l   12f, r9
+       not     r9, r9
+       stc     sr, r8
+       and     r9, r8
+       ldc     r8, sr
+       mov.l   r7, @-r15
+       mov.l   r6, @-r15
+       mov.l   r5, @-r15
+       mov.l   r4, @-r15
+       mov.l   r3, @-r15
+       mov.l   r2, @-r15
+       mov.l   r1, @-r15
+       mov.l   r0, @-r15
+
+       mov.l   r4, @-r15       /* save indirection page again */
+
+       bsr     swap_pages      /* swap pages before jumping to new kernel */
+        nop
+
+       mova    11f, r0
+       mov.l   r15, @r0        /* save pointer to stack */
+
+       jsr     @r6             /* hand over control to new kernel */
+        nop
+
+       mov.l   11f, r15        /* get pointer to stack */
+       mov.l   @r15+, r4       /* restore r4 to get indirection page */
 
-       /*  stack setting */
-       add     r8,r5
-       mov     r5,r15
+       bsr     swap_pages      /* swap pages back to previous state */
+        nop
 
+       /* make sure bank0 is active and restore r0->r7 */
+       mov.l   12f, r9
+       not     r9, r9
+       stc     sr, r8
+       and     r9, r8
+       ldc     r8, sr
+       mov.l   @r15+, r0
+       mov.l   @r15+, r1
+       mov.l   @r15+, r2
+       mov.l   @r15+, r3
+       mov.l   @r15+, r4
+       mov.l   @r15+, r5
+       mov.l   @r15+, r6
+       mov.l   @r15+, r7
+
+       /* switch to bank1 and restore r0->r7 */
+       mov.l   12f, r9
+       stc     sr, r8
+       or      r9, r8
+       ldc     r8, sr
+       mov.l   @r15+, r0
+       mov.l   @r15+, r1
+       mov.l   @r15+, r2
+       mov.l   @r15+, r3
+       mov.l   @r15+, r4
+       mov.l   @r15+, r5
+       mov.l   @r15+, r6
+       mov.l   @r15+, r7
+
+       /* switch back to bank0 */
+       mov.l   12f, r9
+       not     r9, r9
+       stc     sr, r8
+       and     r9, r8
+       ldc     r8, sr
+
+       /* restore other random registers */
+       ldc.l   @r15+, spc
+       lds.l   @r15+, pr
+       ldc.l   @r15+, sr
+       ldc.l   @r15+, ssr
+       ldc.l   @r15+, gbr
+       lds.l   @r15+, mach
+       lds.l   @r15+, macl
+
+       /* restore r8->r15 */
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r10
+       mov.l   @r15+, r11
+       mov.l   @r15+, r12
+       mov.l   @r15+, r13
+       mov.l   @r15+, r14
+       mov.l   @r15+, r15
+       rts
+        nop
+
+swap_pages:
        bra     1f
-       mov     r4,r0     /* cmd = indirection_page */
+        mov    r4,r0     /* cmd = indirection_page */
 0:
        mov.l   @r4+,r0   /* cmd = *ind++ */
 
-1:     /* addr = (cmd | P2SEG) & 0xfffffff0 */
+1:     /* addr = cmd & 0xfffffff0 */
        mov     r0,r2
-       or      r9,r2
        mov     #-16,r1
        and     r1,r2
 
@@ -40,57 +160,70 @@ relocate_new_kernel:
        tst     #1,r0
        bt      2f
        bra     0b
-       mov     r2,r5
+        mov    r2,r5
 
 2:     /* else if(cmd & IND_INDIRECTION) ind = addr  */
        tst     #2,r0
        bt      3f
        bra     0b
-       mov     r2,r4
+        mov    r2,r4
 
-3:     /* else if(cmd & IND_DONE) goto 6  */
+3:     /* else if(cmd & IND_DONE) return */
        tst     #4,r0
        bt      4f
-       bra     6f
-       nop
+       rts
+        nop
 
 4:     /* else if(cmd & IND_SOURCE) memcpy(dst,addr,PAGE_SIZE) */
        tst     #8,r0
        bt      0b
 
-       mov     r8,r3
+       mov.l   10f,r3    /* PAGE_SIZE */
        shlr2   r3
        shlr2   r3
 5:
        dt      r3
-       mov.l   @r2+,r1   /*  16n+0 */
-       mov.l   r1,@r5
-       add     #4,r5
-       mov.l   @r2+,r1   /*  16n+4 */
-       mov.l   r1,@r5
-       add     #4,r5
-       mov.l   @r2+,r1   /*  16n+8 */
-       mov.l   r1,@r5
-       add     #4,r5
-       mov.l   @r2+,r1   /*  16n+12 */
-       mov.l   r1,@r5
-       add     #4,r5
+
+       /* regular kexec just overwrites the destination page
+        * with the contents of the source page.
+        * for the kexec jump case we need to swap the contents
+        * of the pages.
+        * to keep it simple swap the contents for both cases.
+        */
+       mov.l   @(0, r2), r8
+       mov.l   @(0, r5), r1
+       mov.l   r8, @(0, r5)
+       mov.l   r1, @(0, r2)
+
+       mov.l   @(4, r2), r8
+       mov.l   @(4, r5), r1
+       mov.l   r8, @(4, r5)
+       mov.l   r1, @(4, r2)
+
+       mov.l   @(8, r2), r8
+       mov.l   @(8, r5), r1
+       mov.l   r8, @(8, r5)
+       mov.l   r1, @(8, r2)
+
+       mov.l   @(12, r2), r8
+       mov.l   @(12, r5), r1
+       mov.l   r8, @(12, r5)
+       mov.l   r1, @(12, r2)
+
+       add     #16,r5
+       add     #16,r2
        bf      5b
 
        bra     0b
-       nop
-6:
-#ifdef CONFIG_SH_STANDARD_BIOS
-       ldc   r7, vbr
-#endif
-       jmp @r6
-       nop
+        nop
 
        .align 2
 10:
        .long   PAGE_SIZE
 11:
-       .long   P2SEG
+       .long   0
+12:
+       .long   0x20000000 ! RB=1
 
 relocate_new_kernel_end:
 
index 370d2cfa34eba0c427da15cc3b35fb7e34078b97..24c60251f68017d5c120b33b21a30dd46bb9c6e1 100644 (file)
@@ -432,6 +432,7 @@ static const char *cpu_name[] = {
        [CPU_SH7763]    = "SH7763",     [CPU_SH7770]    = "SH7770",
        [CPU_SH7780]    = "SH7780",     [CPU_SH7781]    = "SH7781",
        [CPU_SH7343]    = "SH7343",     [CPU_SH7785]    = "SH7785",
+       [CPU_SH7786]    = "SH7786",
        [CPU_SH7722]    = "SH7722",     [CPU_SHX3]      = "SH-X3",
        [CPU_SH5_101]   = "SH5-101",    [CPU_SH5_103]   = "SH5-103",
        [CPU_MXG]       = "MX-G",       [CPU_SH7723]    = "SH7723",
@@ -448,7 +449,7 @@ EXPORT_SYMBOL(get_cpu_subtype);
 /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
 static const char *cpu_flags[] = {
        "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
-       "ptea", "llsc", "l2", "op32", NULL
+       "ptea", "llsc", "l2", "op32", "pteaex", NULL
 };
 
 static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/swsusp.c b/arch/sh/kernel/swsusp.c
new file mode 100644 (file)
index 0000000..12b64a0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * swsusp.c - SuperH hibernation support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/sections.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/fpu.h>
+
+struct swsusp_arch_regs swsusp_arch_regs_cpu0;
+
+int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+       unsigned long end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
+
+       return (pfn >= begin_pfn) && (pfn < end_pfn);
+}
+
+void save_processor_state(void)
+{
+       init_fpu(current);
+}
+
+void restore_processor_state(void)
+{
+       local_flush_tlb_all();
+}
index 8457f83242c536a35cc47fb6086a64e01bdb0a80..c34e1e0f9b025072e8fb056d727a61e652656193 100644 (file)
@@ -41,14 +41,6 @@ static int null_rtc_set_time(const time_t secs)
        return 0;
 }
 
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
-       return 0;
-}
-
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
@@ -112,7 +104,6 @@ int do_settimeofday(struct timespec *tv)
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /* last time the RTC clock got updated */
 static long last_rtc_update;
 
@@ -156,7 +147,6 @@ void handle_timer_tick(void)
        update_process_times(user_mode(get_irq_regs()));
 #endif
 }
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 #ifdef CONFIG_PM
 int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -189,7 +179,12 @@ static struct sysdev_class timer_sysclass = {
 
 static int __init timer_init_sysfs(void)
 {
-       int ret = sysdev_class_register(&timer_sysclass);
+       int ret;
+
+       if (!sys_timer)
+               return 0;
+
+       ret = sysdev_class_register(&timer_sysclass);
        if (ret != 0)
                return ret;
 
@@ -200,42 +195,21 @@ device_initcall(timer_init_sysfs);
 
 void (*board_time_init)(void);
 
-/*
- * Shamelessly based on the MIPS and Sparc64 work.
- */
-static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-unsigned long sh_hpt_frequency = 0;
-
-#define NSEC_PER_CYC_SHIFT     10
-
-static struct clocksource clocksource_sh = {
+struct clocksource clocksource_sh = {
        .name           = "SuperH",
-       .rating         = 200,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .read           = null_hpt_read,
-       .shift          = 16,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init init_sh_clocksource(void)
-{
-       if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
-               return;
-
-       clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
-                                                 clocksource_sh.shift);
-
-       timer_ticks_per_nsec_quotient =
-               clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
-
-       clocksource_register(&clocksource_sh);
-}
-
 #ifdef CONFIG_GENERIC_TIME
 unsigned long long sched_clock(void)
 {
-       unsigned long long ticks = clocksource_sh.read();
-       return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
+       unsigned long long cycles;
+
+       /* jiffies based sched_clock if no clocksource is installed */
+       if (!clocksource_sh.rating)
+               return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ);
+
+       cycles = clocksource_sh.read();
+       return cyc2ns(&clocksource_sh, cycles);
 }
 #endif
 
@@ -259,17 +233,8 @@ void __init time_init(void)
         * initialized for us.
         */
        sys_timer = get_sys_timer();
-       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-
-
-       if (sys_timer->ops->read)
-               clocksource_sh.read = sys_timer->ops->read;
-
-       init_sh_clocksource();
-
-       if (sh_hpt_frequency)
-               printk("Using %lu.%03lu MHz high precision timer.\n",
-                      ((sh_hpt_frequency + 500) / 1000) / 1000,
-                      ((sh_hpt_frequency + 500) / 1000) % 1000);
+       if (unlikely(!sys_timer))
+               panic("System timer missing.\n");
 
+       printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
 }
index c3d237e1d566e4c91704284b07a8ced28ce2ba1d..9a77ae86b403132a0483c964d2bf83af53794f72 100644 (file)
@@ -35,7 +35,8 @@
 #define MTU2_TSR_1     0xfffe4385
 #define MTU2_TCNT_1    0xfffe4386      /* 16-bit counter */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#if defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7203)
 #define MTU2_TGRA_1    0xfffe4388
 #else
 #define MTU2_TGRA_1    0xfffe438a
index 0db3f95103368fa4c236e4666b38c828d25ac3a2..10b5a6f17cc0a197341458412ba4d5bc906295ac 100644 (file)
@@ -146,7 +146,14 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
        _tmu_clear_status(TMU0);
        _tmu_set_irq(TMU0,tmu0_clockevent.mode != CLOCK_EVT_MODE_ONESHOT);
 
-       evt->event_handler(evt);
+       switch (tmu0_clockevent.mode) {
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_PERIODIC:
+               evt->event_handler(evt);
+               break;
+       default:
+               break;
+       }
 
        return IRQ_HANDLED;
 }
@@ -237,6 +244,7 @@ static int tmu_timer_init(void)
     !defined(CONFIG_CPU_SUBTYPE_SH7721) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7785) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7786) && \
     !defined(CONFIG_CPU_SUBTYPE_SHX3)
        ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
 #endif
@@ -254,7 +262,14 @@ static int tmu_timer_init(void)
 
        _tmu_start(TMU1);
 
-       sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+       clocksource_sh.rating = 200;
+       clocksource_sh.mask = CLOCKSOURCE_MASK(32);
+       clocksource_sh.read = tmu_timer_read;
+       clocksource_sh.shift = 10;
+       clocksource_sh.mult = clocksource_hz2mult(clk_get_rate(&tmu1_clk),
+                                                 clocksource_sh.shift);
+       clocksource_sh.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+       clocksource_register(&clocksource_sh);
 
        tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
                                      tmu0_clockevent.shift);
@@ -264,6 +279,7 @@ static int tmu_timer_init(void)
                        clockevent_delta2ns(1, &tmu0_clockevent);
 
        tmu0_clockevent.cpumask = cpumask_of(0);
+       tmu0_clockevent.rating = 100;
 
        clockevents_register_device(&tmu0_clockevent);
 
@@ -274,7 +290,6 @@ static struct sys_timer_ops tmu_timer_ops = {
        .init           = tmu_timer_init,
        .start          = tmu_timer_start,
        .stop           = tmu_timer_stop,
-       .read           = tmu_timer_read,
 };
 
 struct sys_timer tmu_timer = {
index 7b4b82bd1156bc8c373fb61fe4edce6ab82d6a4b..d0b2a715cd14de730223a7036834201a249d44df 100644 (file)
@@ -15,7 +15,10 @@ OUTPUT_ARCH(sh)
 ENTRY(_start)
 SECTIONS
 {
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB_FIXED
+       . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) +
+           CONFIG_ZERO_PAGE_OFFSET;
+#elif defined(CONFIG_32BIT)
        . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
 #else
        . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
index 555ec9714b9e042c6e5f6247515d5e0343021e83..10c24356d2d5343b055e3fd304b133abfb3daa6e 100644 (file)
@@ -57,7 +57,7 @@ config 32BIT
        bool
        default y if CPU_SH5
 
-config PMB
+config PMB_ENABLE
        bool "Support 32-bit physical addressing through PMB"
        depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
        select 32BIT
@@ -67,6 +67,33 @@ config PMB
          32-bits through the SH-4A PMB. If this is not set, legacy
          29-bit physical addressing will be used.
 
+choice
+       prompt "PMB handling type"
+       depends on PMB_ENABLE
+       default PMB_FIXED
+
+config PMB
+       bool "PMB"
+       depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
+       select 32BIT
+       help
+         If you say Y here, physical addressing will be extended to
+         32-bits through the SH-4A PMB. If this is not set, legacy
+         29-bit physical addressing will be used.
+
+config PMB_FIXED
+       bool "fixed PMB"
+       depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || \
+                                          CPU_SUBTYPE_SH7785)
+       select 32BIT
+       help
+         If this option is enabled, fixed PMB mappings are inherited
+         from the boot loader, and the kernel does not attempt dynamic
+         management. This is the closest to legacy 29-bit physical mode,
+         and allows systems to support up to 512MiB of system memory.
+
+endchoice
+
 config X2TLB
        bool "Enable extended TLB mode"
        depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL
index cb2f3f2995914003c5f1966362be9b325df9a90f..986a1e0558348dfe2d8ef11873350918a28639ac 100644 (file)
@@ -25,8 +25,10 @@ obj-$(CONFIG_CPU_SH4)        += cache-debugfs.o
 endif
 
 ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3)  += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4)  += tlb-sh4.o
+tlb-$(CONFIG_CPU_SH3)          := tlb-sh3.o
+tlb-$(CONFIG_CPU_SH4)          := tlb-sh4.o
+tlb-$(CONFIG_CPU_HAS_PTEAEX)   := tlb-pteaex.o
+obj-y                          += $(tlb-y)
 ifndef CONFIG_CACHE_OFF
 obj-$(CONFIG_CPU_SH4)          += pg-sh4.o
 obj-$(CONFIG_SH7705_CACHE_32KB)        += pg-sh7705.o
@@ -35,6 +37,7 @@ endif
 
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_PMB)              += pmb.o
+obj-$(CONFIG_PMB_FIXED)                += pmb-fixed.o
 obj-$(CONFIG_NUMA)             += numa.o
 
 EXTRA_CFLAGS += -Werror
index 8e912a15e94f4583e1f4a8fe488b1dc45128e766..cd8c3bf39b5a8390efbc22df4e8523af05714d99 100644 (file)
@@ -37,10 +37,8 @@ static int asids_seq_show(struct seq_file *file, void *iter)
                        continue;
 
                if (p->mm)
-                       seq_printf(file, "%5d : %02lx\n", pid,
+                       seq_printf(file, "%5d : %04lx\n", pid,
                                   cpu_asid(smp_processor_id(), p->mm));
-               else
-                       seq_printf(file, "%5d : (none)\n", pid);
        }
 
        read_unlock(&tasklist_lock);
index 32946fba123e597046a7316f49150a1b6d3be8ea..60cc486d2c2cc71f0f3b45df5b9bc4e856ae5a58 100644 (file)
@@ -59,11 +59,13 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
                return (void __iomem *)phys_addr;
 
+#if !defined(CONFIG_PMB_FIXED)
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
        if (phys_addr < virt_to_phys(high_memory))
                return NULL;
+#endif
 
        /*
         * Mappings have to be page-aligned
@@ -81,7 +83,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        area->phys_addr = phys_addr;
        orig_addr = addr = (unsigned long)area->addr;
 
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB
        /*
         * First try to remap through the PMB once a valid VMA has been
         * established. Smaller allocations (or the rest of the size
@@ -119,10 +121,10 @@ void __iounmap(void __iomem *addr)
        unsigned long seg = PXSEG(vaddr);
        struct vm_struct *p;
 
-       if (seg < P3SEG || seg >= P3_ADDR_MAX || is_pci_memaddr(vaddr))
+       if (seg < P3SEG || vaddr >= P3_ADDR_MAX || is_pci_memaddr(vaddr))
                return;
 
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB
        /*
         * Purge any PMB entries that may have been established for this
         * mapping, then proceed with conventional VMA teardown.
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c
new file mode 100644 (file)
index 0000000..43c8eac
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/sh/mm/fixed_pmb.c
+ *
+ * Copyright (C) 2009  Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+
+static int __uses_jump_to_uncached fixed_pmb_init(void)
+{
+       int i;
+       unsigned long addr, data;
+
+       jump_to_uncached();
+
+       for (i = 0; i < PMB_ENTRY_MAX; i++) {
+               addr = PMB_DATA + (i << PMB_E_SHIFT);
+               data = ctrl_inl(addr);
+               if (!(data & PMB_V))
+                       continue;
+
+               if (data & PMB_C) {
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+                       data |= PMB_WT;
+#elif defined(CONFIG_CACHE_WRITEBACK)
+                       data &= ~PMB_WT;
+#else
+                       data &= ~(PMB_C | PMB_WT);
+#endif
+               }
+               ctrl_outl(data, addr);
+       }
+
+       back_to_cached();
+
+       return 0;
+}
+arch_initcall(fixed_pmb_init);
index 84241676265e61455f4e9579f7cf41810601f1e9..b1a714a92b14fe4fcb8d029d6100456b3cc46d5b 100644 (file)
@@ -15,6 +15,8 @@
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/bitops.h>
@@ -402,3 +404,39 @@ static int __init pmb_debugfs_init(void)
        return 0;
 }
 postcore_initcall(pmb_debugfs_init);
+
+#ifdef CONFIG_PM
+static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+       static pm_message_t prev_state;
+
+       /* Restore the PMB after a resume from hibernation */
+       if (state.event == PM_EVENT_ON &&
+           prev_state.event == PM_EVENT_FREEZE) {
+               struct pmb_entry *pmbe;
+               spin_lock_irq(&pmb_list_lock);
+               for (pmbe = pmb_list; pmbe; pmbe = pmbe->next)
+                       set_pmb_entry(pmbe);
+               spin_unlock_irq(&pmb_list_lock);
+       }
+       prev_state = state;
+       return 0;
+}
+
+static int pmb_sysdev_resume(struct sys_device *dev)
+{
+       return pmb_sysdev_suspend(dev, PMSG_ON);
+}
+
+static struct sysdev_driver pmb_sysdev_driver = {
+       .suspend = pmb_sysdev_suspend,
+       .resume = pmb_sysdev_resume,
+};
+
+static int __init pmb_sysdev_init(void)
+{
+       return sysdev_driver_register(&cpu_sysdev_class, &pmb_sysdev_driver);
+}
+
+subsys_initcall(pmb_sysdev_init);
+#endif
diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c
new file mode 100644 (file)
index 0000000..2aab3ea
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * arch/sh/mm/tlb-pteaex.c
+ *
+ * TLB operations for SH-X3 CPUs featuring PTE ASID Extensions.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+void update_mmu_cache(struct vm_area_struct * vma,
+                     unsigned long address, pte_t pte)
+{
+       unsigned long flags;
+       unsigned long pteval;
+       unsigned long vpn;
+
+       /* Ptrace may call this routine. */
+       if (vma && current->active_mm != vma->vm_mm)
+               return;
+
+#ifndef CONFIG_CACHE_OFF
+       {
+               unsigned long pfn = pte_pfn(pte);
+
+               if (pfn_valid(pfn)) {
+                       struct page *page = pfn_to_page(pfn);
+
+                       if (!test_bit(PG_mapped, &page->flags)) {
+                               unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+                               __flush_wback_region((void *)P1SEGADDR(phys),
+                                                    PAGE_SIZE);
+                               __set_bit(PG_mapped, &page->flags);
+                       }
+               }
+       }
+#endif
+
+       local_irq_save(flags);
+
+       /* Set PTEH register */
+       vpn = address & MMU_VPN_MASK;
+       __raw_writel(vpn, MMU_PTEH);
+
+       /* Set PTEAEX */
+       __raw_writel(get_asid(), MMU_PTEAEX);
+
+       pteval = pte.pte_low;
+
+       /* Set PTEA register */
+#ifdef CONFIG_X2TLB
+       /*
+        * For the extended mode TLB this is trivial, only the ESZ and
+        * EPR bits need to be written out to PTEA, with the remainder of
+        * the protection bits (with the exception of the compat-mode SZ
+        * and PR bits, which are cleared) being written out in PTEL.
+        */
+       __raw_writel(pte.pte_high, MMU_PTEA);
+#endif
+
+       /* Set PTEL register */
+       pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+#ifdef CONFIG_CACHE_WRITETHROUGH
+       pteval |= _PAGE_WT;
+#endif
+       /* conveniently, we want all the software flags to be 0 anyway */
+       __raw_writel(pteval, MMU_PTEL);
+
+       /* Load the TLB */
+       asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
+       local_irq_restore(flags);
+}
+
+/*
+ * While SH-X2 extended TLB mode splits out the memory-mapped I/UTLB
+ * data arrays, SH-X3 cores with PTEAEX split out the memory-mapped
+ * address arrays. In compat mode the second array is inaccessible, while
+ * in extended mode, the legacy 8-bit ASID field in address array 1 has
+ * undefined behaviour.
+ */
+void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid,
+                                                unsigned long page)
+{
+       jump_to_uncached();
+       __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT);
+       __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT);
+       back_to_cached();
+}
index 1d97d64cb95fa68cfece09c0d6abec4c97890c16..1b9d4304b3bf796b4561aaffe201ff06ca3300d7 100644 (file)
@@ -107,6 +107,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        case CPU_SH7780:
        case CPU_SH7781:
        case CPU_SH7785:
+       case CPU_SH7786:
        case CPU_SH7723:
        case CPU_SHX3:
                lmodel = &op_model_sh4a_ops;
index 284b7e86749685cc7fe25157edcaf7e8e9bf0dcb..8477b5d884fd1147fa743e9f0bbba1767e672ff1 100644 (file)
@@ -52,3 +52,6 @@ RSK7203                       SH_RSK7203
 AP325RXA               SH_AP325RXA
 SH7763RDP              SH_SH7763RDP
 SH7785LCR              SH_SH7785LCR
+URQUELL                        SH_URQUELL
+ESPT                   SH_ESPT
+POLARIS                        SH_POLARIS
index 903de4aa509496205cf792980d1b6f57b3d87177..ebe7deedd5b42b27974b1b8884e1b68bdebb82cb 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
+obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
 
 obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
 
@@ -19,3 +20,5 @@ salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
+
+aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
index e41b147f45093009d9dbda30c314d1d4d748d3a5..b949ec2f9af444e06377492d39b9db9960f3a626 100644 (file)
 #define tlen 1024   // length of each of 4 'xor' arrays (256 32-bit words)
 
 /* offsets to parameters with one register pushed onto stack */
-#define tfm 8
+#define ctx 8
 #define out_blk 12
 #define in_blk 16
 
-/* offsets in crypto_tfm structure */
-#define klen (crypto_tfm_ctx_offset + 0)
-#define ekey (crypto_tfm_ctx_offset + 4)
-#define dkey (crypto_tfm_ctx_offset + 244)
+/* offsets in crypto_aes_ctx structure */
+#define klen (480)
+#define ekey (0)
+#define dkey (240)
 
 // register mapping for encrypt and decrypt subroutines
 
        do_col (table, r5,r0,r1,r4, r2,r3);             /* idx=r5 */
 
 // AES (Rijndael) Encryption Subroutine
-/* void aes_enc_blk(struct crypto_tfm *tfm, u8 *out_blk, const u8 *in_blk) */
+/* void aes_enc_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */
 
 .global  aes_enc_blk
 
 
 aes_enc_blk:
        push    %ebp
-       mov     tfm(%esp),%ebp
+       mov     ctx(%esp),%ebp
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
@@ -292,7 +292,7 @@ aes_enc_blk:
        ret
 
 // AES (Rijndael) Decryption Subroutine
-/* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out_blk, const u8 *in_blk) */
+/* void aes_dec_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */
 
 .global  aes_dec_blk
 
@@ -303,7 +303,7 @@ aes_enc_blk:
 
 aes_dec_blk:
        push    %ebp
-       mov     tfm(%esp),%ebp
+       mov     ctx(%esp),%ebp
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
index a120f526c3df9d9c547b996867f1b035b44b006b..5b577d5a059b03db65d587e1eb15495d0ba99fa1 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <asm/asm-offsets.h>
 
-#define BASE crypto_tfm_ctx_offset
-
 #define R1     %rax
 #define R1E    %eax
 #define R1X    %ax
        .align  8;                      \
 FUNC:  movq    r1,r2;                  \
        movq    r3,r4;                  \
-       leaq    BASE+KEY+48+4(r8),r9;   \
+       leaq    KEY+48(r8),r9;          \
        movq    r10,r11;                \
        movl    (r7),r5 ## E;           \
        movl    4(r7),r1 ## E;          \
        movl    8(r7),r6 ## E;          \
        movl    12(r7),r7 ## E;         \
-       movl    BASE+0(r8),r10 ## E;    \
+       movl    480(r8),r10 ## E;       \
        xorl    -48(r9),r5 ## E;        \
        xorl    -44(r9),r1 ## E;        \
        xorl    -40(r9),r6 ## E;        \
index 71f457827116bee654f4f5c67edebfe8117697c9..49ae9fe32b22079dc22c8d0bf121410285010d3d 100644 (file)
@@ -5,17 +5,29 @@
 
 #include <crypto/aes.h>
 
-asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
-asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+asmlinkage void aes_enc_blk(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in);
+asmlinkage void aes_dec_blk(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in);
+
+void crypto_aes_encrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+{
+       aes_enc_blk(ctx, dst, src);
+}
+EXPORT_SYMBOL_GPL(crypto_aes_encrypt_x86);
+
+void crypto_aes_decrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+{
+       aes_dec_blk(ctx, dst, src);
+}
+EXPORT_SYMBOL_GPL(crypto_aes_decrypt_x86);
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-       aes_enc_blk(tfm, dst, src);
+       aes_enc_blk(crypto_tfm_ctx(tfm), dst, src);
 }
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-       aes_dec_blk(tfm, dst, src);
+       aes_dec_blk(crypto_tfm_ctx(tfm), dst, src);
 }
 
 static struct crypto_alg aes_alg = {
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
new file mode 100644 (file)
index 0000000..caba996
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ * Implement AES algorithm in Intel AES-NI instructions.
+ *
+ * The white paper of AES-NI instructions can be downloaded from:
+ *   http://softwarecommunity.intel.com/isn/downloads/intelavx/AES-Instructions-Set_WP.pdf
+ *
+ * Copyright (C) 2008, Intel Corp.
+ *    Author: Huang Ying <ying.huang@intel.com>
+ *            Vinodh Gopal <vinodh.gopal@intel.com>
+ *            Kahraman Akdemir
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/linkage.h>
+
+.text
+
+#define STATE1 %xmm0
+#define STATE2 %xmm4
+#define STATE3 %xmm5
+#define STATE4 %xmm6
+#define STATE  STATE1
+#define IN1    %xmm1
+#define IN2    %xmm7
+#define IN3    %xmm8
+#define IN4    %xmm9
+#define IN     IN1
+#define KEY    %xmm2
+#define IV     %xmm3
+
+#define KEYP   %rdi
+#define OUTP   %rsi
+#define INP    %rdx
+#define LEN    %rcx
+#define IVP    %r8
+#define KLEN   %r9d
+#define T1     %r10
+#define TKEYP  T1
+#define T2     %r11
+
+_key_expansion_128:
+_key_expansion_256a:
+       pshufd $0b11111111, %xmm1, %xmm1
+       shufps $0b00010000, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       shufps $0b10001100, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       pxor %xmm1, %xmm0
+       movaps %xmm0, (%rcx)
+       add $0x10, %rcx
+       ret
+
+_key_expansion_192a:
+       pshufd $0b01010101, %xmm1, %xmm1
+       shufps $0b00010000, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       shufps $0b10001100, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       pxor %xmm1, %xmm0
+
+       movaps %xmm2, %xmm5
+       movaps %xmm2, %xmm6
+       pslldq $4, %xmm5
+       pshufd $0b11111111, %xmm0, %xmm3
+       pxor %xmm3, %xmm2
+       pxor %xmm5, %xmm2
+
+       movaps %xmm0, %xmm1
+       shufps $0b01000100, %xmm0, %xmm6
+       movaps %xmm6, (%rcx)
+       shufps $0b01001110, %xmm2, %xmm1
+       movaps %xmm1, 16(%rcx)
+       add $0x20, %rcx
+       ret
+
+_key_expansion_192b:
+       pshufd $0b01010101, %xmm1, %xmm1
+       shufps $0b00010000, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       shufps $0b10001100, %xmm0, %xmm4
+       pxor %xmm4, %xmm0
+       pxor %xmm1, %xmm0
+
+       movaps %xmm2, %xmm5
+       pslldq $4, %xmm5
+       pshufd $0b11111111, %xmm0, %xmm3
+       pxor %xmm3, %xmm2
+       pxor %xmm5, %xmm2
+
+       movaps %xmm0, (%rcx)
+       add $0x10, %rcx
+       ret
+
+_key_expansion_256b:
+       pshufd $0b10101010, %xmm1, %xmm1
+       shufps $0b00010000, %xmm2, %xmm4
+       pxor %xmm4, %xmm2
+       shufps $0b10001100, %xmm2, %xmm4
+       pxor %xmm4, %xmm2
+       pxor %xmm1, %xmm2
+       movaps %xmm2, (%rcx)
+       add $0x10, %rcx
+       ret
+
+/*
+ * int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
+ *                   unsigned int key_len)
+ */
+ENTRY(aesni_set_key)
+       movups (%rsi), %xmm0            # user key (first 16 bytes)
+       movaps %xmm0, (%rdi)
+       lea 0x10(%rdi), %rcx            # key addr
+       movl %edx, 480(%rdi)
+       pxor %xmm4, %xmm4               # xmm4 is assumed 0 in _key_expansion_x
+       cmp $24, %dl
+       jb .Lenc_key128
+       je .Lenc_key192
+       movups 0x10(%rsi), %xmm2        # other user key
+       movaps %xmm2, (%rcx)
+       add $0x10, %rcx
+       # aeskeygenassist $0x1, %xmm2, %xmm1    # round 1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x01
+       call _key_expansion_256a
+       # aeskeygenassist $0x1, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x01
+       call _key_expansion_256b
+       # aeskeygenassist $0x2, %xmm2, %xmm1    # round 2
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x02
+       call _key_expansion_256a
+       # aeskeygenassist $0x2, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x02
+       call _key_expansion_256b
+       # aeskeygenassist $0x4, %xmm2, %xmm1    # round 3
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x04
+       call _key_expansion_256a
+       # aeskeygenassist $0x4, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x04
+       call _key_expansion_256b
+       # aeskeygenassist $0x8, %xmm2, %xmm1    # round 4
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x08
+       call _key_expansion_256a
+       # aeskeygenassist $0x8, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x08
+       call _key_expansion_256b
+       # aeskeygenassist $0x10, %xmm2, %xmm1   # round 5
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x10
+       call _key_expansion_256a
+       # aeskeygenassist $0x10, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x10
+       call _key_expansion_256b
+       # aeskeygenassist $0x20, %xmm2, %xmm1   # round 6
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x20
+       call _key_expansion_256a
+       # aeskeygenassist $0x20, %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x20
+       call _key_expansion_256b
+       # aeskeygenassist $0x40, %xmm2, %xmm1   # round 7
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x40
+       call _key_expansion_256a
+       jmp .Ldec_key
+.Lenc_key192:
+       movq 0x10(%rsi), %xmm2          # other user key
+       # aeskeygenassist $0x1, %xmm2, %xmm1    # round 1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x01
+       call _key_expansion_192a
+       # aeskeygenassist $0x2, %xmm2, %xmm1    # round 2
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x02
+       call _key_expansion_192b
+       # aeskeygenassist $0x4, %xmm2, %xmm1    # round 3
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x04
+       call _key_expansion_192a
+       # aeskeygenassist $0x8, %xmm2, %xmm1    # round 4
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x08
+       call _key_expansion_192b
+       # aeskeygenassist $0x10, %xmm2, %xmm1   # round 5
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x10
+       call _key_expansion_192a
+       # aeskeygenassist $0x20, %xmm2, %xmm1   # round 6
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x20
+       call _key_expansion_192b
+       # aeskeygenassist $0x40, %xmm2, %xmm1   # round 7
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x40
+       call _key_expansion_192a
+       # aeskeygenassist $0x80, %xmm2, %xmm1   # round 8
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x80
+       call _key_expansion_192b
+       jmp .Ldec_key
+.Lenc_key128:
+       # aeskeygenassist $0x1, %xmm0, %xmm1    # round 1
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x01
+       call _key_expansion_128
+       # aeskeygenassist $0x2, %xmm0, %xmm1    # round 2
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x02
+       call _key_expansion_128
+       # aeskeygenassist $0x4, %xmm0, %xmm1    # round 3
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x04
+       call _key_expansion_128
+       # aeskeygenassist $0x8, %xmm0, %xmm1    # round 4
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x08
+       call _key_expansion_128
+       # aeskeygenassist $0x10, %xmm0, %xmm1   # round 5
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x10
+       call _key_expansion_128
+       # aeskeygenassist $0x20, %xmm0, %xmm1   # round 6
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x20
+       call _key_expansion_128
+       # aeskeygenassist $0x40, %xmm0, %xmm1   # round 7
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x40
+       call _key_expansion_128
+       # aeskeygenassist $0x80, %xmm0, %xmm1   # round 8
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x80
+       call _key_expansion_128
+       # aeskeygenassist $0x1b, %xmm0, %xmm1   # round 9
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x1b
+       call _key_expansion_128
+       # aeskeygenassist $0x36, %xmm0, %xmm1   # round 10
+       .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x36
+       call _key_expansion_128
+.Ldec_key:
+       sub $0x10, %rcx
+       movaps (%rdi), %xmm0
+       movaps (%rcx), %xmm1
+       movaps %xmm0, 240(%rcx)
+       movaps %xmm1, 240(%rdi)
+       add $0x10, %rdi
+       lea 240-16(%rcx), %rsi
+.align 4
+.Ldec_key_loop:
+       movaps (%rdi), %xmm0
+       # aesimc %xmm0, %xmm1
+       .byte 0x66, 0x0f, 0x38, 0xdb, 0xc8
+       movaps %xmm1, (%rsi)
+       add $0x10, %rdi
+       sub $0x10, %rsi
+       cmp %rcx, %rdi
+       jb .Ldec_key_loop
+       xor %rax, %rax
+       ret
+
+/*
+ * void aesni_enc(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+ */
+ENTRY(aesni_enc)
+       movl 480(KEYP), KLEN            # key length
+       movups (INP), STATE             # input
+       call _aesni_enc1
+       movups STATE, (OUTP)            # output
+       ret
+
+/*
+ * _aesni_enc1:                internal ABI
+ * input:
+ *     KEYP:           key struct pointer
+ *     KLEN:           round count
+ *     STATE:          initial state (input)
+ * output:
+ *     STATE:          finial state (output)
+ * changed:
+ *     KEY
+ *     TKEYP (T1)
+ */
+_aesni_enc1:
+       movaps (KEYP), KEY              # key
+       mov KEYP, TKEYP
+       pxor KEY, STATE         # round 0
+       add $0x30, TKEYP
+       cmp $24, KLEN
+       jb .Lenc128
+       lea 0x20(TKEYP), TKEYP
+       je .Lenc192
+       add $0x20, TKEYP
+       movaps -0x60(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps -0x50(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+.align 4
+.Lenc192:
+       movaps -0x40(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps -0x30(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+.align 4
+.Lenc128:
+       movaps -0x20(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps -0x10(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps (TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x10(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x20(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x30(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x40(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x50(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x60(TKEYP), KEY
+       # aesenc KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       movaps 0x70(TKEYP), KEY
+       # aesenclast KEY, STATE # last round
+       .byte 0x66, 0x0f, 0x38, 0xdd, 0xc2
+       ret
+
+/*
+ * _aesni_enc4:        internal ABI
+ * input:
+ *     KEYP:           key struct pointer
+ *     KLEN:           round count
+ *     STATE1:         initial state (input)
+ *     STATE2
+ *     STATE3
+ *     STATE4
+ * output:
+ *     STATE1:         finial state (output)
+ *     STATE2
+ *     STATE3
+ *     STATE4
+ * changed:
+ *     KEY
+ *     TKEYP (T1)
+ */
+_aesni_enc4:
+       movaps (KEYP), KEY              # key
+       mov KEYP, TKEYP
+       pxor KEY, STATE1                # round 0
+       pxor KEY, STATE2
+       pxor KEY, STATE3
+       pxor KEY, STATE4
+       add $0x30, TKEYP
+       cmp $24, KLEN
+       jb .L4enc128
+       lea 0x20(TKEYP), TKEYP
+       je .L4enc192
+       add $0x20, TKEYP
+       movaps -0x60(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps -0x50(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+#.align 4
+.L4enc192:
+       movaps -0x40(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps -0x30(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+#.align 4
+.L4enc128:
+       movaps -0x20(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps -0x10(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps (TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x10(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x20(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x30(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x40(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x50(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x60(TKEYP), KEY
+       # aesenc KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+       # aesenc KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
+       # aesenc KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
+       # aesenc KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+       movaps 0x70(TKEYP), KEY
+       # aesenclast KEY, STATE1        # last round
+       .byte 0x66, 0x0f, 0x38, 0xdd, 0xc2
+       # aesenclast KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdd, 0xe2
+       # aesenclast KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdd, 0xea
+       # aesenclast KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdd, 0xf2
+       ret
+
+/*
+ * void aesni_dec (struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+ */
+ENTRY(aesni_dec)
+       mov 480(KEYP), KLEN             # key length
+       add $240, KEYP
+       movups (INP), STATE             # input
+       call _aesni_dec1
+       movups STATE, (OUTP)            #output
+       ret
+
+/*
+ * _aesni_dec1:                internal ABI
+ * input:
+ *     KEYP:           key struct pointer
+ *     KLEN:           key length
+ *     STATE:          initial state (input)
+ * output:
+ *     STATE:          finial state (output)
+ * changed:
+ *     KEY
+ *     TKEYP (T1)
+ */
+_aesni_dec1:
+       movaps (KEYP), KEY              # key
+       mov KEYP, TKEYP
+       pxor KEY, STATE         # round 0
+       add $0x30, TKEYP
+       cmp $24, KLEN
+       jb .Ldec128
+       lea 0x20(TKEYP), TKEYP
+       je .Ldec192
+       add $0x20, TKEYP
+       movaps -0x60(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps -0x50(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+.align 4
+.Ldec192:
+       movaps -0x40(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps -0x30(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+.align 4
+.Ldec128:
+       movaps -0x20(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps -0x10(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps (TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x10(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x20(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x30(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x40(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x50(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x60(TKEYP), KEY
+       # aesdec KEY, STATE
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       movaps 0x70(TKEYP), KEY
+       # aesdeclast KEY, STATE         # last round
+       .byte 0x66, 0x0f, 0x38, 0xdf, 0xc2
+       ret
+
+/*
+ * _aesni_dec4:        internal ABI
+ * input:
+ *     KEYP:           key struct pointer
+ *     KLEN:           key length
+ *     STATE1:         initial state (input)
+ *     STATE2
+ *     STATE3
+ *     STATE4
+ * output:
+ *     STATE1:         finial state (output)
+ *     STATE2
+ *     STATE3
+ *     STATE4
+ * changed:
+ *     KEY
+ *     TKEYP (T1)
+ */
+_aesni_dec4:
+       movaps (KEYP), KEY              # key
+       mov KEYP, TKEYP
+       pxor KEY, STATE1                # round 0
+       pxor KEY, STATE2
+       pxor KEY, STATE3
+       pxor KEY, STATE4
+       add $0x30, TKEYP
+       cmp $24, KLEN
+       jb .L4dec128
+       lea 0x20(TKEYP), TKEYP
+       je .L4dec192
+       add $0x20, TKEYP
+       movaps -0x60(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps -0x50(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+.align 4
+.L4dec192:
+       movaps -0x40(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps -0x30(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+.align 4
+.L4dec128:
+       movaps -0x20(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps -0x10(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps (TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x10(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x20(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x30(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x40(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x50(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x60(TKEYP), KEY
+       # aesdec KEY, STATE1
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+       # aesdec KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
+       # aesdec KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xea
+       # aesdec KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+       movaps 0x70(TKEYP), KEY
+       # aesdeclast KEY, STATE1        # last round
+       .byte 0x66, 0x0f, 0x38, 0xdf, 0xc2
+       # aesdeclast KEY, STATE2
+       .byte 0x66, 0x0f, 0x38, 0xdf, 0xe2
+       # aesdeclast KEY, STATE3
+       .byte 0x66, 0x0f, 0x38, 0xdf, 0xea
+       # aesdeclast KEY, STATE4
+       .byte 0x66, 0x0f, 0x38, 0xdf, 0xf2
+       ret
+
+/*
+ * void aesni_ecb_enc(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
+ *                   size_t len)
+ */
+ENTRY(aesni_ecb_enc)
+       test LEN, LEN           # check length
+       jz .Lecb_enc_ret
+       mov 480(KEYP), KLEN
+       cmp $16, LEN
+       jb .Lecb_enc_ret
+       cmp $64, LEN
+       jb .Lecb_enc_loop1
+.align 4
+.Lecb_enc_loop4:
+       movups (INP), STATE1
+       movups 0x10(INP), STATE2
+       movups 0x20(INP), STATE3
+       movups 0x30(INP), STATE4
+       call _aesni_enc4
+       movups STATE1, (OUTP)
+       movups STATE2, 0x10(OUTP)
+       movups STATE3, 0x20(OUTP)
+       movups STATE4, 0x30(OUTP)
+       sub $64, LEN
+       add $64, INP
+       add $64, OUTP
+       cmp $64, LEN
+       jge .Lecb_enc_loop4
+       cmp $16, LEN
+       jb .Lecb_enc_ret
+.align 4
+.Lecb_enc_loop1:
+       movups (INP), STATE1
+       call _aesni_enc1
+       movups STATE1, (OUTP)
+       sub $16, LEN
+       add $16, INP
+       add $16, OUTP
+       cmp $16, LEN
+       jge .Lecb_enc_loop1
+.Lecb_enc_ret:
+       ret
+
+/*
+ * void aesni_ecb_dec(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
+ *                   size_t len);
+ */
+ENTRY(aesni_ecb_dec)
+       test LEN, LEN
+       jz .Lecb_dec_ret
+       mov 480(KEYP), KLEN
+       add $240, KEYP
+       cmp $16, LEN
+       jb .Lecb_dec_ret
+       cmp $64, LEN
+       jb .Lecb_dec_loop1
+.align 4
+.Lecb_dec_loop4:
+       movups (INP), STATE1
+       movups 0x10(INP), STATE2
+       movups 0x20(INP), STATE3
+       movups 0x30(INP), STATE4
+       call _aesni_dec4
+       movups STATE1, (OUTP)
+       movups STATE2, 0x10(OUTP)
+       movups STATE3, 0x20(OUTP)
+       movups STATE4, 0x30(OUTP)
+       sub $64, LEN
+       add $64, INP
+       add $64, OUTP
+       cmp $64, LEN
+       jge .Lecb_dec_loop4
+       cmp $16, LEN
+       jb .Lecb_dec_ret
+.align 4
+.Lecb_dec_loop1:
+       movups (INP), STATE1
+       call _aesni_dec1
+       movups STATE1, (OUTP)
+       sub $16, LEN
+       add $16, INP
+       add $16, OUTP
+       cmp $16, LEN
+       jge .Lecb_dec_loop1
+.Lecb_dec_ret:
+       ret
+
+/*
+ * void aesni_cbc_enc(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
+ *                   size_t len, u8 *iv)
+ */
+ENTRY(aesni_cbc_enc)
+       cmp $16, LEN
+       jb .Lcbc_enc_ret
+       mov 480(KEYP), KLEN
+       movups (IVP), STATE     # load iv as initial state
+.align 4
+.Lcbc_enc_loop:
+       movups (INP), IN        # load input
+       pxor IN, STATE
+       call _aesni_enc1
+       movups STATE, (OUTP)    # store output
+       sub $16, LEN
+       add $16, INP
+       add $16, OUTP
+       cmp $16, LEN
+       jge .Lcbc_enc_loop
+       movups STATE, (IVP)
+.Lcbc_enc_ret:
+       ret
+
+/*
+ * void aesni_cbc_dec(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
+ *                   size_t len, u8 *iv)
+ */
+ENTRY(aesni_cbc_dec)
+       cmp $16, LEN
+       jb .Lcbc_dec_ret
+       mov 480(KEYP), KLEN
+       add $240, KEYP
+       movups (IVP), IV
+       cmp $64, LEN
+       jb .Lcbc_dec_loop1
+.align 4
+.Lcbc_dec_loop4:
+       movups (INP), IN1
+       movaps IN1, STATE1
+       movups 0x10(INP), IN2
+       movaps IN2, STATE2
+       movups 0x20(INP), IN3
+       movaps IN3, STATE3
+       movups 0x30(INP), IN4
+       movaps IN4, STATE4
+       call _aesni_dec4
+       pxor IV, STATE1
+       pxor IN1, STATE2
+       pxor IN2, STATE3
+       pxor IN3, STATE4
+       movaps IN4, IV
+       movups STATE1, (OUTP)
+       movups STATE2, 0x10(OUTP)
+       movups STATE3, 0x20(OUTP)
+       movups STATE4, 0x30(OUTP)
+       sub $64, LEN
+       add $64, INP
+       add $64, OUTP
+       cmp $64, LEN
+       jge .Lcbc_dec_loop4
+       cmp $16, LEN
+       jb .Lcbc_dec_ret
+.align 4
+.Lcbc_dec_loop1:
+       movups (INP), IN
+       movaps IN, STATE
+       call _aesni_dec1
+       pxor IV, STATE
+       movups STATE, (OUTP)
+       movaps IN, IV
+       sub $16, LEN
+       add $16, INP
+       add $16, OUTP
+       cmp $16, LEN
+       jge .Lcbc_dec_loop1
+       movups IV, (IVP)
+.Lcbc_dec_ret:
+       ret
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
new file mode 100644 (file)
index 0000000..02af0af
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Support for Intel AES-NI instructions. This file contains glue
+ * code, the real AES implementation is in intel-aes_asm.S.
+ *
+ * Copyright (C) 2008, Intel Corp.
+ *    Author: Huang Ying <ying.huang@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.
+ */
+
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/cryptd.h>
+#include <asm/i387.h>
+#include <asm/aes.h>
+
+struct async_aes_ctx {
+       struct cryptd_ablkcipher *cryptd_tfm;
+};
+
+#define AESNI_ALIGN    16
+#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
+
+asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
+                            unsigned int key_len);
+asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out,
+                         const u8 *in);
+asmlinkage void aesni_dec(struct crypto_aes_ctx *ctx, u8 *out,
+                         const u8 *in);
+asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out,
+                             const u8 *in, unsigned int len);
+asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out,
+                             const u8 *in, unsigned int len);
+asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out,
+                             const u8 *in, unsigned int len, u8 *iv);
+asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out,
+                             const u8 *in, unsigned int len, u8 *iv);
+
+static inline int kernel_fpu_using(void)
+{
+       if (in_interrupt() && !(read_cr0() & X86_CR0_TS))
+               return 1;
+       return 0;
+}
+
+static inline struct crypto_aes_ctx *aes_ctx(void *raw_ctx)
+{
+       unsigned long addr = (unsigned long)raw_ctx;
+       unsigned long align = AESNI_ALIGN;
+
+       if (align <= crypto_tfm_ctx_alignment())
+               align = 1;
+       return (struct crypto_aes_ctx *)ALIGN(addr, align);
+}
+
+static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx,
+                             const u8 *in_key, unsigned int key_len)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(raw_ctx);
+       u32 *flags = &tfm->crt_flags;
+       int err;
+
+       if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
+           key_len != AES_KEYSIZE_256) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       if (kernel_fpu_using())
+               err = crypto_aes_expand_key(ctx, in_key, key_len);
+       else {
+               kernel_fpu_begin();
+               err = aesni_set_key(ctx, in_key, key_len);
+               kernel_fpu_end();
+       }
+
+       return err;
+}
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+                      unsigned int key_len)
+{
+       return aes_set_key_common(tfm, crypto_tfm_ctx(tfm), in_key, key_len);
+}
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+       if (kernel_fpu_using())
+               crypto_aes_encrypt_x86(ctx, dst, src);
+       else {
+               kernel_fpu_begin();
+               aesni_enc(ctx, dst, src);
+               kernel_fpu_end();
+       }
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+       if (kernel_fpu_using())
+               crypto_aes_decrypt_x86(ctx, dst, src);
+       else {
+               kernel_fpu_begin();
+               aesni_dec(ctx, dst, src);
+               kernel_fpu_end();
+       }
+}
+
+static struct crypto_alg aesni_alg = {
+       .cra_name               = "aes",
+       .cra_driver_name        = "aes-aesni",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
+       .cra_alignmask          = 0,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(aesni_alg.cra_list),
+       .cra_u  = {
+               .cipher = {
+                       .cia_min_keysize        = AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        = AES_MAX_KEY_SIZE,
+                       .cia_setkey             = aes_set_key,
+                       .cia_encrypt            = aes_encrypt,
+                       .cia_decrypt            = aes_decrypt
+               }
+       }
+};
+
+static int ecb_encrypt(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       kernel_fpu_begin();
+       while ((nbytes = walk.nbytes)) {
+               aesni_ecb_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
+                             nbytes & AES_BLOCK_MASK);
+               nbytes &= AES_BLOCK_SIZE - 1;
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+       kernel_fpu_end();
+
+       return err;
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       kernel_fpu_begin();
+       while ((nbytes = walk.nbytes)) {
+               aesni_ecb_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
+                             nbytes & AES_BLOCK_MASK);
+               nbytes &= AES_BLOCK_SIZE - 1;
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+       kernel_fpu_end();
+
+       return err;
+}
+
+static struct crypto_alg blk_ecb_alg = {
+       .cra_name               = "__ecb-aes-aesni",
+       .cra_driver_name        = "__driver-ecb-aes-aesni",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .setkey         = aes_set_key,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+};
+
+static int cbc_encrypt(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       kernel_fpu_begin();
+       while ((nbytes = walk.nbytes)) {
+               aesni_cbc_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
+                             nbytes & AES_BLOCK_MASK, walk.iv);
+               nbytes &= AES_BLOCK_SIZE - 1;
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+       kernel_fpu_end();
+
+       return err;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       kernel_fpu_begin();
+       while ((nbytes = walk.nbytes)) {
+               aesni_cbc_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
+                             nbytes & AES_BLOCK_MASK, walk.iv);
+               nbytes &= AES_BLOCK_SIZE - 1;
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+       kernel_fpu_end();
+
+       return err;
+}
+
+static struct crypto_alg blk_cbc_alg = {
+       .cra_name               = "__cbc-aes-aesni",
+       .cra_driver_name        = "__driver-cbc-aes-aesni",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .setkey         = aes_set_key,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+};
+
+static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+                       unsigned int key_len)
+{
+       struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       return crypto_ablkcipher_setkey(&ctx->cryptd_tfm->base, key, key_len);
+}
+
+static int ablk_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       if (kernel_fpu_using()) {
+               struct ablkcipher_request *cryptd_req =
+                       ablkcipher_request_ctx(req);
+               memcpy(cryptd_req, req, sizeof(*req));
+               ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+               return crypto_ablkcipher_encrypt(cryptd_req);
+       } else {
+               struct blkcipher_desc desc;
+               desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+               desc.info = req->info;
+               desc.flags = 0;
+               return crypto_blkcipher_crt(desc.tfm)->encrypt(
+                       &desc, req->dst, req->src, req->nbytes);
+       }
+}
+
+static int ablk_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       if (kernel_fpu_using()) {
+               struct ablkcipher_request *cryptd_req =
+                       ablkcipher_request_ctx(req);
+               memcpy(cryptd_req, req, sizeof(*req));
+               ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+               return crypto_ablkcipher_decrypt(cryptd_req);
+       } else {
+               struct blkcipher_desc desc;
+               desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+               desc.info = req->info;
+               desc.flags = 0;
+               return crypto_blkcipher_crt(desc.tfm)->decrypt(
+                       &desc, req->dst, req->src, req->nbytes);
+       }
+}
+
+static void ablk_exit(struct crypto_tfm *tfm)
+{
+       struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       cryptd_free_ablkcipher(ctx->cryptd_tfm);
+}
+
+static void ablk_init_common(struct crypto_tfm *tfm,
+                            struct cryptd_ablkcipher *cryptd_tfm)
+{
+       struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->cryptd_tfm = cryptd_tfm;
+       tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+               crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+}
+
+static int ablk_ecb_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-aes-aesni", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_ecb_alg = {
+       .cra_name               = "ecb(aes)",
+       .cra_driver_name        = "ecb-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
+       .cra_init               = ablk_ecb_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int ablk_cbc_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-aes-aesni", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_cbc_alg = {
+       .cra_name               = "cbc(aes)",
+       .cra_driver_name        = "cbc-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
+       .cra_init               = ablk_cbc_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int __init aesni_init(void)
+{
+       int err;
+
+       if (!cpu_has_aes) {
+               printk(KERN_ERR "Intel AES-NI instructions are not detected.\n");
+               return -ENODEV;
+       }
+       if ((err = crypto_register_alg(&aesni_alg)))
+               goto aes_err;
+       if ((err = crypto_register_alg(&blk_ecb_alg)))
+               goto blk_ecb_err;
+       if ((err = crypto_register_alg(&blk_cbc_alg)))
+               goto blk_cbc_err;
+       if ((err = crypto_register_alg(&ablk_ecb_alg)))
+               goto ablk_ecb_err;
+       if ((err = crypto_register_alg(&ablk_cbc_alg)))
+               goto ablk_cbc_err;
+
+       return err;
+
+ablk_cbc_err:
+       crypto_unregister_alg(&ablk_ecb_alg);
+ablk_ecb_err:
+       crypto_unregister_alg(&blk_cbc_alg);
+blk_cbc_err:
+       crypto_unregister_alg(&blk_ecb_alg);
+blk_ecb_err:
+       crypto_unregister_alg(&aesni_alg);
+aes_err:
+       return err;
+}
+
+static void __exit aesni_exit(void)
+{
+       crypto_unregister_alg(&ablk_cbc_alg);
+       crypto_unregister_alg(&ablk_ecb_alg);
+       crypto_unregister_alg(&blk_cbc_alg);
+       crypto_unregister_alg(&blk_ecb_alg);
+       crypto_unregister_alg(&aesni_alg);
+}
+
+module_init(aesni_init);
+module_exit(aesni_exit);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, Intel AES-NI instructions optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
diff --git a/arch/x86/include/asm/aes.h b/arch/x86/include/asm/aes.h
new file mode 100644 (file)
index 0000000..80545a1
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef ASM_X86_AES_H
+#define ASM_X86_AES_H
+
+#include <linux/crypto.h>
+#include <crypto/aes.h>
+
+void crypto_aes_encrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst,
+                           const u8 *src);
+void crypto_aes_decrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst,
+                           const u8 *src);
+#endif
index 7301e60dc4a83c56e28b6e8867ab6a15419347bf..0beba0d1468db24bceaa1e81cdf8c652eb5180ee 100644 (file)
@@ -213,6 +213,7 @@ extern const char * const x86_power_flags[32];
 #define cpu_has_xmm            boot_cpu_has(X86_FEATURE_XMM)
 #define cpu_has_xmm2           boot_cpu_has(X86_FEATURE_XMM2)
 #define cpu_has_xmm3           boot_cpu_has(X86_FEATURE_XMM3)
+#define cpu_has_aes            boot_cpu_has(X86_FEATURE_AES)
 #define cpu_has_ht             boot_cpu_has(X86_FEATURE_HT)
 #define cpu_has_mp             boot_cpu_has(X86_FEATURE_MP)
 #define cpu_has_nx             boot_cpu_has(X86_FEATURE_NX)
index 2bb6a835c453c0ced2d9b7e78e998e7fde5d8c3e..4f5c247248567708f0b4b599c8b618b12ddb458d 100644 (file)
@@ -11,8 +11,8 @@ unsigned long native_calibrate_tsc(void);
 
 #ifdef CONFIG_X86_32
 extern int timer_ack;
+#endif
 extern int recalibrate_cpu_khz(void);
-#endif /* CONFIG_X86_32 */
 
 extern int no_timer_check;
 
index 65792c2cc4625f7c44337ddb043bbcd92090aee5..52c839875478571711df3d861ffc1a3d4c5eb413 100644 (file)
@@ -87,30 +87,15 @@ config X86_POWERNOW_K7_ACPI
 config X86_POWERNOW_K8
        tristate "AMD Opteron/Athlon64 PowerNow!"
        select CPU_FREQ_TABLE
+       depends on ACPI && ACPI_PROCESSOR
        help
-         This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
+         This adds the CPUFreq driver for K8/K10 Opteron/Athlon64 processors.
 
          To compile this driver as a module, choose M here: the
          module will be called powernow-k8.
 
          For details, take a look at <file:Documentation/cpu-freq/>.
 
-         If in doubt, say N.
-
-config X86_POWERNOW_K8_ACPI
-       bool
-       prompt "ACPI Support" if X86_32
-       depends on ACPI && X86_POWERNOW_K8 && ACPI_PROCESSOR
-       depends on !(X86_POWERNOW_K8 = y && ACPI_PROCESSOR = m)
-       default y
-       help
-         This provides access to the K8s Processor Performance States via ACPI.
-         This driver is probably required for CPUFreq to work with multi-socket and
-         SMP systems.  It is not required on at least some single-socket yet
-         multi-core systems, even if SMP is enabled.
-
-         It is safe to say Y here.
-
 config X86_GX_SUSPMOD
        tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
        depends on X86_32 && PCI
index 560f7760dae5c3dd18fa4b85845531bca0d30db4..509296df294d9432ed6459f8c6b3cccbbb04e1ef 100644 (file)
@@ -1,6 +1,11 @@
+# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
+# K8 systems. ACPI is preferred to all other hardware-specific drivers.
+# speedstep-* is preferred over p4-clockmod.
+
+obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K6)          += powernow-k6.o
 obj-$(CONFIG_X86_POWERNOW_K7)          += powernow-k7.o
-obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o
 obj-$(CONFIG_X86_LONGHAUL)             += longhaul.o
 obj-$(CONFIG_X86_E_POWERSAVER)         += e_powersaver.o
 obj-$(CONFIG_ELAN_CPUFREQ)             += elanfreq.o
@@ -10,7 +15,6 @@ obj-$(CONFIG_X86_GX_SUSPMOD)          += gx-suspmod.o
 obj-$(CONFIG_X86_SPEEDSTEP_ICH)                += speedstep-ich.o
 obj-$(CONFIG_X86_SPEEDSTEP_LIB)                += speedstep-lib.o
 obj-$(CONFIG_X86_SPEEDSTEP_SMI)                += speedstep-smi.o
-obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o
 obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO)   += speedstep-centrino.o
 obj-$(CONFIG_X86_P4_CLOCKMOD)          += p4-clockmod.o
 obj-$(CONFIG_X86_CPUFREQ_NFORCE2)      += cpufreq-nforce2.o
index 4b1c319d30c368592e990663fb1c8efd5abea963..3babe1f1e912eba061378087b5d4211022e4f772 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $)
+ * acpi-cpufreq.c - ACPI Processor P-States Driver
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 #include <linux/ftrace.h>
 
 #include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
 #include <acpi/processor.h>
 
-#include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "acpi-cpufreq", msg)
 
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -95,7 +97,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
 
        perf = data->acpi_data;
 
-       for (i=0; i<perf->state_count; i++) {
+       for (i = 0; i < perf->state_count; i++) {
                if (value == perf->states[i].status)
                        return data->freq_table[i].frequency;
        }
@@ -110,7 +112,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
        msr &= INTEL_MSR_RANGE;
        perf = data->acpi_data;
 
-       for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+       for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
                if (msr == perf->states[data->freq_table[i].index].status)
                        return data->freq_table[i].frequency;
        }
@@ -138,15 +140,13 @@ struct io_addr {
        u8 bit_width;
 };
 
-typedef union {
-       struct msr_addr msr;
-       struct io_addr io;
-} drv_addr_union;
-
 struct drv_cmd {
        unsigned int type;
        const struct cpumask *mask;
-       drv_addr_union addr;
+       union {
+               struct msr_addr msr;
+               struct io_addr io;
+       } addr;
        u32 val;
 };
 
@@ -369,7 +369,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
        unsigned int cur_freq;
        unsigned int i;
 
-       for (i=0; i<100; i++) {
+       for (i = 0; i < 100; i++) {
                cur_freq = extract_freq(get_cur_val(mask), data);
                if (cur_freq == freq)
                        return 1;
@@ -494,7 +494,7 @@ acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
                unsigned long freq;
                unsigned long freqn = perf->states[0].core_frequency * 1000;
 
-               for (i=0; i<(perf->state_count-1); i++) {
+               for (i = 0; i < (perf->state_count-1); i++) {
                        freq = freqn;
                        freqn = perf->states[i+1].core_frequency * 1000;
                        if ((2 * cpu_khz) > (freqn + freq)) {
@@ -673,7 +673,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        /* detect transition latency */
        policy->cpuinfo.transition_latency = 0;
-       for (i=0; i<perf->state_count; i++) {
+       for (i = 0; i < perf->state_count; i++) {
                if ((perf->states[i].transition_latency * 1000) >
                    policy->cpuinfo.transition_latency)
                        policy->cpuinfo.transition_latency =
@@ -682,8 +682,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        data->max_freq = perf->states[0].core_frequency * 1000;
        /* table init */
-       for (i=0; i<perf->state_count; i++) {
-               if (i>0 && perf->states[i].core_frequency >=
+       for (i = 0; i < perf->state_count; i++) {
+               if (i > 0 && perf->states[i].core_frequency >=
                    data->freq_table[valid_states-1].frequency / 1000)
                        continue;
 
index 965ea52767ac65f5059673a3448764103a0e8543..733093d6043698ecba3eca01249b3d301f6008b2 100644 (file)
@@ -32,7 +32,7 @@
  * nforce2_chipset:
  * FSB is changed using the chipset
  */
-static struct pci_dev *nforce2_chipset_dev;
+static struct pci_dev *nforce2_dev;
 
 /* fid:
  * multiplier * 10
@@ -56,7 +56,9 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
 MODULE_PARM_DESC(min_fsb,
                "Minimum FSB to use, if not defined: current FSB - 50");
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg)
+#define PFX "cpufreq-nforce2: "
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "cpufreq-nforce2", msg)
 
 /**
  * nforce2_calc_fsb - calculate FSB
@@ -118,11 +120,11 @@ static void nforce2_write_pll(int pll)
        int temp;
 
        /* Set the pll addr. to 0x00 */
-       pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, 0);
+       pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
 
        /* Now write the value in all 64 registers */
        for (temp = 0; temp <= 0x3f; temp++)
-               pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, pll);
+               pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
 
        return;
 }
@@ -139,8 +141,8 @@ static unsigned int nforce2_fsb_read(int bootfsb)
        u32 fsb, temp = 0;
 
        /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
-       nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
-                                               0x01EF, PCI_ANY_ID, PCI_ANY_ID, NULL);
+       nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF,
+                               PCI_ANY_ID, PCI_ANY_ID, NULL);
        if (!nforce2_sub5)
                return 0;
 
@@ -148,13 +150,13 @@ static unsigned int nforce2_fsb_read(int bootfsb)
        fsb /= 1000000;
 
        /* Check if PLL register is already set */
-       pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
+       pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
 
        if (bootfsb || !temp)
                return fsb;
 
        /* Use PLL register FSB value */
-       pci_read_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, &temp);
+       pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp);
        fsb = nforce2_calc_fsb(temp);
 
        return fsb;
@@ -174,18 +176,18 @@ static int nforce2_set_fsb(unsigned int fsb)
        int pll = 0;
 
        if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
-               printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb);
+               printk(KERN_ERR PFX "FSB %d is out of range!\n", fsb);
                return -EINVAL;
        }
 
        tfsb = nforce2_fsb_read(0);
        if (!tfsb) {
-               printk(KERN_ERR "cpufreq: Error while reading the FSB\n");
+               printk(KERN_ERR PFX "Error while reading the FSB\n");
                return -EINVAL;
        }
 
        /* First write? Then set actual value */
-       pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
+       pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
        if (!temp) {
                pll = nforce2_calc_pll(tfsb);
 
@@ -197,7 +199,7 @@ static int nforce2_set_fsb(unsigned int fsb)
 
        /* Enable write access */
        temp = 0x01;
-       pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp);
+       pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
 
        diff = tfsb - fsb;
 
@@ -222,7 +224,7 @@ static int nforce2_set_fsb(unsigned int fsb)
        }
 
        temp = 0x40;
-       pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp);
+       pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
 
        return 0;
 }
@@ -244,7 +246,8 @@ static unsigned int nforce2_get(unsigned int cpu)
  * nforce2_target - set a new CPUFreq policy
  * @policy: new policy
  * @target_freq: the target frequency
- * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
+ * @relation: how that frequency relates to achieved frequency
+ *  (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
  *
  * Sets a new CPUFreq policy.
  */
@@ -276,7 +279,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
        /* local_irq_save(flags); */
 
        if (nforce2_set_fsb(target_fsb) < 0)
-               printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n",
+               printk(KERN_ERR PFX "Changing FSB to %d failed\n",
                        target_fsb);
        else
                dprintk("Changed FSB successfully to %d\n",
@@ -327,8 +330,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
        /* FIX: Get FID from CPU */
        if (!fid) {
                if (!cpu_khz) {
-                       printk(KERN_WARNING
-                              "cpufreq: cpu_khz not set, can't calculate multiplier!\n");
+                       printk(KERN_WARNING PFX
+                       "cpu_khz not set, can't calculate multiplier!\n");
                        return -ENODEV;
                }
 
@@ -343,7 +346,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
                }
        }
 
-       printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb,
+       printk(KERN_INFO PFX "FSB currently at %i MHz, FID %d.%d\n", fsb,
               fid / 10, fid % 10);
 
        /* Set maximum FSB to FSB at boot time */
@@ -392,17 +395,18 @@ static struct cpufreq_driver nforce2_driver = {
  */
 static unsigned int nforce2_detect_chipset(void)
 {
-       nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
+       nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
                                        PCI_DEVICE_ID_NVIDIA_NFORCE2,
                                        PCI_ANY_ID, PCI_ANY_ID, NULL);
 
-       if (nforce2_chipset_dev == NULL)
+       if (nforce2_dev == NULL)
                return -ENODEV;
 
-       printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
-              nforce2_chipset_dev->revision);
-       printk(KERN_INFO
-              "cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
+       printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n",
+              nforce2_dev->revision);
+       printk(KERN_INFO PFX
+              "FSB changing is maybe unstable and can lead to "
+              "crashes and data loss.\n");
 
        return 0;
 }
@@ -420,7 +424,7 @@ static int __init nforce2_init(void)
 
        /* detect chipset */
        if (nforce2_detect_chipset()) {
-               printk(KERN_ERR "cpufreq: No nForce2 chipset.\n");
+               printk(KERN_INFO PFX "No nForce2 chipset.\n");
                return -ENODEV;
        }
 
index c2f930d8664091932c1a7b614d860f8f365b7f10..3f83ea12c47a5972c2a32e3f5750e6d79fa9f105 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+#include <linux/delay.h>
 
 #include <asm/msr.h>
 #include <asm/tsc.h>
-#include <asm/timex.h>
-#include <asm/io.h>
-#include <asm/delay.h>
 
 #define EPS_BRAND_C7M  0
 #define EPS_BRAND_C7   1
@@ -184,7 +184,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                break;
        }
 
-       switch(brand) {
+       switch (brand) {
        case EPS_BRAND_C7M:
                printk(KERN_CONT "C7-M\n");
                break;
@@ -218,17 +218,20 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
        /* Print voltage and multiplier */
        rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
        current_voltage = lo & 0xff;
-       printk(KERN_INFO "eps: Current voltage = %dmV\n", current_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Current voltage = %dmV\n",
+                       current_voltage * 16 + 700);
        current_multiplier = (lo >> 8) & 0xff;
        printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier);
 
        /* Print limits */
        max_voltage = hi & 0xff;
-       printk(KERN_INFO "eps: Highest voltage = %dmV\n", max_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Highest voltage = %dmV\n",
+                       max_voltage * 16 + 700);
        max_multiplier = (hi >> 8) & 0xff;
        printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier);
        min_voltage = (hi >> 16) & 0xff;
-       printk(KERN_INFO "eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700);
+       printk(KERN_INFO "eps: Lowest voltage = %dmV\n",
+                       min_voltage * 16 + 700);
        min_multiplier = (hi >> 24) & 0xff;
        printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier);
 
@@ -318,7 +321,7 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static struct freq_attreps_attr[] = {
+static struct freq_attr *eps_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -356,7 +359,7 @@ static void __exit eps_exit(void)
        cpufreq_unregister_driver(&eps_driver);
 }
 
-MODULE_AUTHOR("Rafa³ Bilski <rafalbilski@interia.pl>");
+MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
 MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
 MODULE_LICENSE("GPL");
 
index fe613c93b3667d73e78ca6747f691232a9233702..006b278b0d5d973f794e3c0f17a0e9f925369f52 100644 (file)
@@ -184,7 +184,8 @@ static int elanfreq_target(struct cpufreq_policy *policy,
 {
        unsigned int newstate = 0;
 
-       if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, &elanfreq_table[0],
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        elanfreq_set_cpu_state(newstate);
@@ -301,7 +302,8 @@ static void __exit elanfreq_exit(void)
 module_param(max_freq, int, 0444);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
+MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, "
+               "Sven Geggus <sven@geggus.net>");
 MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
 
 module_init(elanfreq_init);
index 9d9eae82e60fae3baec7333269ddb6c46b7d1d27..ac27ec2264d50afd3601ae7a5a10caf93bb94858 100644 (file)
@@ -79,8 +79,9 @@
 #include <linux/smp.h>
 #include <linux/cpufreq.h>
 #include <linux/pci.h>
+#include <linux/errno.h>
+
 #include <asm/processor-cyrix.h>
-#include <asm/errno.h>
 
 /* PCI config registers, all at F0 */
 #define PCI_PMER1      0x80    /* power management enable register 1 */
@@ -122,8 +123,8 @@ static struct gxfreq_params *gx_params;
 static int stock_freq;
 
 /* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
-static int pci_busclk = 0;
-module_param (pci_busclk, int, 0444);
+static int pci_busclk;
+module_param(pci_busclk, int, 0444);
 
 /* maximum duration for which the cpu may be suspended
  * (32us * MAX_DURATION). If no parameter is given, this defaults
@@ -132,7 +133,7 @@ module_param (pci_busclk, int, 0444);
  * is suspended -- processing power is just 0.39% of what it used to be,
  * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */
 static int max_duration = 255;
-module_param (max_duration, int, 0444);
+module_param(max_duration, int, 0444);
 
 /* For the default policy, we want at least some processing power
  * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
@@ -140,7 +141,8 @@ module_param (max_duration, int, 0444);
 #define POLICY_MIN_DIV 20
 
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "gx-suspmod", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "gx-suspmod", msg)
 
 /**
  * we can detect a core multipiler from dir0_lsb
@@ -166,12 +168,20 @@ static int gx_freq_mult[16] = {
  *     Low Level chipset interface                             *
  ****************************************************************/
 static struct pci_device_id gx_chipset_tbl[] __initdata = {
-       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID },
-       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510,
+               PCI_ANY_ID, PCI_ANY_ID },
        { 0, },
 };
 
+static void gx_write_byte(int reg, int value)
+{
+       pci_write_config_byte(gx_params->cs55x0, reg, value);
+}
+
 /**
  * gx_detect_chipset:
  *
@@ -200,7 +210,8 @@ static __init struct pci_dev *gx_detect_chipset(void)
 /**
  * gx_get_cpuspeed:
  *
- * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi Geode CPU runs.
+ * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi
+ * Geode CPU runs.
  */
 static unsigned int gx_get_cpuspeed(unsigned int cpu)
 {
@@ -217,17 +228,18 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu)
  *
  **/
 
-static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, u8 *off_duration)
+static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
+               u8 *off_duration)
 {
        unsigned int i;
        u8 tmp_on, tmp_off;
        int old_tmp_freq = stock_freq;
        int tmp_freq;
 
-       *off_duration=1;
-       *on_duration=0;
+       *off_duration = 1;
+       *on_duration = 0;
 
-       for (i=max_duration; i>0; i--) {
+       for (i = max_duration; i > 0; i--) {
                tmp_off = ((khz * i) / stock_freq) & 0xff;
                tmp_on = i - tmp_off;
                tmp_freq = (stock_freq * tmp_off) / i;
@@ -259,26 +271,34 @@ static void gx_set_cpuspeed(unsigned int khz)
        freqs.cpu = 0;
        freqs.old = gx_get_cpuspeed(0);
 
-       new_khz = gx_validate_speed(khz, &gx_params->on_duration, &gx_params->off_duration);
+       new_khz = gx_validate_speed(khz, &gx_params->on_duration,
+                       &gx_params->off_duration);
 
        freqs.new = new_khz;
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        local_irq_save(flags);
 
-       if (new_khz != stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
+
+
+       if (new_khz != stock_freq) {
+               /* if new khz == 100% of CPU speed, it is special case */
                switch (gx_params->cs55x0->device) {
                case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
                        pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
                        /* FIXME: need to test other values -- Zwane,Miura */
-                       pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */
-                       pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
-                       pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
-
-                       if (gx_params->cs55x0->revision < 0x10) {   /* CS5530(rev 1.2, 1.3) */
-                               suscfg = gx_params->pci_suscfg | SUSMOD;
-                       } else {                           /* CS5530A,B.. */
-                               suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
+                       /* typical 2 to 4ms */
+                       gx_write_byte(PCI_IRQTC, 4);
+                       /* typical 50 to 100ms */
+                       gx_write_byte(PCI_VIDTC, 100);
+                       gx_write_byte(PCI_PMER1, pmer1);
+
+                       if (gx_params->cs55x0->revision < 0x10) {
+                               /* CS5530(rev 1.2, 1.3) */
+                               suscfg = gx_params->pci_suscfg|SUSMOD;
+                       } else {
+                               /* CS5530A,B.. */
+                               suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE;
                        }
                        break;
                case PCI_DEVICE_ID_CYRIX_5520:
@@ -294,13 +314,13 @@ static void gx_set_cpuspeed(unsigned int khz)
                suscfg = gx_params->pci_suscfg & ~(SUSMOD);
                gx_params->off_duration = 0;
                gx_params->on_duration = 0;
-               dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n");
+               dprintk("suspend modulation disabled: cpu runs 100%% speed.\n");
        }
 
-       pci_write_config_byte(gx_params->cs55x0, PCI_MODOFF, gx_params->off_duration);
-       pci_write_config_byte(gx_params->cs55x0, PCI_MODON, gx_params->on_duration);
+       gx_write_byte(PCI_MODOFF, gx_params->off_duration);
+       gx_write_byte(PCI_MODON, gx_params->on_duration);
 
-       pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, suscfg);
+       gx_write_byte(PCI_SUSCFG, suscfg);
        pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg);
 
        local_irq_restore(flags);
@@ -334,7 +354,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
                return -EINVAL;
 
        policy->cpu = 0;
-       cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq);
+       cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
+                       stock_freq);
 
        /* it needs to be assured that at least one supported frequency is
         * within policy->min and policy->max. If it is not, policy->max
@@ -354,7 +375,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
        policy->max = tmp_freq;
        if (policy->max < policy->min)
                policy->max = policy->min;
-       cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq);
+       cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
+                       stock_freq);
 
        return 0;
 }
@@ -398,18 +420,18 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
                return -ENODEV;
 
        /* determine maximum frequency */
-       if (pci_busclk) {
+       if (pci_busclk)
                maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
-       } else if (cpu_khz) {
+       else if (cpu_khz)
                maxfreq = cpu_khz;
-       } else {
+       else
                maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
-       }
+
        stock_freq = maxfreq;
        curfreq = gx_get_cpuspeed(0);
 
        dprintk("cpu max frequency is %d.\n", maxfreq);
-       dprintk("cpu current frequency is %dkHz.\n",curfreq);
+       dprintk("cpu current frequency is %dkHz.\n", curfreq);
 
        /* setup basic struct for cpufreq API */
        policy->cpu = 0;
@@ -447,7 +469,8 @@ static int __init cpufreq_gx_init(void)
        struct pci_dev *gx_pci;
 
        /* Test if we have the right hardware */
-       if ((gx_pci = gx_detect_chipset()) == NULL)
+       gx_pci = gx_detect_chipset();
+       if (gx_pci == NULL)
                return -ENODEV;
 
        /* check whether module parameters are sane */
@@ -468,9 +491,11 @@ static int __init cpufreq_gx_init(void)
        pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1));
        pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
        pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
-       pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration));
+       pci_read_config_byte(params->cs55x0, PCI_MODOFF,
+                       &(params->off_duration));
 
-       if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
+       ret = cpufreq_register_driver(&gx_suspmod_driver);
+       if (ret) {
                kfree(params);
                return ret;                   /* register error! */
        }
@@ -485,9 +510,9 @@ static void __exit cpufreq_gx_exit(void)
        kfree(gx_params);
 }
 
-MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>");
-MODULE_DESCRIPTION ("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
+MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
+MODULE_LICENSE("GPL");
 
 module_init(cpufreq_gx_init);
 module_exit(cpufreq_gx_exit);
index a4cff5d6e380fa8b027eaf3413f1911fbe821599..f1c51aea064df73fb28c3793da94c080703d4580 100644 (file)
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/kernel.h>
 
 #include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
-#include <asm/acpi.h>
-#include <linux/acpi.h>
 #include <acpi/processor.h>
 
 #include "longhaul.h"
@@ -58,7 +58,7 @@
 #define USE_NORTHBRIDGE                (1 << 2)
 
 static int cpu_model;
-static unsigned int numscales=16;
+static unsigned int numscales = 16;
 static unsigned int fsb;
 
 static const struct mV_pos *vrm_mV_table;
@@ -67,8 +67,8 @@ static const unsigned char *mV_vrm_table;
 static unsigned int highest_speed, lowest_speed; /* kHz */
 static unsigned int minmult, maxmult;
 static int can_scale_voltage;
-static struct acpi_processor *pr = NULL;
-static struct acpi_processor_cx *cx = NULL;
+static struct acpi_processor *pr;
+static struct acpi_processor_cx *cx;
 static u32 acpi_regs_addr;
 static u8 longhaul_flags;
 static unsigned int longhaul_index;
@@ -78,12 +78,13 @@ static int scale_voltage;
 static int disable_acpi_c3;
 static int revid_errata;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "longhaul", msg)
 
 
 /* Clock ratios multiplied by 10 */
-static int clock_ratio[32];
-static int eblcr_table[32];
+static int mults[32];
+static int eblcr[32];
 static int longhaul_version;
 static struct cpufreq_frequency_table *longhaul_table;
 
@@ -93,7 +94,7 @@ static char speedbuffer[8];
 static char *print_speed(int speed)
 {
        if (speed < 1000) {
-               snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed);
+               snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);
                return speedbuffer;
        }
 
@@ -122,27 +123,28 @@ static unsigned int calc_speed(int mult)
 
 static int longhaul_get_cpu_mult(void)
 {
-       unsigned long invalue=0,lo, hi;
+       unsigned long invalue = 0, lo, hi;
 
-       rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
-       invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
-       if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) {
+       rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);
+       invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;
+       if (longhaul_version == TYPE_LONGHAUL_V2 ||
+           longhaul_version == TYPE_POWERSAVER) {
                if (lo & (1<<27))
-                       invalue+=16;
+                       invalue += 16;
        }
-       return eblcr_table[invalue];
+       return eblcr[invalue];
 }
 
 /* For processor with BCR2 MSR */
 
-static void do_longhaul1(unsigned int clock_ratio_index)
+static void do_longhaul1(unsigned int mults_index)
 {
        union msr_bcr2 bcr2;
 
        rdmsrl(MSR_VIA_BCR2, bcr2.val);
        /* Enable software clock multiplier */
        bcr2.bits.ESOFTBF = 1;
-       bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff;
+       bcr2.bits.CLOCKMUL = mults_index & 0xff;
 
        /* Sync to timer tick */
        safe_halt();
@@ -161,7 +163,7 @@ static void do_longhaul1(unsigned int clock_ratio_index)
 
 /* For processor with Longhaul MSR */
 
-static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
+static void do_powersaver(int cx_address, unsigned int mults_index,
                          unsigned int dir)
 {
        union msr_longhaul longhaul;
@@ -173,11 +175,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
                longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
        else
                longhaul.bits.RevisionKey = 0;
-       longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
-       longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+       longhaul.bits.SoftBusRatio = mults_index & 0xf;
+       longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;
        /* Setup new voltage */
        if (can_scale_voltage)
-               longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f;
+               longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;
        /* Sync to timer tick */
        safe_halt();
        /* Raise voltage if necessary */
@@ -240,14 +242,14 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
 
 /**
  * longhaul_set_cpu_frequency()
- * @clock_ratio_index : bitpattern of the new multiplier.
+ * @mults_index : bitpattern of the new multiplier.
  *
  * Sets a new clock ratio.
  */
 
 static void longhaul_setstate(unsigned int table_index)
 {
-       unsigned int clock_ratio_index;
+       unsigned int mults_index;
        int speed, mult;
        struct cpufreq_freqs freqs;
        unsigned long flags;
@@ -256,9 +258,9 @@ static void longhaul_setstate(unsigned int table_index)
        u32 bm_timeout = 1000;
        unsigned int dir = 0;
 
-       clock_ratio_index = longhaul_table[table_index].index;
+       mults_index = longhaul_table[table_index].index;
        /* Safety precautions */
-       mult = clock_ratio[clock_ratio_index & 0x1f];
+       mult = mults[mults_index & 0x1f];
        if (mult == -1)
                return;
        speed = calc_speed(mult);
@@ -274,7 +276,7 @@ static void longhaul_setstate(unsigned int table_index)
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-       dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
+       dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
                        fsb, mult/10, mult%10, print_speed(speed/1000));
 retry_loop:
        preempt_disable();
@@ -282,8 +284,8 @@ retry_loop:
 
        pic2_mask = inb(0xA1);
        pic1_mask = inb(0x21);  /* works on C3. save mask. */
-       outb(0xFF,0xA1);        /* Overkill */
-       outb(0xFE,0x21);        /* TMR0 only */
+       outb(0xFF, 0xA1);       /* Overkill */
+       outb(0xFE, 0x21);       /* TMR0 only */
 
        /* Wait while PCI bus is busy. */
        if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
@@ -312,7 +314,7 @@ retry_loop:
         * Software controlled multipliers only.
         */
        case TYPE_LONGHAUL_V1:
-               do_longhaul1(clock_ratio_index);
+               do_longhaul1(mults_index);
                break;
 
        /*
@@ -327,9 +329,9 @@ retry_loop:
                if (longhaul_flags & USE_ACPI_C3) {
                        /* Don't allow wakeup */
                        acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
-                       do_powersaver(cx->address, clock_ratio_index, dir);
+                       do_powersaver(cx->address, mults_index, dir);
                } else {
-                       do_powersaver(0, clock_ratio_index, dir);
+                       do_powersaver(0, mults_index, dir);
                }
                break;
        }
@@ -341,8 +343,8 @@ retry_loop:
                /* Enable bus master arbitration */
                acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
        }
-       outb(pic2_mask,0xA1);   /* restore mask */
-       outb(pic1_mask,0x21);
+       outb(pic2_mask, 0xA1);  /* restore mask */
+       outb(pic1_mask, 0x21);
 
        local_irq_restore(flags);
        preempt_enable();
@@ -392,7 +394,8 @@ retry_loop:
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
        if (!bm_timeout)
-               printk(KERN_INFO PFX "Warning: Timeout while waiting for idle PCI bus.\n");
+               printk(KERN_INFO PFX "Warning: Timeout while waiting for "
+                               "idle PCI bus.\n");
 }
 
 /*
@@ -458,31 +461,32 @@ static int __init longhaul_get_ranges(void)
                break;
        }
 
-       dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
+       dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n",
                 minmult/10, minmult%10, maxmult/10, maxmult%10);
 
        highest_speed = calc_speed(maxmult);
        lowest_speed = calc_speed(minmult);
-       dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
+       dprintk("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
                 print_speed(lowest_speed/1000),
                 print_speed(highest_speed/1000));
 
        if (lowest_speed == highest_speed) {
-               printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");
+               printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n");
                return -EINVAL;
        }
        if (lowest_speed > highest_speed) {
-               printk (KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",
+               printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",
                        lowest_speed, highest_speed);
                return -EINVAL;
        }
 
-       longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
-       if(!longhaul_table)
+       longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table),
+                       GFP_KERNEL);
+       if (!longhaul_table)
                return -ENOMEM;
 
        for (j = 0; j < numscales; j++) {
-               ratio = clock_ratio[j];
+               ratio = mults[j];
                if (ratio == -1)
                        continue;
                if (ratio > maxmult || ratio < minmult)
@@ -507,13 +511,10 @@ static int __init longhaul_get_ranges(void)
                        }
                }
                if (min_i != j) {
-                       unsigned int temp;
-                       temp = longhaul_table[j].frequency;
-                       longhaul_table[j].frequency = longhaul_table[min_i].frequency;
-                       longhaul_table[min_i].frequency = temp;
-                       temp = longhaul_table[j].index;
-                       longhaul_table[j].index = longhaul_table[min_i].index;
-                       longhaul_table[min_i].index = temp;
+                       swap(longhaul_table[j].frequency,
+                            longhaul_table[min_i].frequency);
+                       swap(longhaul_table[j].index,
+                            longhaul_table[min_i].index);
                }
        }
 
@@ -521,7 +522,7 @@ static int __init longhaul_get_ranges(void)
 
        /* Find index we are running on */
        for (j = 0; j < k; j++) {
-               if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) {
+               if (mults[longhaul_table[j].index & 0x1f] == mult) {
                        longhaul_index = j;
                        break;
                }
@@ -559,20 +560,22 @@ static void __init longhaul_setup_voltagescaling(void)
        maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
 
        if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
-               printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
+               printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
                                        "Voltage scaling disabled.\n",
-                                       minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
+                                       minvid.mV/1000, minvid.mV%1000,
+                                       maxvid.mV/1000, maxvid.mV%1000);
                return;
        }
 
        if (minvid.mV == maxvid.mV) {
-               printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
-                               "both %d.%03d. Voltage scaling disabled\n",
+               printk(KERN_INFO PFX "Claims to support voltage scaling but "
+                               "min & max are both %d.%03d. "
+                               "Voltage scaling disabled\n",
                                maxvid.mV/1000, maxvid.mV%1000);
                return;
        }
 
-       /* How many voltage steps */
+       /* How many voltage steps*/
        numvscales = maxvid.pos - minvid.pos + 1;
        printk(KERN_INFO PFX
                "Max VID=%d.%03d  "
@@ -586,7 +589,7 @@ static void __init longhaul_setup_voltagescaling(void)
        j = longhaul.bits.MinMHzBR;
        if (longhaul.bits.MinMHzBR4)
                j += 16;
-       min_vid_speed = eblcr_table[j];
+       min_vid_speed = eblcr[j];
        if (min_vid_speed == -1)
                return;
        switch (longhaul.bits.MinMHzFSB) {
@@ -617,7 +620,8 @@ static void __init longhaul_setup_voltagescaling(void)
                        pos = minvid.pos;
                longhaul_table[j].index |= mV_vrm_table[pos] << 8;
                vid = vrm_mV_table[mV_vrm_table[pos]];
-               printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV);
+               printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
+                               speed, j, vid.mV);
                j++;
        }
 
@@ -640,7 +644,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
        unsigned int dir = 0;
        u8 vid, current_vid;
 
-       if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
+       if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq,
+                               relation, &table_index))
                return -EINVAL;
 
        /* Don't set same frequency again */
@@ -656,7 +661,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
                 * this in hardware, C3 is old and we need to do this
                 * in software. */
                i = longhaul_index;
-               current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f;
+               current_vid = (longhaul_table[longhaul_index].index >> 8);
+               current_vid &= 0x1f;
                if (table_index > longhaul_index)
                        dir = 1;
                while (i != table_index) {
@@ -691,9 +697,9 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
 {
        struct acpi_device *d;
 
-       if ( acpi_bus_get_device(obj_handle, &d) ) {
+       if (acpi_bus_get_device(obj_handle, &d))
                return 0;
-       }
+
        *return_value = acpi_driver_data(d);
        return 1;
 }
@@ -750,7 +756,7 @@ static int longhaul_setup_southbridge(void)
        /* Find VT8235 southbridge */
        dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
        if (dev == NULL)
-       /* Find VT8237 southbridge */
+               /* Find VT8237 southbridge */
                dev = pci_get_device(PCI_VENDOR_ID_VIA,
                                     PCI_DEVICE_ID_VIA_8237, NULL);
        if (dev != NULL) {
@@ -769,7 +775,8 @@ static int longhaul_setup_southbridge(void)
                if (pci_cmd & 1 << 7) {
                        pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
                        acpi_regs_addr &= 0xff00;
-                       printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", acpi_regs_addr);
+                       printk(KERN_INFO PFX "ACPI I/O at 0x%x\n",
+                                       acpi_regs_addr);
                }
 
                pci_dev_put(dev);
@@ -781,7 +788,7 @@ static int longhaul_setup_southbridge(void)
 static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
-       char *cpuname=NULL;
+       char *cpuname = NULL;
        int ret;
        u32 lo, hi;
 
@@ -791,8 +798,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
                cpu_model = CPU_SAMUEL;
                cpuname = "C3 'Samuel' [C5A]";
                longhaul_version = TYPE_LONGHAUL_V1;
-               memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
-               memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
+               memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
+               memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
                break;
 
        case 7:
@@ -803,10 +810,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
                        cpuname = "C3 'Samuel 2' [C5B]";
                        /* Note, this is not a typo, early Samuel2's had
                         * Samuel1 ratios. */
-                       memcpy(clock_ratio, samuel1_clock_ratio,
-                               sizeof(samuel1_clock_ratio));
-                       memcpy(eblcr_table, samuel2_eblcr,
-                               sizeof(samuel2_eblcr));
+                       memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
+                       memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
                        break;
                case 1 ... 15:
                        longhaul_version = TYPE_LONGHAUL_V1;
@@ -817,10 +822,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
                                cpu_model = CPU_EZRA;
                                cpuname = "C3 'Ezra' [C5C]";
                        }
-                       memcpy(clock_ratio, ezra_clock_ratio,
-                               sizeof(ezra_clock_ratio));
-                       memcpy(eblcr_table, ezra_eblcr,
-                               sizeof(ezra_eblcr));
+                       memcpy(mults, ezra_mults, sizeof(ezra_mults));
+                       memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
                        break;
                }
                break;
@@ -829,18 +832,16 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
                cpu_model = CPU_EZRA_T;
                cpuname = "C3 'Ezra-T' [C5M]";
                longhaul_version = TYPE_POWERSAVER;
-               numscales=32;
-               memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));
-               memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));
+               numscales = 32;
+               memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
+               memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
                break;
 
        case 9:
                longhaul_version = TYPE_POWERSAVER;
                numscales = 32;
-               memcpy(clock_ratio,
-                      nehemiah_clock_ratio,
-                      sizeof(nehemiah_clock_ratio));
-               memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
+               memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
+               memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
                switch (c->x86_mask) {
                case 0 ... 1:
                        cpu_model = CPU_NEHEMIAH;
@@ -869,14 +870,14 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
                        longhaul_version = TYPE_LONGHAUL_V1;
        }
 
-       printk (KERN_INFO PFX "VIA %s CPU detected.  ", cpuname);
+       printk(KERN_INFO PFX "VIA %s CPU detected.  ", cpuname);
        switch (longhaul_version) {
        case TYPE_LONGHAUL_V1:
        case TYPE_LONGHAUL_V2:
-               printk ("Longhaul v%d supported.\n", longhaul_version);
+               printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version);
                break;
        case TYPE_POWERSAVER:
-               printk ("Powersaver supported.\n");
+               printk(KERN_CONT "Powersaver supported.\n");
                break;
        };
 
@@ -940,7 +941,7 @@ static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static struct freq_attrlonghaul_attr[] = {
+static struct freq_attr *longhaul_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -966,13 +967,15 @@ static int __init longhaul_init(void)
 
 #ifdef CONFIG_SMP
        if (num_online_cpus() > 1) {
-               printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
+               printk(KERN_ERR PFX "More than 1 CPU detected, "
+                               "longhaul disabled.\n");
                return -ENODEV;
        }
 #endif
 #ifdef CONFIG_X86_IO_APIC
        if (cpu_has_apic) {
-               printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n");
+               printk(KERN_ERR PFX "APIC detected. Longhaul is currently "
+                               "broken in this configuration.\n");
                return -ENODEV;
        }
 #endif
@@ -993,8 +996,8 @@ static void __exit longhaul_exit(void)
 {
        int i;
 
-       for (i=0; i < numscales; i++) {
-               if (clock_ratio[i] == maxmult) {
+       for (i = 0; i < numscales; i++) {
+               if (mults[i] == maxmult) {
                        longhaul_setstate(i);
                        break;
                }
@@ -1007,11 +1010,11 @@ static void __exit longhaul_exit(void)
 /* Even if BIOS is exporting ACPI C3 state, and it is used
  * with success when CPU is idle, this state doesn't
  * trigger frequency transition in some cases. */
-module_param (disable_acpi_c3, int, 0644);
+module_param(disable_acpi_c3, int, 0644);
 MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
 /* Change CPU voltage with frequency. Very usefull to save
  * power, but most VIA C3 processors aren't supporting it. */
-module_param (scale_voltage, int, 0644);
+module_param(scale_voltage, int, 0644);
 MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
 /* Force revision key to 0 for processors which doesn't
  * support voltage scaling, but are introducing itself as
@@ -1019,9 +1022,9 @@ MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
 module_param(revid_errata, int, 0644);
 MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
 
-MODULE_AUTHOR ("Dave Jones <davej@redhat.com>");
-MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
+MODULE_LICENSE("GPL");
 
 late_initcall(longhaul_init);
 module_exit(longhaul_exit);
index 4fcc320997dfd5b9462d21f9282ca2bdcb0c85f0..e2360a469f793b50ab0a5a2662cce15edf25c2aa 100644 (file)
@@ -49,14 +49,14 @@ union msr_longhaul {
 
 /*
  * Clock ratio tables. Div/Mod by 10 to get ratio.
- * The eblcr ones specify the ratio read from the CPU.
- * The clock_ratio ones specify what to write to the CPU.
+ * The eblcr values specify the ratio read from the CPU.
+ * The mults values specify what to write to the CPU.
  */
 
 /*
  * VIA C3 Samuel 1  & Samuel 2 (stepping 0)
  */
-static const int __initdata samuel1_clock_ratio[16] = {
+static const int __initdata samuel1_mults[16] = {
        -1, /* 0000 -> RESERVED */
        30, /* 0001 ->  3.0x */
        40, /* 0010 ->  4.0x */
@@ -119,7 +119,7 @@ static const int __initdata samuel2_eblcr[16] = {
 /*
  * VIA C3 Ezra
  */
-static const int __initdata ezra_clock_ratio[16] = {
+static const int __initdata ezra_mults[16] = {
        100, /* 0000 -> 10.0x */
        30,  /* 0001 ->  3.0x */
        40,  /* 0010 ->  4.0x */
@@ -160,7 +160,7 @@ static const int __initdata ezra_eblcr[16] = {
 /*
  * VIA C3 (Ezra-T) [C5M].
  */
-static const int __initdata ezrat_clock_ratio[32] = {
+static const int __initdata ezrat_mults[32] = {
        100, /* 0000 -> 10.0x */
        30,  /* 0001 ->  3.0x */
        40,  /* 0010 ->  4.0x */
@@ -235,7 +235,7 @@ static const int __initdata ezrat_eblcr[32] = {
 /*
  * VIA C3 Nehemiah */
 
-static const int __initdata  nehemiah_clock_ratio[32] = {
+static const int __initdata  nehemiah_mults[32] = {
        100, /* 0000 -> 10.0x */
        -1, /* 0001 -> 16.0x */
        40,  /* 0010 ->  4.0x */
index 777a7ff075ded63d0c460a4d3c5c2db64ae764e3..da5f70fcb766d1f4a257466e5710c7da62af6d5e 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/cpufreq.h>
+#include <linux/timex.h>
 
 #include <asm/msr.h>
 #include <asm/processor.h>
-#include <asm/timex.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longrun", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "longrun", msg)
 
 static struct cpufreq_driver   longrun_driver;
 
@@ -51,7 +52,7 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
        msr_lo &= 0x0000007F;
        msr_hi &= 0x0000007F;
 
-       if ( longrun_high_freq <= longrun_low_freq ) {
+       if (longrun_high_freq <= longrun_low_freq) {
                /* Assume degenerate Longrun table */
                policy->min = policy->max = longrun_high_freq;
        } else {
@@ -79,7 +80,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
        if (!policy)
                return -EINVAL;
 
-       if ( longrun_high_freq <= longrun_low_freq ) {
+       if (longrun_high_freq <= longrun_low_freq) {
                /* Assume degenerate Longrun table */
                pctg_lo = pctg_hi = 100;
        } else {
@@ -152,7 +153,7 @@ static unsigned int longrun_get(unsigned int cpu)
        cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
        dprintk("cpuid eax is %u\n", eax);
 
-       return (eax * 1000);
+       return eax * 1000;
 }
 
 /**
@@ -196,7 +197,8 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
                rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
                *high_freq = msr_lo * 1000; /* to kHz */
 
-               dprintk("longrun table interface told %u - %u kHz\n", *low_freq, *high_freq);
+               dprintk("longrun table interface told %u - %u kHz\n",
+                               *low_freq, *high_freq);
 
                if (*low_freq > *high_freq)
                        *low_freq = *high_freq;
@@ -219,7 +221,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
        cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
        /* try decreasing in 10% steps, some processors react only
         * on some barrier values */
-       for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -=10) {
+       for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -= 10) {
                /* set to 0 to try_hi perf_pctg */
                msr_lo &= 0xFFFFFF80;
                msr_hi &= 0xFFFFFF80;
@@ -236,7 +238,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
 
        /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
         * eqals
-        * low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
+        * low_freq * (1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
         *
         * high_freq * perf_pctg is stored tempoarily into "ebx".
         */
@@ -317,9 +319,10 @@ static void __exit longrun_exit(void)
 }
 
 
-MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe and Efficeon processors.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and "
+               "Efficeon processors.");
+MODULE_LICENSE("GPL");
 
 module_init(longrun_init);
 module_exit(longrun_exit);
index 3178c3acd97ebb4aa515d19da8a7f75b1178b08a..41ed94915f974ce0310510d9864b54d8e96f37df 100644 (file)
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/cpumask.h>
+#include <linux/timex.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
-#include <asm/timex.h>
+#include <asm/timer.h>
 
 #include "speedstep-lib.h"
 
 #define PFX    "p4-clockmod: "
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "p4-clockmod", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "p4-clockmod", msg)
 
 /*
  * Duty Cycle (3bits), note DC_DISABLE is not specified in
@@ -58,7 +60,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
 {
        u32 l, h;
 
-       if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
+       if (!cpu_online(cpu) ||
+           (newstate > DC_DISABLE) || (newstate == DC_RESV))
                return -EINVAL;
 
        rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
@@ -66,7 +69,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
        if (l & 0x01)
                dprintk("CPU#%d currently thermal throttled\n", cpu);
 
-       if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT))
+       if (has_N44_O17_errata[cpu] &&
+           (newstate == DC_25PT || newstate == DC_DFLT))
                newstate = DC_38PT;
 
        rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
@@ -112,7 +116,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
        struct cpufreq_freqs freqs;
        int i;
 
-       if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0],
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        freqs.old = cpufreq_p4_get(policy->cpu);
@@ -127,7 +132,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
                cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        }
 
-       /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
+       /* run on each logical CPU,
+        * see section 13.15.3 of IA32 Intel Architecture Software
         * Developer's Manual, Volume 3
         */
        for_each_cpu(i, policy->cpus)
@@ -153,28 +159,30 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
 {
        if (c->x86 == 0x06) {
                if (cpu_has(c, X86_FEATURE_EST))
-                       printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. "
-                              "The acpi-cpufreq module offers voltage scaling"
-                              " in addition of frequency scaling. You should use "
-                              "that instead of p4-clockmod, if possible.\n");
+                       printk(KERN_WARNING PFX "Warning: EST-capable CPU "
+                              "detected. The acpi-cpufreq module offers "
+                              "voltage scaling in addition of frequency "
+                              "scaling. You should use that instead of "
+                              "p4-clockmod, if possible.\n");
                switch (c->x86_model) {
                case 0x0E: /* Core */
                case 0x0F: /* Core Duo */
                case 0x16: /* Celeron Core */
                        p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
-                       return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE);
+                       return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE);
                case 0x0D: /* Pentium M (Dothan) */
                        p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
                        /* fall through */
                case 0x09: /* Pentium M (Banias) */
-                       return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
+                       return speedstep_get_frequency(SPEEDSTEP_CPU_PM);
                }
        }
 
        if (c->x86 != 0xF) {
                if (!cpu_has(c, X86_FEATURE_EST))
-                       printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. "
-                               "Please send an e-mail to <cpufreq@vger.kernel.org>\n");
+                       printk(KERN_WARNING PFX "Unknown CPU. "
+                               "Please send an e-mail to "
+                               "<cpufreq@vger.kernel.org>\n");
                return 0;
        }
 
@@ -182,16 +190,16 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
         * throttling is active or not. */
        p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
 
-       if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
+       if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) {
                printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
                       "The speedstep-ich or acpi cpufreq modules offer "
                       "voltage scaling in addition of frequency scaling. "
                       "You should use either one instead of p4-clockmod, "
                       "if possible.\n");
-               return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M);
+               return speedstep_get_frequency(SPEEDSTEP_CPU_P4M);
        }
 
-       return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4D);
+       return speedstep_get_frequency(SPEEDSTEP_CPU_P4D);
 }
 
 
@@ -217,14 +225,20 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
                dprintk("has errata -- disabling low frequencies\n");
        }
 
+       if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D &&
+           c->x86_model < 2) {
+               /* switch to maximum frequency and measure result */
+               cpufreq_p4_setdc(policy->cpu, DC_DISABLE);
+               recalibrate_cpu_khz();
+       }
        /* get max frequency */
        stock_freq = cpufreq_p4_get_frequency(c);
        if (!stock_freq)
                return -EINVAL;
 
        /* table init */
-       for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               if ((i<2) && (has_N44_O17_errata[policy->cpu]))
+       for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
+               if ((i < 2) && (has_N44_O17_errata[policy->cpu]))
                        p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
                else
                        p4clockmod_table[i].frequency = (stock_freq * i)/8;
@@ -232,7 +246,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
 
        /* cpuinfo and default policy values */
-       policy->cpuinfo.transition_latency = 1000000; /* assumed */
+
+       /* the transition latency is set to be 1 higher than the maximum
+        * transition latency of the ondemand governor */
+       policy->cpuinfo.transition_latency = 10000001;
        policy->cur = stock_freq;
 
        return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]);
@@ -258,12 +275,12 @@ static unsigned int cpufreq_p4_get(unsigned int cpu)
                l = DC_DISABLE;
 
        if (l != DC_DISABLE)
-               return (stock_freq * l / 8);
+               return stock_freq * l / 8;
 
        return stock_freq;
 }
 
-static struct freq_attrp4clockmod_attr[] = {
+static struct freq_attr *p4clockmod_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -298,9 +315,10 @@ static int __init cpufreq_p4_init(void)
 
        ret = cpufreq_register_driver(&p4clockmod_driver);
        if (!ret)
-               printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
+               printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock "
+                               "Modulation available\n");
 
-       return (ret);
+       return ret;
 }
 
 
@@ -310,9 +328,9 @@ static void __exit cpufreq_p4_exit(void)
 }
 
 
-MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>");
-MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
+MODULE_LICENSE("GPL");
 
 late_initcall(cpufreq_p4_init);
 module_exit(cpufreq_p4_exit);
index c1ac5790c63e34ec65cfe062f6fbf34c6d3607ce..f10dea409f40c3755754fbad0ae1b91eb6d1f604 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  This file was based upon code in Powertweak Linux (http://powertweak.sf.net)
- *  (C) 2000-2003  Dave Jones, Arjan van de Ven, Janne Pänkälä, Dominik Brodowski.
+ *  (C) 2000-2003  Dave Jones, Arjan van de Ven, Janne Pänkälä,
+ *                 Dominik Brodowski.
  *
  *  Licensed under the terms of the GNU GPL License version 2.
  *
 #include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-
-#include <asm/msr.h>
 #include <linux/timex.h>
 #include <linux/io.h>
 
+#include <asm/msr.h>
+
 #define POWERNOW_IOPORT 0xfff0          /* it doesn't matter where, as long
                                           as it is unused */
 
+#define PFX "powernow-k6: "
 static unsigned int                     busfreq;   /* FSB, in 10 kHz */
 static unsigned int                     max_multiplier;
 
@@ -47,8 +49,8 @@ static struct cpufreq_frequency_table clock_ratio[] = {
  */
 static int powernow_k6_get_cpu_multiplier(void)
 {
-       u64             invalue = 0;
-       u32             msrval;
+       u64 invalue = 0;
+       u32 msrval;
 
        msrval = POWERNOW_IOPORT + 0x1;
        wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
@@ -68,12 +70,12 @@ static int powernow_k6_get_cpu_multiplier(void)
  */
 static void powernow_k6_set_state(unsigned int best_i)
 {
-       unsigned long           outvalue = 0, invalue = 0;
-       unsigned long           msrval;
-       struct cpufreq_freqs    freqs;
+       unsigned long outvalue = 0, invalue = 0;
+       unsigned long msrval;
+       struct cpufreq_freqs freqs;
 
        if (clock_ratio[best_i].index > max_multiplier) {
-               printk(KERN_ERR "cpufreq: invalid target frequency\n");
+               printk(KERN_ERR PFX "invalid target frequency\n");
                return;
        }
 
@@ -119,7 +121,8 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
  * powernow_k6_setpolicy - sets a new CPUFreq policy
  * @policy: new policy
  * @target_freq: the target frequency
- * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
+ * @relation: how that frequency relates to achieved frequency
+ *  (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
  *
  * sets a new CPUFreq policy
  */
@@ -127,9 +130,10 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
                               unsigned int target_freq,
                               unsigned int relation)
 {
-       unsigned int    newstate = 0;
+       unsigned int newstate = 0;
 
-       if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, &clock_ratio[0],
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        powernow_k6_set_state(newstate);
@@ -140,7 +144,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
 
 static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
 {
-       unsigned int i;
+       unsigned int i, f;
        int result;
 
        if (policy->cpu != 0)
@@ -152,10 +156,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
 
        /* table init */
        for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
-               if (clock_ratio[i].index > max_multiplier)
+               f = clock_ratio[i].index;
+               if (f > max_multiplier)
                        clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
                else
-                       clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
+                       clock_ratio[i].frequency = busfreq * f;
        }
 
        /* cpuinfo and default policy values */
@@ -185,7 +190,9 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
 
 static unsigned int powernow_k6_get(unsigned int cpu)
 {
-       return busfreq * powernow_k6_get_cpu_multiplier();
+       unsigned int ret;
+       ret = (busfreq * powernow_k6_get_cpu_multiplier());
+       return ret;
 }
 
 static struct freq_attr *powernow_k6_attr[] = {
@@ -221,7 +228,7 @@ static int __init powernow_k6_init(void)
                return -ENODEV;
 
        if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
-               printk("cpufreq: PowerNow IOPORT region already used.\n");
+               printk(KERN_INFO PFX "PowerNow IOPORT region already used.\n");
                return -EIO;
        }
 
@@ -246,7 +253,8 @@ static void __exit powernow_k6_exit(void)
 }
 
 
-MODULE_AUTHOR("Arjan van de Ven, Dave Jones <davej@redhat.com>, Dominik Brodowski <linux@brodo.de>");
+MODULE_AUTHOR("Arjan van de Ven, Dave Jones <davej@redhat.com>, "
+               "Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
 MODULE_LICENSE("GPL");
 
index 1b446d79a8fdd2d2a92f8ea04dbaa41da57a4f88..3c28ccd49742f26022a49ab3bb6a81cfc1713c4a 100644 (file)
@@ -6,10 +6,12 @@
  *  Licensed under the terms of the GNU GPL License version 2.
  *  Based upon datasheets & sample CPUs kindly provided by AMD.
  *
- * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
- * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
- * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
- * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
+ * Errata 5:
+ *  CPU may fail to execute a FID/VID change in presence of interrupt.
+ *  - We cli/sti on stepping A0 CPUs around the FID/VID transition.
+ * Errata 15:
+ *  CPU with half frequency multipliers may hang upon wakeup from disconnect.
+ *  - We disable half multipliers if ACPI is used on A0 stepping CPUs.
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/dmi.h>
+#include <linux/timex.h>
+#include <linux/io.h>
 
+#include <asm/timer.h>         /* Needed for recalibrate_cpu_khz() */
 #include <asm/msr.h>
-#include <asm/timer.h>
-#include <asm/timex.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
@@ -58,9 +60,9 @@ struct pst_s {
 union powernow_acpi_control_t {
        struct {
                unsigned long fid:5,
-               vid:5,
-               sgtc:20,
-               res1:2;
+                       vid:5,
+                       sgtc:20,
+                       res1:2;
        } bits;
        unsigned long val;
 };
@@ -94,14 +96,15 @@ static struct cpufreq_frequency_table *powernow_table;
 
 static unsigned int can_scale_bus;
 static unsigned int can_scale_vid;
-static unsigned int minimum_speed=-1;
+static unsigned int minimum_speed = -1;
 static unsigned int maximum_speed;
 static unsigned int number_scales;
 static unsigned int fsb;
 static unsigned int latency;
 static char have_a0;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k7", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "powernow-k7", msg)
 
 static int check_fsb(unsigned int fsbspeed)
 {
@@ -109,7 +112,7 @@ static int check_fsb(unsigned int fsbspeed)
        unsigned int f = fsb / 1000;
 
        delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
-       return (delta < 5);
+       return delta < 5;
 }
 
 static int check_powernow(void)
@@ -117,24 +120,26 @@ static int check_powernow(void)
        struct cpuinfo_x86 *c = &cpu_data(0);
        unsigned int maxei, eax, ebx, ecx, edx;
 
-       if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 !=6)) {
+       if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
 #ifdef MODULE
-               printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n");
+               printk(KERN_INFO PFX "This module only works with "
+                               "AMD K7 CPUs\n");
 #endif
                return 0;
        }
 
        /* Get maximum capabilities */
-       maxei = cpuid_eax (0x80000000);
+       maxei = cpuid_eax(0x80000000);
        if (maxei < 0x80000007) {       /* Any powernow info ? */
 #ifdef MODULE
-               printk (KERN_INFO PFX "No powernow capabilities detected\n");
+               printk(KERN_INFO PFX "No powernow capabilities detected\n");
 #endif
                return 0;
        }
 
        if ((c->x86_model == 6) && (c->x86_mask == 0)) {
-               printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
+               printk(KERN_INFO PFX "K7 660[A0] core detected, "
+                               "enabling errata workarounds\n");
                have_a0 = 1;
        }
 
@@ -144,37 +149,42 @@ static int check_powernow(void)
        if (!(edx & (1 << 1 | 1 << 2)))
                return 0;
 
-       printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
+       printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
 
        if (edx & 1 << 1) {
-               printk ("frequency");
-               can_scale_bus=1;
+               printk("frequency");
+               can_scale_bus = 1;
        }
 
        if ((edx & (1 << 1 | 1 << 2)) == 0x6)
-               printk (" and ");
+               printk(" and ");
 
        if (edx & 1 << 2) {
-               printk ("voltage");
-               can_scale_vid=1;
+               printk("voltage");
+               can_scale_vid = 1;
        }
 
-       printk (".\n");
+       printk(".\n");
        return 1;
 }
 
+static void invalidate_entry(unsigned int entry)
+{
+       powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
+}
 
-static int get_ranges (unsigned char *pst)
+static int get_ranges(unsigned char *pst)
 {
        unsigned int j;
        unsigned int speed;
        u8 fid, vid;
 
-       powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL);
+       powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+                               (number_scales + 1)), GFP_KERNEL);
        if (!powernow_table)
                return -ENOMEM;
 
-       for (j=0 ; j < number_scales; j++) {
+       for (j = 0 ; j < number_scales; j++) {
                fid = *pst++;
 
                powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
@@ -182,10 +192,10 @@ static int get_ranges (unsigned char *pst)
 
                speed = powernow_table[j].frequency;
 
-               if ((fid_codes[fid] % 10)==5) {
+               if ((fid_codes[fid] % 10) == 5) {
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
                        if (have_a0 == 1)
-                               powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
+                               invalidate_entry(j);
 #endif
                }
 
@@ -197,7 +207,7 @@ static int get_ranges (unsigned char *pst)
                vid = *pst++;
                powernow_table[j].index |= (vid << 8); /* upper 8 bits */
 
-               dprintk ("   FID: 0x%x (%d.%dx [%dMHz])  "
+               dprintk("   FID: 0x%x (%d.%dx [%dMHz])  "
                         "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
                         fid_codes[fid] % 10, speed/1000, vid,
                         mobile_vid_table[vid]/1000,
@@ -214,13 +224,13 @@ static void change_FID(int fid)
 {
        union msr_fidvidctl fidvidctl;
 
-       rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+       rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
        if (fidvidctl.bits.FID != fid) {
                fidvidctl.bits.SGTC = latency;
                fidvidctl.bits.FID = fid;
                fidvidctl.bits.VIDC = 0;
                fidvidctl.bits.FIDC = 1;
-               wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+               wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
        }
 }
 
@@ -229,18 +239,18 @@ static void change_VID(int vid)
 {
        union msr_fidvidctl fidvidctl;
 
-       rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+       rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
        if (fidvidctl.bits.VID != vid) {
                fidvidctl.bits.SGTC = latency;
                fidvidctl.bits.VID = vid;
                fidvidctl.bits.FIDC = 0;
                fidvidctl.bits.VIDC = 1;
-               wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+               wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
        }
 }
 
 
-static void change_speed (unsigned int index)
+static void change_speed(unsigned int index)
 {
        u8 fid, vid;
        struct cpufreq_freqs freqs;
@@ -257,7 +267,7 @@ static void change_speed (unsigned int index)
 
        freqs.cpu = 0;
 
-       rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
+       rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
        cfid = fidvidstatus.bits.CFID;
        freqs.old = fsb * fid_codes[cfid] / 10;
 
@@ -321,12 +331,14 @@ static int powernow_acpi_init(void)
                goto err1;
        }
 
-       if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
+       if (acpi_processor_perf->control_register.space_id !=
+                       ACPI_ADR_SPACE_FIXED_HARDWARE) {
                retval = -ENODEV;
                goto err2;
        }
 
-       if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
+       if (acpi_processor_perf->status_register.space_id !=
+                       ACPI_ADR_SPACE_FIXED_HARDWARE) {
                retval = -ENODEV;
                goto err2;
        }
@@ -338,7 +350,8 @@ static int powernow_acpi_init(void)
                goto err2;
        }
 
-       powernow_table = kzalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL);
+       powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+                               (number_scales + 1)), GFP_KERNEL);
        if (!powernow_table) {
                retval = -ENOMEM;
                goto err2;
@@ -352,7 +365,7 @@ static int powernow_acpi_init(void)
                unsigned int speed, speed_mhz;
 
                pc.val = (unsigned long) state->control;
-               dprintk ("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
+               dprintk("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
                         i,
                         (u32) state->core_frequency,
                         (u32) state->power,
@@ -381,12 +394,12 @@ static int powernow_acpi_init(void)
                if (speed % 1000 > 0)
                        speed_mhz++;
 
-               if ((fid_codes[fid] % 10)==5) {
+               if ((fid_codes[fid] % 10) == 5) {
                        if (have_a0 == 1)
-                               powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                               invalidate_entry(i);
                }
 
-               dprintk ("   FID: 0x%x (%d.%dx [%dMHz])  "
+               dprintk("   FID: 0x%x (%d.%dx [%dMHz])  "
                         "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
                         fid_codes[fid] % 10, speed_mhz, vid,
                         mobile_vid_table[vid]/1000,
@@ -422,7 +435,8 @@ err1:
 err05:
        kfree(acpi_processor_perf);
 err0:
-       printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n");
+       printk(KERN_WARNING PFX "ACPI perflib can not be used on "
+                       "this platform\n");
        acpi_processor_perf = NULL;
        return retval;
 }
@@ -435,7 +449,14 @@ static int powernow_acpi_init(void)
 }
 #endif
 
-static int powernow_decode_bios (int maxfid, int startvid)
+static void print_pst_entry(struct pst_s *pst, unsigned int j)
+{
+       dprintk("PST:%d (@%p)\n", j, pst);
+       dprintk(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
+               pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
+}
+
+static int powernow_decode_bios(int maxfid, int startvid)
 {
        struct psb_s *psb;
        struct pst_s *pst;
@@ -446,61 +467,67 @@ static int powernow_decode_bios (int maxfid, int startvid)
 
        etuple = cpuid_eax(0x80000001);
 
-       for (i=0xC0000; i < 0xffff0 ; i+=16) {
+       for (i = 0xC0000; i < 0xffff0 ; i += 16) {
 
                p = phys_to_virt(i);
 
-               if (memcmp(p, "AMDK7PNOW!",  10) == 0){
-                       dprintk ("Found PSB header at %p\n", p);
+               if (memcmp(p, "AMDK7PNOW!",  10) == 0) {
+                       dprintk("Found PSB header at %p\n", p);
                        psb = (struct psb_s *) p;
-                       dprintk ("Table version: 0x%x\n", psb->tableversion);
+                       dprintk("Table version: 0x%x\n", psb->tableversion);
                        if (psb->tableversion != 0x12) {
-                               printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n");
+                               printk(KERN_INFO PFX "Sorry, only v1.2 tables"
+                                               " supported right now\n");
                                return -ENODEV;
                        }
 
-                       dprintk ("Flags: 0x%x\n", psb->flags);
-                       if ((psb->flags & 1)==0) {
-                               dprintk ("Mobile voltage regulator\n");
-                       } else {
-                               dprintk ("Desktop voltage regulator\n");
-                       }
+                       dprintk("Flags: 0x%x\n", psb->flags);
+                       if ((psb->flags & 1) == 0)
+                               dprintk("Mobile voltage regulator\n");
+                       else
+                               dprintk("Desktop voltage regulator\n");
 
                        latency = psb->settlingtime;
                        if (latency < 100) {
-                               printk(KERN_INFO PFX "BIOS set settling time to %d microseconds. "
-                                               "Should be at least 100. Correcting.\n", latency);
+                               printk(KERN_INFO PFX "BIOS set settling time "
+                                               "to %d microseconds. "
+                                               "Should be at least 100. "
+                                               "Correcting.\n", latency);
                                latency = 100;
                        }
-                       dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);
-                       dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);
+                       dprintk("Settling Time: %d microseconds.\n",
+                                       psb->settlingtime);
+                       dprintk("Has %d PST tables. (Only dumping ones "
+                                       "relevant to this CPU).\n",
+                                       psb->numpst);
 
-                       p += sizeof (struct psb_s);
+                       p += sizeof(struct psb_s);
 
                        pst = (struct pst_s *) p;
 
-                       for (j=0; j<psb->numpst; j++) {
+                       for (j = 0; j < psb->numpst; j++) {
                                pst = (struct pst_s *) p;
                                number_scales = pst->numpstates;
 
-                               if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&
-                                   (maxfid==pst->maxfid) && (startvid==pst->startvid))
-                               {
-                                       dprintk ("PST:%d (@%p)\n", j, pst);
-                                       dprintk (" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
-                                                pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
-
-                                       ret = get_ranges ((char *) pst + sizeof (struct pst_s));
+                               if ((etuple == pst->cpuid) &&
+                                   check_fsb(pst->fsbspeed) &&
+                                   (maxfid == pst->maxfid) &&
+                                   (startvid == pst->startvid)) {
+                                       print_pst_entry(pst, j);
+                                       p = (char *)pst + sizeof(struct pst_s);
+                                       ret = get_ranges(p);
                                        return ret;
                                } else {
                                        unsigned int k;
-                                       p = (char *) pst + sizeof (struct pst_s);
-                                       for (k=0; k<number_scales; k++)
-                                               p+=2;
+                                       p = (char *)pst + sizeof(struct pst_s);
+                                       for (k = 0; k < number_scales; k++)
+                                               p += 2;
                                }
                        }
-                       printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);
-                       printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");
+                       printk(KERN_INFO PFX "No PST tables match this cpuid "
+                                       "(0x%x)\n", etuple);
+                       printk(KERN_INFO PFX "This is indicative of a broken "
+                                       "BIOS.\n");
 
                        return -EINVAL;
                }
@@ -511,13 +538,14 @@ static int powernow_decode_bios (int maxfid, int startvid)
 }
 
 
-static int powernow_target (struct cpufreq_policy *policy,
+static int powernow_target(struct cpufreq_policy *policy,
                            unsigned int target_freq,
                            unsigned int relation)
 {
        unsigned int newstate;
 
-       if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, powernow_table, target_freq,
+                               relation, &newstate))
                return -EINVAL;
 
        change_speed(newstate);
@@ -526,7 +554,7 @@ static int powernow_target (struct cpufreq_policy *policy,
 }
 
 
-static int powernow_verify (struct cpufreq_policy *policy)
+static int powernow_verify(struct cpufreq_policy *policy)
 {
        return cpufreq_frequency_table_verify(policy, powernow_table);
 }
@@ -566,18 +594,23 @@ static unsigned int powernow_get(unsigned int cpu)
 
        if (cpu)
                return 0;
-       rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
+       rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
        cfid = fidvidstatus.bits.CFID;
 
-       return (fsb * fid_codes[cfid] / 10);
+       return fsb * fid_codes[cfid] / 10;
 }
 
 
 static int __init acer_cpufreq_pst(const struct dmi_system_id *d)
 {
-       printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
-       printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
-       printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
+       printk(KERN_WARNING PFX
+               "%s laptop with broken PST tables in BIOS detected.\n",
+               d->ident);
+       printk(KERN_WARNING PFX
+               "You need to downgrade to 3A21 (09/09/2002), or try a newer "
+               "BIOS than 3A71 (01/20/2003)\n");
+       printk(KERN_WARNING PFX
+               "cpufreq scaling has been disabled as a result of this.\n");
        return 0;
 }
 
@@ -598,7 +631,7 @@ static struct dmi_system_id __initdata powernow_dmi_table[] = {
        { }
 };
 
-static int __init powernow_cpu_init (struct cpufreq_policy *policy)
+static int __init powernow_cpu_init(struct cpufreq_policy *policy)
 {
        union msr_fidvidstatus fidvidstatus;
        int result;
@@ -606,7 +639,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -ENODEV;
 
-       rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
+       rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 
        recalibrate_cpu_khz();
 
@@ -618,19 +651,21 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        dprintk("FSB: %3dMHz\n", fsb/1000);
 
        if (dmi_check_system(powernow_dmi_table) || acpi_force) {
-               printk (KERN_INFO PFX "PSB/PST known to be broken.  Trying ACPI instead\n");
+               printk(KERN_INFO PFX "PSB/PST known to be broken.  "
+                               "Trying ACPI instead\n");
                result = powernow_acpi_init();
        } else {
-               result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);
+               result = powernow_decode_bios(fidvidstatus.bits.MFID,
+                               fidvidstatus.bits.SVID);
                if (result) {
-                       printk (KERN_INFO PFX "Trying ACPI perflib\n");
+                       printk(KERN_INFO PFX "Trying ACPI perflib\n");
                        maximum_speed = 0;
                        minimum_speed = -1;
                        latency = 0;
                        result = powernow_acpi_init();
                        if (result) {
-                               printk (KERN_INFO PFX "ACPI and legacy methods failed\n");
-                               printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n");
+                               printk(KERN_INFO PFX
+                                       "ACPI and legacy methods failed\n");
                        }
                } else {
                        /* SGTC use the bus clock as timer */
@@ -642,10 +677,11 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        if (result)
                return result;
 
-       printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
+       printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
                                minimum_speed/1000, maximum_speed/1000);
 
-       policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
+       policy->cpuinfo.transition_latency =
+               cpufreq_scale(2000000UL, fsb, latency);
 
        policy->cur = powernow_get(0);
 
@@ -654,7 +690,8 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
 }
 
-static int powernow_cpu_exit (struct cpufreq_policy *policy) {
+static int powernow_cpu_exit(struct cpufreq_policy *policy)
+{
        cpufreq_frequency_table_put_attr(policy->cpu);
 
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
@@ -669,7 +706,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) {
        return 0;
 }
 
-static struct freq_attrpowernow_table_attr[] = {
+static struct freq_attr *powernow_table_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -685,15 +722,15 @@ static struct cpufreq_driver powernow_driver = {
        .attr   = powernow_table_attr,
 };
 
-static int __init powernow_init (void)
+static int __init powernow_init(void)
 {
-       if (check_powernow()==0)
+       if (check_powernow() == 0)
                return -ENODEV;
        return cpufreq_register_driver(&powernow_driver);
 }
 
 
-static void __exit powernow_exit (void)
+static void __exit powernow_exit(void)
 {
        cpufreq_unregister_driver(&powernow_driver);
 }
@@ -701,9 +738,9 @@ static void __exit powernow_exit (void)
 module_param(acpi_force,  int, 0444);
 MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
 
-MODULE_AUTHOR ("Dave Jones <davej@redhat.com>");
-MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
+MODULE_LICENSE("GPL");
 
 late_initcall(powernow_init);
 module_exit(powernow_exit);
index 6428aa17b40e794683b5359ed0589dc3dbfbf592..a15ac94e0b9b8c2ad1ee540fc7bad1b5415aff36 100644 (file)
 #include <linux/string.h>
 #include <linux/cpumask.h>
 #include <linux/sched.h>       /* for current / set_cpus_allowed() */
+#include <linux/io.h>
+#include <linux/delay.h>
 
 #include <asm/msr.h>
-#include <asm/io.h>
-#include <asm/delay.h>
 
-#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 #include <linux/acpi.h>
 #include <linux/mutex.h>
 #include <acpi/processor.h>
-#endif
 
 #define PFX "powernow-k8: "
 #define VERSION "version 2.20.00"
@@ -71,7 +69,8 @@ static u32 find_khz_freq_from_fid(u32 fid)
        return 1000 * find_freq_from_fid(fid);
 }
 
-static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, u32 pstate)
+static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
+               u32 pstate)
 {
        return data[pstate].frequency;
 }
@@ -186,7 +185,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
                return 1;
        }
 
-       lo = fid | (data->currvid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
+       lo = fid;
+       lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
+       lo |= MSR_C_LO_INIT_FID_VID;
 
        dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
                fid, lo, data->plllock * PLL_LOCK_CONVERSION);
@@ -194,7 +195,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
        do {
                wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
                if (i++ > 100) {
-                       printk(KERN_ERR PFX "Hardware error - pending bit very stuck - no further pstate changes possible\n");
+                       printk(KERN_ERR PFX
+                               "Hardware error - pending bit very stuck - "
+                               "no further pstate changes possible\n");
                        return 1;
                }
        } while (query_current_values_with_pending_wait(data));
@@ -202,14 +205,16 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
        count_off_irt(data);
 
        if (savevid != data->currvid) {
-               printk(KERN_ERR PFX "vid change on fid trans, old 0x%x, new 0x%x\n",
-                      savevid, data->currvid);
+               printk(KERN_ERR PFX
+                       "vid change on fid trans, old 0x%x, new 0x%x\n",
+                       savevid, data->currvid);
                return 1;
        }
 
        if (fid != data->currfid) {
-               printk(KERN_ERR PFX "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
-                       data->currfid);
+               printk(KERN_ERR PFX
+                       "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
+                       data->currfid);
                return 1;
        }
 
@@ -228,7 +233,9 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
                return 1;
        }
 
-       lo = data->currfid | (vid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
+       lo = data->currfid;
+       lo |= (vid << MSR_C_LO_VID_SHIFT);
+       lo |= MSR_C_LO_INIT_FID_VID;
 
        dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
                vid, lo, STOP_GRANT_5NS);
@@ -236,20 +243,24 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
        do {
                wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
                if (i++ > 100) {
-                       printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n");
+                       printk(KERN_ERR PFX "internal error - pending bit "
+                                       "very stuck - no further pstate "
+                                       "changes possible\n");
                        return 1;
                }
        } while (query_current_values_with_pending_wait(data));
 
        if (savefid != data->currfid) {
-               printk(KERN_ERR PFX "fid changed on vid trans, old 0x%x new 0x%x\n",
+               printk(KERN_ERR PFX "fid changed on vid trans, old "
+                       "0x%x new 0x%x\n",
                       savefid, data->currfid);
                return 1;
        }
 
        if (vid != data->currvid) {
-               printk(KERN_ERR PFX "vid trans failed, vid 0x%x, curr 0x%x\n", vid,
-                               data->currvid);
+               printk(KERN_ERR PFX "vid trans failed, vid 0x%x, "
+                               "curr 0x%x\n",
+                               vid, data->currvid);
                return 1;
        }
 
@@ -261,7 +272,8 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
  * Decreasing vid codes represent increasing voltages:
  * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
  */
-static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid, u32 step)
+static int decrease_vid_code_by_step(struct powernow_k8_data *data,
+               u32 reqvid, u32 step)
 {
        if ((data->currvid - reqvid) > step)
                reqvid = data->currvid - step;
@@ -283,7 +295,8 @@ static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
 }
 
 /* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
-static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 reqvid)
+static int transition_fid_vid(struct powernow_k8_data *data,
+               u32 reqfid, u32 reqvid)
 {
        if (core_voltage_pre_transition(data, reqvid))
                return 1;
@@ -298,7 +311,8 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req
                return 1;
 
        if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
-               printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n",
+               printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, "
+                               "curr 0x%x 0x%x\n",
                                smp_processor_id(),
                                reqfid, reqvid, data->currfid, data->currvid);
                return 1;
@@ -311,13 +325,15 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req
 }
 
 /* Phase 1 - core voltage transition ... setup voltage */
-static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid)
+static int core_voltage_pre_transition(struct powernow_k8_data *data,
+               u32 reqvid)
 {
        u32 rvosteps = data->rvo;
        u32 savefid = data->currfid;
        u32 maxvid, lo;
 
-       dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
+       dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
+               "reqvid 0x%x, rvo 0x%x\n",
                smp_processor_id(),
                data->currfid, data->currvid, reqvid, data->rvo);
 
@@ -340,7 +356,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
                } else {
                        dprintk("ph1: changing vid for rvo, req 0x%x\n",
                                data->currvid - 1);
-                       if (decrease_vid_code_by_step(data, data->currvid - 1, 1))
+                       if (decrease_vid_code_by_step(data, data->currvid-1, 1))
                                return 1;
                        rvosteps--;
                }
@@ -350,7 +366,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
                return 1;
 
        if (savefid != data->currfid) {
-               printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", data->currfid);
+               printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n",
+                               data->currfid);
                return 1;
        }
 
@@ -363,20 +380,24 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
 /* Phase 2 - core frequency transition */
 static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 {
-       u32 vcoreqfid, vcocurrfid, vcofiddiff, fid_interval, savevid = data->currvid;
+       u32 vcoreqfid, vcocurrfid, vcofiddiff;
+       u32 fid_interval, savevid = data->currvid;
 
-       if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
-               printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n",
-                       reqfid, data->currfid);
+       if ((reqfid < HI_FID_TABLE_BOTTOM) &&
+           (data->currfid < HI_FID_TABLE_BOTTOM)) {
+               printk(KERN_ERR PFX "ph2: illegal lo-lo transition "
+                               "0x%x 0x%x\n", reqfid, data->currfid);
                return 1;
        }
 
        if (data->currfid == reqfid) {
-               printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", data->currfid);
+               printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n",
+                               data->currfid);
                return 0;
        }
 
-       dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
+       dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
+               "reqfid 0x%x\n",
                smp_processor_id(),
                data->currfid, data->currvid, reqfid);
 
@@ -390,14 +411,14 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 
                if (reqfid > data->currfid) {
                        if (data->currfid > LO_FID_TABLE_TOP) {
-                               if (write_new_fid(data, data->currfid + fid_interval)) {
+                               if (write_new_fid(data,
+                                               data->currfid + fid_interval))
                                        return 1;
-                               }
                        } else {
                                if (write_new_fid
-                                   (data, 2 + convert_fid_to_vco_fid(data->currfid))) {
+                                   (data,
+                                    2 + convert_fid_to_vco_fid(data->currfid)))
                                        return 1;
-                               }
                        }
                } else {
                        if (write_new_fid(data, data->currfid - fid_interval))
@@ -417,7 +438,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 
        if (data->currfid != reqfid) {
                printk(KERN_ERR PFX
-                       "ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n",
+                       "ph2: mismatch, failed fid transition, "
+                       "curr 0x%x, req 0x%x\n",
                        data->currfid, reqfid);
                return 1;
        }
@@ -435,7 +457,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 }
 
 /* Phase 3 - core voltage transition flow ... jump to the final vid. */
-static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid)
+static int core_voltage_post_transition(struct powernow_k8_data *data,
+               u32 reqvid)
 {
        u32 savefid = data->currfid;
        u32 savereqvid = reqvid;
@@ -457,7 +480,8 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi
 
                if (data->currvid != reqvid) {
                        printk(KERN_ERR PFX
-                              "ph3: failed vid transition\n, req 0x%x, curr 0x%x",
+                              "ph3: failed vid transition\n, "
+                              "req 0x%x, curr 0x%x",
                               reqvid, data->currvid);
                        return 1;
                }
@@ -508,7 +532,8 @@ static int check_supported_cpu(unsigned int cpu)
        if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
                if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
                    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
-                       printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
+                       printk(KERN_INFO PFX
+                               "Processor cpuid %x not supported\n", eax);
                        goto out;
                }
 
@@ -520,8 +545,10 @@ static int check_supported_cpu(unsigned int cpu)
                }
 
                cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
-               if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
-                       printk(KERN_INFO PFX "Power state transitions not supported\n");
+               if ((edx & P_STATE_TRANSITION_CAPABLE)
+                       != P_STATE_TRANSITION_CAPABLE) {
+                       printk(KERN_INFO PFX
+                               "Power state transitions not supported\n");
                        goto out;
                }
        } else { /* must be a HW Pstate capable processor */
@@ -539,7 +566,8 @@ out:
        return rc;
 }
 
-static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
+static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
+               u8 maxvid)
 {
        unsigned int j;
        u8 lastfid = 0xff;
@@ -550,12 +578,14 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
                               j, pst[j].vid);
                        return -EINVAL;
                }
-               if (pst[j].vid < data->rvo) {   /* vid + rvo >= 0 */
+               if (pst[j].vid < data->rvo) {
+                       /* vid + rvo >= 0 */
                        printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate"
                               " %d\n", j);
                        return -ENODEV;
                }
-               if (pst[j].vid < maxvid + data->rvo) {  /* vid + rvo >= maxvid */
+               if (pst[j].vid < maxvid + data->rvo) {
+                       /* vid + rvo >= maxvid */
                        printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate"
                               " %d\n", j);
                        return -ENODEV;
@@ -579,23 +609,31 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
                return -EINVAL;
        }
        if (lastfid > LO_FID_TABLE_TOP)
-               printk(KERN_INFO FW_BUG PFX  "first fid not from lo freq table\n");
+               printk(KERN_INFO FW_BUG PFX
+                       "first fid not from lo freq table\n");
 
        return 0;
 }
 
+static void invalidate_entry(struct powernow_k8_data *data, unsigned int entry)
+{
+       data->powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
+}
+
 static void print_basics(struct powernow_k8_data *data)
 {
        int j;
        for (j = 0; j < data->numps; j++) {
-               if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
+               if (data->powernow_table[j].frequency !=
+                               CPUFREQ_ENTRY_INVALID) {
                        if (cpu_family == CPU_HW_PSTATE) {
-                               printk(KERN_INFO PFX "   %d : pstate %d (%d MHz)\n",
-                                       j,
+                               printk(KERN_INFO PFX
+                                       "   %d : pstate %d (%d MHz)\n", j,
                                        data->powernow_table[j].index,
                                        data->powernow_table[j].frequency/1000);
                        } else {
-                               printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x\n",
+                               printk(KERN_INFO PFX
+                                       "   %d : fid 0x%x (%d MHz), vid 0x%x\n",
                                        j,
                                        data->powernow_table[j].index & 0xff,
                                        data->powernow_table[j].frequency/1000,
@@ -604,20 +642,25 @@ static void print_basics(struct powernow_k8_data *data)
                }
        }
        if (data->batps)
-               printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
+               printk(KERN_INFO PFX "Only %d pstates on battery\n",
+                               data->batps);
 }
 
-static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
+static int fill_powernow_table(struct powernow_k8_data *data,
+               struct pst_s *pst, u8 maxvid)
 {
        struct cpufreq_frequency_table *powernow_table;
        unsigned int j;
 
-       if (data->batps) {    /* use ACPI support to get full speed on mains power */
-               printk(KERN_WARNING PFX "Only %d pstates usable (use ACPI driver for full range\n", data->batps);
+       if (data->batps) {
+               /* use ACPI support to get full speed on mains power */
+               printk(KERN_WARNING PFX
+                       "Only %d pstates usable (use ACPI driver for full "
+                       "range\n", data->batps);
                data->numps = data->batps;
        }
 
-       for ( j=1; j<data->numps; j++ ) {
+       for (j = 1; j < data->numps; j++) {
                if (pst[j-1].fid >= pst[j].fid) {
                        printk(KERN_ERR PFX "PST out of sequence\n");
                        return -EINVAL;
@@ -640,9 +683,11 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
        }
 
        for (j = 0; j < data->numps; j++) {
+               int freq;
                powernow_table[j].index = pst[j].fid; /* lower 8 bits */
                powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
-               powernow_table[j].frequency = find_khz_freq_from_fid(pst[j].fid);
+               freq = find_khz_freq_from_fid(pst[j].fid);
+               powernow_table[j].frequency = freq;
        }
        powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
        powernow_table[data->numps].index = 0;
@@ -658,7 +703,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
                print_basics(data);
 
        for (j = 0; j < data->numps; j++)
-               if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))
+               if ((pst[j].fid == data->currfid) &&
+                   (pst[j].vid == data->currvid))
                        return 0;
 
        dprintk("currfid/vid do not match PST, ignoring\n");
@@ -698,7 +744,8 @@ static int find_psb_table(struct powernow_k8_data *data)
                }
 
                data->vstable = psb->vstable;
-               dprintk("voltage stabilization time: %d(*20us)\n", data->vstable);
+               dprintk("voltage stabilization time: %d(*20us)\n",
+                               data->vstable);
 
                dprintk("flags2: 0x%x\n", psb->flags2);
                data->rvo = psb->flags2 & 3;
@@ -713,11 +760,12 @@ static int find_psb_table(struct powernow_k8_data *data)
 
                dprintk("numpst: 0x%x\n", psb->num_tables);
                cpst = psb->num_tables;
-               if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){
+               if ((psb->cpuid == 0x00000fc0) ||
+                   (psb->cpuid == 0x00000fe0)) {
                        thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-                       if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
+                       if ((thiscpuid == 0x00000fc0) ||
+                           (thiscpuid == 0x00000fe0))
                                cpst = 1;
-                       }
                }
                if (cpst != 1) {
                        printk(KERN_ERR FW_BUG PFX "numpst must be 1\n");
@@ -732,7 +780,8 @@ static int find_psb_table(struct powernow_k8_data *data)
 
                data->numps = psb->numps;
                dprintk("numpstates: 0x%x\n", data->numps);
-               return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid);
+               return fill_powernow_table(data,
+                               (struct pst_s *)(psb+1), maxvid);
        }
        /*
         * If you see this message, complain to BIOS manufacturer. If
@@ -745,28 +794,31 @@ static int find_psb_table(struct powernow_k8_data *data)
         * BIOS and Kernel Developer's Guide, which is available on
         * www.amd.com
         */
-       printk(KERN_ERR PFX "BIOS error - no PSB or ACPI _PSS objects\n");
+       printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
        return -ENODEV;
 }
 
-#ifdef CONFIG_X86_POWERNOW_K8_ACPI
-static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
+static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
+               unsigned int index)
 {
+       acpi_integer control;
+
        if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
                return;
 
-       data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
-       data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK;
-       data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
-       data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK;
-       data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK);
-       data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK;
-}
+       control = data->acpi_data.states[index].control; data->irt = (control
+                       >> IRT_SHIFT) & IRT_MASK; data->rvo = (control >>
+                               RVO_SHIFT) & RVO_MASK; data->exttype = (control
+                                       >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
+       data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; data->vidmvs = 1
+               << ((control >> MVS_SHIFT) & MVS_MASK); data->vstable =
+               (control >> VST_SHIFT) & VST_MASK; }
 
 static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 {
        struct cpufreq_frequency_table *powernow_table;
        int ret_val = -ENODEV;
+       acpi_integer space_id;
 
        if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
                dprintk("register performance failed: bad ACPI data\n");
@@ -779,11 +831,12 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
                goto err_out;
        }
 
-       if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
-               (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+       space_id = data->acpi_data.control_register.space_id;
+       if ((space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+               (space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
                dprintk("Invalid control/status registers (%x - %x)\n",
                        data->acpi_data.control_register.space_id,
-                       data->acpi_data.status_register.space_id);
+                       space_id);
                goto err_out;
        }
 
@@ -802,7 +855,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
        if (ret_val)
                goto err_out_mem;
 
-       powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END;
+       powernow_table[data->acpi_data.state_count].frequency =
+               CPUFREQ_TABLE_END;
        powernow_table[data->acpi_data.state_count].index = 0;
        data->powernow_table = powernow_table;
 
@@ -830,13 +884,15 @@ err_out_mem:
 err_out:
        acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
 
-       /* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
+       /* data->acpi_data.state_count informs us at ->exit()
+        * whether ACPI was used */
        data->acpi_data.state_count = 0;
 
        return ret_val;
 }
 
-static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
+static int fill_powernow_table_pstate(struct powernow_k8_data *data,
+               struct cpufreq_frequency_table *powernow_table)
 {
        int i;
        u32 hi = 0, lo = 0;
@@ -848,84 +904,101 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpuf
 
                index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
                if (index > data->max_hw_pstate) {
-                       printk(KERN_ERR PFX "invalid pstate %d - bad value %d.\n", i, index);
-                       printk(KERN_ERR PFX "Please report to BIOS manufacturer\n");
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       printk(KERN_ERR PFX "invalid pstate %d - "
+                                       "bad value %d.\n", i, index);
+                       printk(KERN_ERR PFX "Please report to BIOS "
+                                       "manufacturer\n");
+                       invalidate_entry(data, i);
                        continue;
                }
                rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
                if (!(hi & HW_PSTATE_VALID_MASK)) {
                        dprintk("invalid pstate %d, ignoring\n", index);
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       invalidate_entry(data, i);
                        continue;
                }
 
                powernow_table[i].index = index;
 
-               powernow_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
+               powernow_table[i].frequency =
+                       data->acpi_data.states[i].core_frequency * 1000;
        }
        return 0;
 }
 
-static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
+static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
+               struct cpufreq_frequency_table *powernow_table)
 {
        int i;
        int cntlofreq = 0;
+
        for (i = 0; i < data->acpi_data.state_count; i++) {
                u32 fid;
                u32 vid;
+               u32 freq, index;
+               acpi_integer status, control;
 
                if (data->exttype) {
-                       fid = data->acpi_data.states[i].status & EXT_FID_MASK;
-                       vid = (data->acpi_data.states[i].status >> VID_SHIFT) & EXT_VID_MASK;
+                       status =  data->acpi_data.states[i].status;
+                       fid = status & EXT_FID_MASK;
+                       vid = (status >> VID_SHIFT) & EXT_VID_MASK;
                } else {
-                       fid = data->acpi_data.states[i].control & FID_MASK;
-                       vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
+                       control =  data->acpi_data.states[i].control;
+                       fid = control & FID_MASK;
+                       vid = (control >> VID_SHIFT) & VID_MASK;
                }
 
                dprintk("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
 
-               powernow_table[i].index = fid; /* lower 8 bits */
-               powernow_table[i].index |= (vid << 8); /* upper 8 bits */
-               powernow_table[i].frequency = find_khz_freq_from_fid(fid);
+               index = fid | (vid<<8);
+               powernow_table[i].index = index;
+
+               freq = find_khz_freq_from_fid(fid);
+               powernow_table[i].frequency = freq;
 
                /* verify frequency is OK */
-               if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
-                       (powernow_table[i].frequency < (MIN_FREQ * 1000))) {
-                       dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
+                       dprintk("invalid freq %u kHz, ignoring\n", freq);
+                       invalidate_entry(data, i);
                        continue;
                }
 
-               /* verify voltage is OK - BIOSs are using "off" to indicate invalid */
+               /* verify voltage is OK -
+                * BIOSs are using "off" to indicate invalid */
                if (vid == VID_OFF) {
                        dprintk("invalid vid %u, ignoring\n", vid);
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       invalidate_entry(data, i);
                        continue;
                }
 
                /* verify only 1 entry from the lo frequency table */
                if (fid < HI_FID_TABLE_BOTTOM) {
                        if (cntlofreq) {
-                               /* if both entries are the same, ignore this one ... */
-                               if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
-                                   (powernow_table[i].index != powernow_table[cntlofreq].index)) {
-                                       printk(KERN_ERR PFX "Too many lo freq table entries\n");
+                               /* if both entries are the same,
+                                * ignore this one ... */
+                               if ((freq != powernow_table[cntlofreq].frequency) ||
+                                   (index != powernow_table[cntlofreq].index)) {
+                                       printk(KERN_ERR PFX
+                                               "Too many lo freq table "
+                                               "entries\n");
                                        return 1;
                                }
 
-                               dprintk("double low frequency table entry, ignoring it.\n");
-                               powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                               dprintk("double low frequency table entry, "
+                                               "ignoring it.\n");
+                               invalidate_entry(data, i);
                                continue;
                        } else
                                cntlofreq = i;
                }
 
-               if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
-                       printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
-                               powernow_table[i].frequency,
-                               (unsigned int) (data->acpi_data.states[i].core_frequency * 1000));
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
+                       printk(KERN_INFO PFX "invalid freq entries "
+                               "%u kHz vs. %u kHz\n", freq,
+                               (unsigned int)
+                               (data->acpi_data.states[i].core_frequency
+                                * 1000));
+                       invalidate_entry(data, i);
                        continue;
                }
        }
@@ -935,7 +1008,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpuf
 static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
 {
        if (data->acpi_data.state_count)
-               acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
+               acpi_processor_unregister_performance(&data->acpi_data,
+                               data->cpu);
        free_cpumask_var(data->acpi_data.shared_cpu_map);
 }
 
@@ -953,15 +1027,9 @@ static int get_transition_latency(struct powernow_k8_data *data)
        return 1000 * max_latency;
 }
 
-#else
-static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; }
-static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; }
-static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; }
-static int get_transition_latency(struct powernow_k8_data *data) { return 0; }
-#endif /* CONFIG_X86_POWERNOW_K8_ACPI */
-
 /* Take a frequency, and issue the fid/vid transition command */
-static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned int index)
+static int transition_frequency_fidvid(struct powernow_k8_data *data,
+               unsigned int index)
 {
        u32 fid = 0;
        u32 vid = 0;
@@ -989,7 +1057,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i
                return 0;
        }
 
-       if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
+       if ((fid < HI_FID_TABLE_BOTTOM) &&
+           (data->currfid < HI_FID_TABLE_BOTTOM)) {
                printk(KERN_ERR PFX
                       "ignoring illegal change in lo freq table-%x to 0x%x\n",
                       data->currfid, fid);
@@ -1017,7 +1086,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i
 }
 
 /* Take a frequency, and issue the hardware pstate transition command */
-static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned int index)
+static int transition_frequency_pstate(struct powernow_k8_data *data,
+               unsigned int index)
 {
        u32 pstate = 0;
        int res, i;
@@ -1029,7 +1099,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i
        pstate = index & HW_PSTATE_MASK;
        if (pstate > data->max_hw_pstate)
                return 0;
-       freqs.old = find_khz_freq_from_pstate(data->powernow_table, data->currpstate);
+       freqs.old = find_khz_freq_from_pstate(data->powernow_table,
+                       data->currpstate);
        freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
 
        for_each_cpu_mask_nr(i, *(data->available_cores)) {
@@ -1048,7 +1119,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i
 }
 
 /* Driver entry point to switch to the target frequency */
-static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation)
+static int powernowk8_target(struct cpufreq_policy *pol,
+               unsigned targfreq, unsigned relation)
 {
        cpumask_t oldmask;
        struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
@@ -1087,14 +1159,18 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
                dprintk("targ: curr fid 0x%x, vid 0x%x\n",
                data->currfid, data->currvid);
 
-               if ((checkvid != data->currvid) || (checkfid != data->currfid)) {
+               if ((checkvid != data->currvid) ||
+                   (checkfid != data->currfid)) {
                        printk(KERN_INFO PFX
-                               "error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
-                               checkfid, data->currfid, checkvid, data->currvid);
+                               "error - out of sync, fix 0x%x 0x%x, "
+                               "vid 0x%x 0x%x\n",
+                               checkfid, data->currfid,
+                               checkvid, data->currvid);
                }
        }
 
-       if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
+       if (cpufreq_frequency_table_target(pol, data->powernow_table,
+                               targfreq, relation, &newstate))
                goto err_out;
 
        mutex_lock(&fidvid_mutex);
@@ -1114,7 +1190,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
        mutex_unlock(&fidvid_mutex);
 
        if (cpu_family == CPU_HW_PSTATE)
-               pol->cur = find_khz_freq_from_pstate(data->powernow_table, newstate);
+               pol->cur = find_khz_freq_from_pstate(data->powernow_table,
+                               newstate);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
        ret = 0;
@@ -1141,6 +1218,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        struct powernow_k8_data *data;
        cpumask_t oldmask;
        int rc;
+       static int print_once;
 
        if (!cpu_online(pol->cpu))
                return -ENODEV;
@@ -1163,33 +1241,31 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
                 * an UP version, and is deprecated by AMD.
                 */
                if (num_online_cpus() != 1) {
-#ifndef CONFIG_ACPI_PROCESSOR
-                       printk(KERN_ERR PFX "ACPI Processor support is required "
-                              "for SMP systems but is absent. Please load the "
-                              "ACPI Processor module before starting this "
-                              "driver.\n");
-#else
-                       printk(KERN_ERR FW_BUG PFX "Your BIOS does not provide"
-                              " ACPI _PSS objects in a way that Linux "
-                              "understands. Please report this to the Linux "
-                              "ACPI maintainers and complain to your BIOS "
-                              "vendor.\n");
-#endif
-                       kfree(data);
-                       return -ENODEV;
+                       /*
+                        * Replace this one with print_once as soon as such a
+                        * thing gets introduced
+                        */
+                       if (!print_once) {
+                               WARN_ONCE(1, KERN_ERR FW_BUG PFX "Your BIOS "
+                                       "does not provide ACPI _PSS objects "
+                                       "in a way that Linux understands. "
+                                       "Please report this to the Linux ACPI"
+                                       " maintainers and complain to your "
+                                       "BIOS vendor.\n");
+                               print_once++;
+                       }
+                       goto err_out;
                }
                if (pol->cpu != 0) {
                        printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
                               "CPU other than CPU0. Complain to your BIOS "
                               "vendor.\n");
-                       kfree(data);
-                       return -ENODEV;
+                       goto err_out;
                }
                rc = find_psb_table(data);
-               if (rc) {
-                       kfree(data);
-                       return -ENODEV;
-               }
+               if (rc)
+                       goto err_out;
+
                /* Take a crude guess here.
                 * That guess was in microseconds, so multiply with 1000 */
                pol->cpuinfo.transition_latency = (
@@ -1204,16 +1280,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
 
        if (smp_processor_id() != pol->cpu) {
                printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
-               goto err_out;
+               goto err_out_unmask;
        }
 
        if (pending_bit_stuck()) {
                printk(KERN_ERR PFX "failing init, change pending bit set\n");
-               goto err_out;
+               goto err_out_unmask;
        }
 
        if (query_current_values_with_pending_wait(data))
-               goto err_out;
+               goto err_out_unmask;
 
        if (cpu_family == CPU_OPTERON)
                fidvid_msr_init();
@@ -1228,7 +1304,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        data->available_cores = pol->cpus;
 
        if (cpu_family == CPU_HW_PSTATE)
-               pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate);
+               pol->cur = find_khz_freq_from_pstate(data->powernow_table,
+                               data->currpstate);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
        dprintk("policy current frequency %d kHz\n", pol->cur);
@@ -1245,7 +1322,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
 
        if (cpu_family == CPU_HW_PSTATE)
-               dprintk("cpu_init done, current pstate 0x%x\n", data->currpstate);
+               dprintk("cpu_init done, current pstate 0x%x\n",
+                               data->currpstate);
        else
                dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
                        data->currfid, data->currvid);
@@ -1254,15 +1332,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
 
        return 0;
 
-err_out:
+err_out_unmask:
        set_cpus_allowed_ptr(current, &oldmask);
        powernow_k8_cpu_exit_acpi(data);
 
+err_out:
        kfree(data);
        return -ENODEV;
 }
 
-static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
+static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol)
 {
        struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
 
@@ -1279,7 +1358,7 @@ static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
        return 0;
 }
 
-static unsigned int powernowk8_get (unsigned int cpu)
+static unsigned int powernowk8_get(unsigned int cpu)
 {
        struct powernow_k8_data *data;
        cpumask_t oldmask = current->cpus_allowed;
@@ -1315,7 +1394,7 @@ out:
        return khz;
 }
 
-static struct freq_attrpowernow_k8_attr[] = {
+static struct freq_attr *powernow_k8_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -1360,7 +1439,8 @@ static void __exit powernowk8_exit(void)
        cpufreq_unregister_driver(&cpufreq_amd64_driver);
 }
 
-MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com>");
+MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and "
+               "Mark Langsdorf <mark.langsdorf@amd.com>");
 MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
 MODULE_LICENSE("GPL");
 
index 8ecc75b6c7c3b39338ff2991bb413cedf94eebb9..6c6698feade15f7ab034d665874a8f4e4fde8384 100644 (file)
@@ -45,11 +45,10 @@ struct powernow_k8_data {
         * frequency is in kHz */
        struct cpufreq_frequency_table  *powernow_table;
 
-#ifdef CONFIG_X86_POWERNOW_K8_ACPI
        /* the acpi table needs to be kept. it's only available if ACPI was
         * used to determine valid frequency/vid/fid states */
        struct acpi_processor_performance acpi_data;
-#endif
+
        /* we need to keep track of associated cores, but let cpufreq
         * handle hotplug events - so just point at cpufreq pol->cpus
         * structure */
@@ -222,10 +221,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
 
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
 
-#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
 static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
-#endif
 
 #ifdef CONFIG_SMP
 static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
index 42da9bd677d6ee91ed3cb41f2b09c62d3bf5b26b..435a996a613a6cb3e1a5da201c45ff48b7ac9f3e 100644 (file)
 
 #include <linux/delay.h>
 #include <linux/cpufreq.h>
+#include <linux/timex.h>
+#include <linux/io.h>
 
 #include <asm/msr.h>
-#include <asm/timex.h>
-#include <asm/io.h>
 
 #define MMCR_BASE      0xfffef000      /* The default base address */
 #define OFFS_CPUCTL    0x2   /* CPU Control Register */
 
 static __u8 __iomem *cpuctl;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "sc520_freq", msg)
+#define PFX "sc520_freq: "
 
 static struct cpufreq_frequency_table sc520_freq_table[] = {
        {0x01,  100000},
@@ -43,7 +45,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
 
        switch (clockspeed_reg & 0x03) {
        default:
-               printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg);
+               printk(KERN_ERR PFX "error: cpuctl register has unexpected "
+                               "value %02x\n", clockspeed_reg);
        case 0x01:
                return 100000;
        case 0x02:
@@ -51,7 +54,7 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
        }
 }
 
-static void sc520_freq_set_cpu_state (unsigned int state)
+static void sc520_freq_set_cpu_state(unsigned int state)
 {
 
        struct cpufreq_freqs    freqs;
@@ -76,18 +79,19 @@ static void sc520_freq_set_cpu_state (unsigned int state)
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 };
 
-static int sc520_freq_verify (struct cpufreq_policy *policy)
+static int sc520_freq_verify(struct cpufreq_policy *policy)
 {
        return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
 }
 
-static int sc520_freq_target (struct cpufreq_policy *policy,
+static int sc520_freq_target(struct cpufreq_policy *policy,
                            unsigned int target_freq,
                            unsigned int relation)
 {
        unsigned int newstate = 0;
 
-       if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, sc520_freq_table,
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        sc520_freq_set_cpu_state(newstate);
@@ -116,7 +120,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
 
        result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
        if (result)
-               return (result);
+               return result;
 
        cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
 
@@ -131,7 +135,7 @@ static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
 }
 
 
-static struct freq_attrsc520_freq_attr[] = {
+static struct freq_attr *sc520_freq_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -155,13 +159,13 @@ static int __init sc520_freq_init(void)
        int err;
 
        /* Test if we have the right hardware */
-       if(c->x86_vendor != X86_VENDOR_AMD ||
-                               c->x86 != 4 || c->x86_model != 9) {
+       if (c->x86_vendor != X86_VENDOR_AMD ||
+           c->x86 != 4 || c->x86_model != 9) {
                dprintk("no Elan SC520 processor found!\n");
                return -ENODEV;
        }
        cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
-       if(!cpuctl) {
+       if (!cpuctl) {
                printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
                return -ENOMEM;
        }
index dedc1e98f1683c4e35e0b194b81aed354ab3e55a..8bbb11adb3157d1e0d436910dd6b2423cec025ef 100644 (file)
@@ -39,7 +39,7 @@ static struct pci_dev *speedstep_chipset_dev;
 
 /* speedstep_processor
  */
-static unsigned int speedstep_processor = 0;
+static unsigned int speedstep_processor;
 
 static u32 pmbase;
 
@@ -54,7 +54,8 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
 };
 
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "speedstep-ich", msg)
 
 
 /**
@@ -62,7 +63,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
  *
  * Returns: -ENODEV if no register could be found
  */
-static int speedstep_find_register (void)
+static int speedstep_find_register(void)
 {
        if (!speedstep_chipset_dev)
                return -ENODEV;
@@ -90,7 +91,7 @@ static int speedstep_find_register (void)
  *
  *   Tries to change the SpeedStep state.
  */
-static void speedstep_set_state (unsigned int state)
+static void speedstep_set_state(unsigned int state)
 {
        u8 pm2_blk;
        u8 value;
@@ -133,11 +134,11 @@ static void speedstep_set_state (unsigned int state)
 
        dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
 
-       if (state == (value & 0x1)) {
-               dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
-       } else {
-               printk (KERN_ERR "cpufreq: change failed - I/O error\n");
-       }
+       if (state == (value & 0x1))
+               dprintk("change to %u MHz succeeded\n",
+                       speedstep_get_frequency(speedstep_processor) / 1000);
+       else
+               printk(KERN_ERR "cpufreq: change failed - I/O error\n");
 
        return;
 }
@@ -149,7 +150,7 @@ static void speedstep_set_state (unsigned int state)
  *   Tries to activate the SpeedStep status and control registers.
  * Returns -EINVAL on an unsupported chipset, and zero on success.
  */
-static int speedstep_activate (void)
+static int speedstep_activate(void)
 {
        u16 value = 0;
 
@@ -175,20 +176,18 @@ static int speedstep_activate (void)
  * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
  * chipset, or zero on failure.
  */
-static unsigned int speedstep_detect_chipset (void)
+static unsigned int speedstep_detect_chipset(void)
 {
        speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                              PCI_DEVICE_ID_INTEL_82801DB_12,
-                             PCI_ANY_ID,
-                             PCI_ANY_ID,
+                             PCI_ANY_ID, PCI_ANY_ID,
                              NULL);
        if (speedstep_chipset_dev)
                return 4; /* 4-M */
 
        speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                              PCI_DEVICE_ID_INTEL_82801CA_12,
-                             PCI_ANY_ID,
-                             PCI_ANY_ID,
+                             PCI_ANY_ID, PCI_ANY_ID,
                              NULL);
        if (speedstep_chipset_dev)
                return 3; /* 3-M */
@@ -196,8 +195,7 @@ static unsigned int speedstep_detect_chipset (void)
 
        speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                              PCI_DEVICE_ID_INTEL_82801BA_10,
-                             PCI_ANY_ID,
-                             PCI_ANY_ID,
+                             PCI_ANY_ID, PCI_ANY_ID,
                              NULL);
        if (speedstep_chipset_dev) {
                /* speedstep.c causes lockups on Dell Inspirons 8000 and
@@ -208,8 +206,7 @@ static unsigned int speedstep_detect_chipset (void)
 
                hostbridge  = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                              PCI_DEVICE_ID_INTEL_82815_MC,
-                             PCI_ANY_ID,
-                             PCI_ANY_ID,
+                             PCI_ANY_ID, PCI_ANY_ID,
                              NULL);
 
                if (!hostbridge)
@@ -236,7 +233,7 @@ static unsigned int _speedstep_get(const struct cpumask *cpus)
 
        cpus_allowed = current->cpus_allowed;
        set_cpus_allowed_ptr(current, cpus);
-       speed = speedstep_get_processor_frequency(speedstep_processor);
+       speed = speedstep_get_frequency(speedstep_processor);
        set_cpus_allowed_ptr(current, &cpus_allowed);
        dprintk("detected %u kHz as current frequency\n", speed);
        return speed;
@@ -251,11 +248,12 @@ static unsigned int speedstep_get(unsigned int cpu)
  * speedstep_target - set a new CPUFreq policy
  * @policy: new policy
  * @target_freq: the target frequency
- * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
+ * @relation: how that frequency relates to achieved frequency
+ *     (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
  *
  * Sets a new CPUFreq policy.
  */
-static int speedstep_target (struct cpufreq_policy *policy,
+static int speedstep_target(struct cpufreq_policy *policy,
                             unsigned int target_freq,
                             unsigned int relation)
 {
@@ -264,7 +262,8 @@ static int speedstep_target (struct cpufreq_policy *policy,
        cpumask_t cpus_allowed;
        int i;
 
-       if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        freqs.old = _speedstep_get(policy->cpus);
@@ -308,7 +307,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
  * Limit must be within speedstep_low_freq and speedstep_high_freq, with
  * at least one border included.
  */
-static int speedstep_verify (struct cpufreq_policy *policy)
+static int speedstep_verify(struct cpufreq_policy *policy)
 {
        return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
 }
@@ -344,7 +343,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                return -EIO;
 
        dprintk("currently at %s speed setting - %i MHz\n",
-               (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
+               (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
+               ? "low" : "high",
                (speed / 1000));
 
        /* cpuinfo and default policy values */
@@ -352,9 +352,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
 
        result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
        if (result)
-               return (result);
+               return result;
 
-        cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
+       cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
 
        return 0;
 }
@@ -366,7 +366,7 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static struct freq_attrspeedstep_attr[] = {
+static struct freq_attr *speedstep_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -396,13 +396,15 @@ static int __init speedstep_init(void)
        /* detect processor */
        speedstep_processor = speedstep_detect_processor();
        if (!speedstep_processor) {
-               dprintk("Intel(R) SpeedStep(TM) capable processor not found\n");
+               dprintk("Intel(R) SpeedStep(TM) capable processor "
+                               "not found\n");
                return -ENODEV;
        }
 
        /* detect chipset */
        if (!speedstep_detect_chipset()) {
-               dprintk("Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n");
+               dprintk("Intel(R) SpeedStep(TM) for this chipset not "
+                               "(yet) available.\n");
                return -ENODEV;
        }
 
@@ -431,9 +433,11 @@ static void __exit speedstep_exit(void)
 }
 
 
-MODULE_AUTHOR ("Dave Jones <davej@redhat.com>, Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>, "
+               "Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("Speedstep driver for Intel mobile processors on chipsets "
+               "with ICH-M southbridges.");
+MODULE_LICENSE("GPL");
 
 module_init(speedstep_init);
 module_exit(speedstep_exit);
index cdac7d62369b645a00b15c41c4d617e78b86c3b1..2e3c6862657b2c0b61d5c445edc5bf6927cc626f 100644 (file)
 #include <linux/slab.h>
 
 #include <asm/msr.h>
+#include <asm/tsc.h>
 #include "speedstep-lib.h"
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-lib", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "speedstep-lib", msg)
+
+#define PFX "speedstep-lib: "
 
 #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
-static int relaxed_check = 0;
+static int relaxed_check;
 #else
 #define relaxed_check 0
 #endif
@@ -30,14 +34,14 @@ static int relaxed_check = 0;
  *                   GET PROCESSOR CORE SPEED IN KHZ                 *
  *********************************************************************/
 
-static unsigned int pentium3_get_frequency (unsigned int processor)
+static unsigned int pentium3_get_frequency(unsigned int processor)
 {
-        /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
+       /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
        struct {
                unsigned int ratio;     /* Frequency Multiplier (x10) */
                u8 bitmap;              /* power on configuration bits
                                        [27, 25:22] (in MSR 0x2a) */
-       } msr_decode_mult [] = {
+       } msr_decode_mult[] = {
                { 30, 0x01 },
                { 35, 0x05 },
                { 40, 0x02 },
@@ -52,7 +56,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
                { 85, 0x26 },
                { 90, 0x20 },
                { 100, 0x2b },
-               { 0, 0xff }     /* error or unknown value */
+               { 0, 0xff }     /* error or unknown value */
        };
 
        /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
@@ -60,7 +64,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
                unsigned int value;     /* Front Side Bus speed in MHz */
                u8 bitmap;              /* power on configuration bits [18: 19]
                                        (in MSR 0x2a) */
-       } msr_decode_fsb [] = {
+       } msr_decode_fsb[] = {
                {  66, 0x0 },
                { 100, 0x2 },
                { 133, 0x1 },
@@ -85,7 +89,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
        }
 
        /* decode the multiplier */
-       if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY) {
+       if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
                dprintk("workaround for early PIIIs\n");
                msr_lo &= 0x03c00000;
        } else
@@ -97,9 +101,10 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
                j++;
        }
 
-       dprintk("speed is %u\n", (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
+       dprintk("speed is %u\n",
+               (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
 
-       return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);
+       return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
 }
 
 
@@ -112,20 +117,23 @@ static unsigned int pentiumM_get_frequency(void)
 
        /* see table B-2 of 24547212.pdf */
        if (msr_lo & 0x00040000) {
-               printk(KERN_DEBUG "speedstep-lib: PM - invalid FSB: 0x%x 0x%x\n", msr_lo, msr_tmp);
+               printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n",
+                               msr_lo, msr_tmp);
                return 0;
        }
 
        msr_tmp = (msr_lo >> 22) & 0x1f;
-       dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * 100 * 1000));
+       dprintk("bits 22-26 are 0x%x, speed is %u\n",
+                       msr_tmp, (msr_tmp * 100 * 1000));
 
-       return (msr_tmp * 100 * 1000);
+       return msr_tmp * 100 * 1000;
 }
 
 static unsigned int pentium_core_get_frequency(void)
 {
        u32 fsb = 0;
        u32 msr_lo, msr_tmp;
+       int ret;
 
        rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
        /* see table B-2 of 25366920.pdf */
@@ -153,12 +161,15 @@ static unsigned int pentium_core_get_frequency(void)
        }
 
        rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
-       dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+       dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
+                       msr_lo, msr_tmp);
 
        msr_tmp = (msr_lo >> 22) & 0x1f;
-       dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb));
+       dprintk("bits 22-26 are 0x%x, speed is %u\n",
+                       msr_tmp, (msr_tmp * fsb));
 
-       return (msr_tmp * fsb);
+       ret = (msr_tmp * fsb);
+       return ret;
 }
 
 
@@ -167,6 +178,16 @@ static unsigned int pentium4_get_frequency(void)
        struct cpuinfo_x86 *c = &boot_cpu_data;
        u32 msr_lo, msr_hi, mult;
        unsigned int fsb = 0;
+       unsigned int ret;
+       u8 fsb_code;
+
+       /* Pentium 4 Model 0 and 1 do not have the Core Clock Frequency
+        * to System Bus Frequency Ratio Field in the Processor Frequency
+        * Configuration Register of the MSR. Therefore the current
+        * frequency cannot be calculated and has to be measured.
+        */
+       if (c->x86_model < 2)
+               return cpu_khz;
 
        rdmsr(0x2c, msr_lo, msr_hi);
 
@@ -177,62 +198,61 @@ static unsigned int pentium4_get_frequency(void)
         * revision #12 in Table B-1: MSRs in the Pentium 4 and
         * Intel Xeon Processors, on page B-4 and B-5.
         */
-       if (c->x86_model < 2)
+       fsb_code = (msr_lo >> 16) & 0x7;
+       switch (fsb_code) {
+       case 0:
                fsb = 100 * 1000;
-       else {
-               u8 fsb_code = (msr_lo >> 16) & 0x7;
-               switch (fsb_code) {
-               case 0:
-                       fsb = 100 * 1000;
-                       break;
-               case 1:
-                       fsb = 13333 * 10;
-                       break;
-               case 2:
-                       fsb = 200 * 1000;
-                       break;
-               }
+               break;
+       case 1:
+               fsb = 13333 * 10;
+               break;
+       case 2:
+               fsb = 200 * 1000;
+               break;
        }
 
        if (!fsb)
-               printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n");
+               printk(KERN_DEBUG PFX "couldn't detect FSB speed. "
+                               "Please send an e-mail to <linux@brodo.de>\n");
 
        /* Multiplier. */
        mult = msr_lo >> 24;
 
-       dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));
+       dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
+                       fsb, mult, (fsb * mult));
 
-       return (fsb * mult);
+       ret = (fsb * mult);
+       return ret;
 }
 
 
-unsigned int speedstep_get_processor_frequency(unsigned int processor)
+unsigned int speedstep_get_frequency(unsigned int processor)
 {
        switch (processor) {
-       case SPEEDSTEP_PROCESSOR_PCORE:
+       case SPEEDSTEP_CPU_PCORE:
                return pentium_core_get_frequency();
-       case SPEEDSTEP_PROCESSOR_PM:
+       case SPEEDSTEP_CPU_PM:
                return pentiumM_get_frequency();
-       case SPEEDSTEP_PROCESSOR_P4D:
-       case SPEEDSTEP_PROCESSOR_P4M:
+       case SPEEDSTEP_CPU_P4D:
+       case SPEEDSTEP_CPU_P4M:
                return pentium4_get_frequency();
-       case SPEEDSTEP_PROCESSOR_PIII_T:
-       case SPEEDSTEP_PROCESSOR_PIII_C:
-       case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
+       case SPEEDSTEP_CPU_PIII_T:
+       case SPEEDSTEP_CPU_PIII_C:
+       case SPEEDSTEP_CPU_PIII_C_EARLY:
                return pentium3_get_frequency(processor);
        default:
                return 0;
        };
        return 0;
 }
-EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency);
+EXPORT_SYMBOL_GPL(speedstep_get_frequency);
 
 
 /*********************************************************************
  *                 DETECT SPEEDSTEP-CAPABLE PROCESSOR                *
  *********************************************************************/
 
-unsigned int speedstep_detect_processor (void)
+unsigned int speedstep_detect_processor(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
        u32 ebx, msr_lo, msr_hi;
@@ -261,7 +281,7 @@ unsigned int speedstep_detect_processor (void)
                         * sample has ebx = 0x0f, production has 0x0e.
                         */
                        if ((ebx == 0x0e) || (ebx == 0x0f))
-                               return SPEEDSTEP_PROCESSOR_P4M;
+                               return SPEEDSTEP_CPU_P4M;
                        break;
                case 7:
                        /*
@@ -272,7 +292,7 @@ unsigned int speedstep_detect_processor (void)
                         * samples are only of B-stepping...
                         */
                        if (ebx == 0x0e)
-                               return SPEEDSTEP_PROCESSOR_P4M;
+                               return SPEEDSTEP_CPU_P4M;
                        break;
                case 9:
                        /*
@@ -288,10 +308,13 @@ unsigned int speedstep_detect_processor (void)
                         * M-P4-Ms may have either ebx=0xe or 0xf [see above]
                         * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
                         * also, M-P4M HTs have ebx=0x8, too
-                        * For now, they are distinguished by the model_id string
+                        * For now, they are distinguished by the model_id
+                        * string
                         */
-                       if ((ebx == 0x0e) || (strstr(c->x86_model_id,"Mobile Intel(R) Pentium(R) 4") != NULL))
-                               return SPEEDSTEP_PROCESSOR_P4M;
+                       if ((ebx == 0x0e) ||
+                               (strstr(c->x86_model_id,
+                                   "Mobile Intel(R) Pentium(R) 4") != NULL))
+                               return SPEEDSTEP_CPU_P4M;
                        break;
                default:
                        break;
@@ -301,7 +324,8 @@ unsigned int speedstep_detect_processor (void)
 
        switch (c->x86_model) {
        case 0x0B: /* Intel PIII [Tualatin] */
-               /* cpuid_ebx(1) is 0x04 for desktop PIII, 0x06 for mobile PIII-M */
+               /* cpuid_ebx(1) is 0x04 for desktop PIII,
+                * 0x06 for mobile PIII-M */
                ebx = cpuid_ebx(0x00000001);
                dprintk("ebx is %x\n", ebx);
 
@@ -313,14 +337,15 @@ unsigned int speedstep_detect_processor (void)
                /* So far all PIII-M processors support SpeedStep. See
                 * Intel's 24540640.pdf of June 2003
                 */
-               return SPEEDSTEP_PROCESSOR_PIII_T;
+               return SPEEDSTEP_CPU_PIII_T;
 
        case 0x08: /* Intel PIII [Coppermine] */
 
                /* all mobile PIII Coppermines have FSB 100 MHz
                 * ==> sort out a few desktop PIIIs. */
                rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
-               dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
+               dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
+                               msr_lo, msr_hi);
                msr_lo &= 0x00c0000;
                if (msr_lo != 0x0080000)
                        return 0;
@@ -332,13 +357,15 @@ unsigned int speedstep_detect_processor (void)
                 * bit 56 or 57 is set
                 */
                rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
-               dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
-               if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
+               dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
+                               msr_lo, msr_hi);
+               if ((msr_hi & (1<<18)) &&
+                   (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
                        if (c->x86_mask == 0x01) {
                                dprintk("early PIII version\n");
-                               return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
+                               return SPEEDSTEP_CPU_PIII_C_EARLY;
                        } else
-                               return SPEEDSTEP_PROCESSOR_PIII_C;
+                               return SPEEDSTEP_CPU_PIII_C;
                }
 
        default:
@@ -369,7 +396,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
        dprintk("trying to determine both speeds\n");
 
        /* get current speed */
-       prev_speed = speedstep_get_processor_frequency(processor);
+       prev_speed = speedstep_get_frequency(processor);
        if (!prev_speed)
                return -EIO;
 
@@ -379,7 +406,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
 
        /* switch to low state */
        set_state(SPEEDSTEP_LOW);
-       *low_speed = speedstep_get_processor_frequency(processor);
+       *low_speed = speedstep_get_frequency(processor);
        if (!*low_speed) {
                ret = -EIO;
                goto out;
@@ -398,7 +425,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
        if (transition_latency)
                do_gettimeofday(&tv2);
 
-       *high_speed = speedstep_get_processor_frequency(processor);
+       *high_speed = speedstep_get_frequency(processor);
        if (!*high_speed) {
                ret = -EIO;
                goto out;
@@ -426,9 +453,12 @@ unsigned int speedstep_get_freqs(unsigned int processor,
                /* check if the latency measurement is too high or too low
                 * and set it to a safe value (500uSec) in that case
                 */
-               if (*transition_latency > 10000000 || *transition_latency < 50000) {
-                       printk (KERN_WARNING "speedstep: frequency transition measured seems out of "
-                                       "range (%u nSec), falling back to a safe one of %u nSec.\n",
+               if (*transition_latency > 10000000 ||
+                   *transition_latency < 50000) {
+                       printk(KERN_WARNING PFX "frequency transition "
+                                       "measured seems out of range (%u "
+                                       "nSec), falling back to a safe one of"
+                                       "%u nSec.\n",
                                        *transition_latency, 500000);
                        *transition_latency = 500000;
                }
@@ -436,15 +466,16 @@ unsigned int speedstep_get_freqs(unsigned int processor,
 
 out:
        local_irq_restore(flags);
-       return (ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(speedstep_get_freqs);
 
 #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
 module_param(relaxed_check, int, 0444);
-MODULE_PARM_DESC(relaxed_check, "Don't do all checks for speedstep capability.");
+MODULE_PARM_DESC(relaxed_check,
+               "Don't do all checks for speedstep capability.");
 #endif
 
-MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
+MODULE_LICENSE("GPL");
index b11bcc608cac5cbe4b823ba8c3675e48932f560c..2b6c04e5a30429a011a78f20e74bf7413548f6ad 100644 (file)
 
 /* processors */
 
-#define SPEEDSTEP_PROCESSOR_PIII_C_EARLY       0x00000001  /* Coppermine core */
-#define SPEEDSTEP_PROCESSOR_PIII_C             0x00000002  /* Coppermine core */
-#define SPEEDSTEP_PROCESSOR_PIII_T             0x00000003  /* Tualatin core */
-#define SPEEDSTEP_PROCESSOR_P4M                        0x00000004  /* P4-M  */
+#define SPEEDSTEP_CPU_PIII_C_EARLY     0x00000001  /* Coppermine core */
+#define SPEEDSTEP_CPU_PIII_C           0x00000002  /* Coppermine core */
+#define SPEEDSTEP_CPU_PIII_T           0x00000003  /* Tualatin core */
+#define SPEEDSTEP_CPU_P4M              0x00000004  /* P4-M  */
 
 /* the following processors are not speedstep-capable and are not auto-detected
  * in speedstep_detect_processor(). However, their speed can be detected using
- * the speedstep_get_processor_frequency() call. */
-#define SPEEDSTEP_PROCESSOR_PM                 0xFFFFFF03  /* Pentium M  */
-#define SPEEDSTEP_PROCESSOR_P4D                        0xFFFFFF04  /* desktop P4  */
-#define SPEEDSTEP_PROCESSOR_PCORE              0xFFFFFF05  /* Core */
+ * the speedstep_get_frequency() call. */
+#define SPEEDSTEP_CPU_PM               0xFFFFFF03  /* Pentium M  */
+#define SPEEDSTEP_CPU_P4D              0xFFFFFF04  /* desktop P4  */
+#define SPEEDSTEP_CPU_PCORE            0xFFFFFF05  /* Core */
 
 /* speedstep states -- only two of them */
 
@@ -34,7 +34,7 @@
 extern unsigned int speedstep_detect_processor (void);
 
 /* detect the current speed (in khz) of the processor */
-extern unsigned int speedstep_get_processor_frequency(unsigned int processor);
+extern unsigned int speedstep_get_frequency(unsigned int processor);
 
 
 /* detect the low and high speeds of the processor. The callback
index 8a85c93bd62a4678f58be9cdcf8040875b564756..befea088e4f58b472259f955a8304e5c834e083f 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <asm/ist.h>
-#include <asm/io.h>
 
 #include "speedstep-lib.h"
 
  * If user gives it, these are used.
  *
  */
-static int smi_port = 0;
-static int smi_cmd = 0;
-static unsigned int smi_sig = 0;
+static int smi_port;
+static int smi_cmd;
+static unsigned int smi_sig;
 
 /* info about the processor */
-static unsigned int speedstep_processor = 0;
+static unsigned int speedstep_processor;
 
 /*
  * There are only two frequency states for each processor. Values
@@ -56,12 +56,13 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
  * of DMA activity going on? */
 #define SMI_TRIES 5
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-smi", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+               "speedstep-smi", msg)
 
 /**
  * speedstep_smi_ownership
  */
-static int speedstep_smi_ownership (void)
+static int speedstep_smi_ownership(void)
 {
        u32 command, result, magic, dummy;
        u32 function = GET_SPEEDSTEP_OWNER;
@@ -70,16 +71,18 @@ static int speedstep_smi_ownership (void)
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
        magic = virt_to_phys(magic_data);
 
-       dprintk("trying to obtain ownership with command %x at port %x\n", command, smi_port);
+       dprintk("trying to obtain ownership with command %x at port %x\n",
+                       command, smi_port);
 
        __asm__ __volatile__(
                "push %%ebp\n"
                "out %%al, (%%dx)\n"
                "pop %%ebp\n"
-               : "=D" (result), "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
-                       "=S" (dummy)
+               : "=D" (result),
+                 "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
+                 "=S" (dummy)
                : "a" (command), "b" (function), "c" (0), "d" (smi_port),
-                       "D" (0), "S" (magic)
+                 "D" (0), "S" (magic)
                : "memory"
        );
 
@@ -97,10 +100,10 @@ static int speedstep_smi_ownership (void)
  * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
  * shows that the latter occurs if !(ist_info.event & 0xFFFF).
  */
-static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
+static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
 {
        u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
-       u32 state=0;
+       u32 state = 0;
        u32 function = GET_SPEEDSTEP_FREQS;
 
        if (!(ist_info.event & 0xFFFF)) {
@@ -110,17 +113,25 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to determine frequencies with command %x at port %x\n", command, smi_port);
+       dprintk("trying to determine frequencies with command %x at port %x\n",
+                       command, smi_port);
 
        __asm__ __volatile__(
                "push %%ebp\n"
                "out %%al, (%%dx)\n"
                "pop %%ebp"
-               : "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi), "=S" (dummy)
-               : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0)
+               : "=a" (result),
+                 "=b" (high_mhz),
+                 "=c" (low_mhz),
+                 "=d" (state), "=D" (edi), "=S" (dummy)
+               : "a" (command),
+                 "b" (function),
+                 "c" (state),
+                 "d" (smi_port), "S" (0), "D" (0)
        );
 
-       dprintk("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz);
+       dprintk("result %x, low_freq %u, high_freq %u\n",
+                       result, low_mhz, high_mhz);
 
        /* abort if results are obviously incorrect... */
        if ((high_mhz + low_mhz) < 600)
@@ -137,26 +148,30 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
  * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
  *
  */
-static int speedstep_get_state (void)
+static int speedstep_get_state(void)
 {
-       u32 function=GET_SPEEDSTEP_STATE;
+       u32 function = GET_SPEEDSTEP_STATE;
        u32 result, state, edi, command, dummy;
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to determine current setting with command %x at port %x\n", command, smi_port);
+       dprintk("trying to determine current setting with command %x "
+               "at port %x\n", command, smi_port);
 
        __asm__ __volatile__(
                "push %%ebp\n"
                "out %%al, (%%dx)\n"
                "pop %%ebp\n"
-               : "=a" (result), "=b" (state), "=D" (edi), "=c" (dummy), "=d" (dummy), "=S" (dummy)
-               : "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0), "D" (0)
+               : "=a" (result),
+                 "=b" (state), "=D" (edi),
+                 "=c" (dummy), "=d" (dummy), "=S" (dummy)
+               : "a" (command), "b" (function), "c" (0),
+                 "d" (smi_port), "S" (0), "D" (0)
        );
 
        dprintk("state is %x, result is %x\n", state, result);
 
-       return (state & 1);
+       return state & 1;
 }
 
 
@@ -165,11 +180,11 @@ static int speedstep_get_state (void)
  * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
  *
  */
-static void speedstep_set_state (unsigned int state)
+static void speedstep_set_state(unsigned int state)
 {
        unsigned int result = 0, command, new_state, dummy;
        unsigned long flags;
-       unsigned int function=SET_SPEEDSTEP_STATE;
+       unsigned int function = SET_SPEEDSTEP_STATE;
        unsigned int retry = 0;
 
        if (state > 0x1)
@@ -180,11 +195,14 @@ static void speedstep_set_state (unsigned int state)
 
        command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 
-       dprintk("trying to set frequency to state %u with command %x at port %x\n", state, command, smi_port);
+       dprintk("trying to set frequency to state %u "
+               "with command %x at port %x\n",
+               state, command, smi_port);
 
        do {
                if (retry) {
-                       dprintk("retry %u, previous result %u, waiting...\n", retry, result);
+                       dprintk("retry %u, previous result %u, waiting...\n",
+                                       retry, result);
                        mdelay(retry * 50);
                }
                retry++;
@@ -192,20 +210,26 @@ static void speedstep_set_state (unsigned int state)
                        "push %%ebp\n"
                        "out %%al, (%%dx)\n"
                        "pop %%ebp"
-                       : "=b" (new_state), "=D" (result), "=c" (dummy), "=a" (dummy),
-                               "=d" (dummy), "=S" (dummy)
-                       : "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0)
+                       : "=b" (new_state), "=D" (result),
+                         "=c" (dummy), "=a" (dummy),
+                         "=d" (dummy), "=S" (dummy)
+                       : "a" (command), "b" (function), "c" (state),
+                         "d" (smi_port), "S" (0), "D" (0)
                        );
        } while ((new_state != state) && (retry <= SMI_TRIES));
 
        /* enable IRQs */
        local_irq_restore(flags);
 
-       if (new_state == state) {
-               dprintk("change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result);
-       } else {
-               printk(KERN_ERR "cpufreq: change to state %u failed with new_state %u and result %u\n", state, new_state, result);
-       }
+       if (new_state == state)
+               dprintk("change to %u MHz succeeded after %u tries "
+                       "with result %u\n",
+                       (speedstep_freqs[new_state].frequency / 1000),
+                       retry, result);
+       else
+               printk(KERN_ERR "cpufreq: change to state %u "
+                       "failed with new_state %u and result %u\n",
+                       state, new_state, result);
 
        return;
 }
@@ -219,13 +243,14 @@ static void speedstep_set_state (unsigned int state)
  *
  * Sets a new CPUFreq policy/freq.
  */
-static int speedstep_target (struct cpufreq_policy *policy,
+static int speedstep_target(struct cpufreq_policy *policy,
                        unsigned int target_freq, unsigned int relation)
 {
        unsigned int newstate = 0;
        struct cpufreq_freqs freqs;
 
-       if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
+       if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
+                               target_freq, relation, &newstate))
                return -EINVAL;
 
        freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
@@ -250,7 +275,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
  * Limit must be within speedstep_low_freq and speedstep_high_freq, with
  * at least one border included.
  */
-static int speedstep_verify (struct cpufreq_policy *policy)
+static int speedstep_verify(struct cpufreq_policy *policy)
 {
        return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
 }
@@ -259,7 +284,8 @@ static int speedstep_verify (struct cpufreq_policy *policy)
 static int speedstep_cpu_init(struct cpufreq_policy *policy)
 {
        int result;
-       unsigned int speed,state;
+       unsigned int speed, state;
+       unsigned int *low, *high;
 
        /* capability check */
        if (policy->cpu != 0)
@@ -272,19 +298,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
        }
 
        /* detect low and high frequency */
-       result = speedstep_smi_get_freqs(&speedstep_freqs[SPEEDSTEP_LOW].frequency,
-                               &speedstep_freqs[SPEEDSTEP_HIGH].frequency);
+       low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
+       high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
+
+       result = speedstep_smi_get_freqs(low, high);
        if (result) {
-               /* fall back to speedstep_lib.c dection mechanism: try both states out */
-               dprintk("could not detect low and high frequencies by SMI call.\n");
+               /* fall back to speedstep_lib.c dection mechanism:
+                * try both states out */
+               dprintk("could not detect low and high frequencies "
+                               "by SMI call.\n");
                result = speedstep_get_freqs(speedstep_processor,
-                               &speedstep_freqs[SPEEDSTEP_LOW].frequency,
-                               &speedstep_freqs[SPEEDSTEP_HIGH].frequency,
+                               low, high,
                                NULL,
                                &speedstep_set_state);
 
                if (result) {
-                       dprintk("could not detect two different speeds -- aborting.\n");
+                       dprintk("could not detect two different speeds"
+                                       " -- aborting.\n");
                        return result;
                } else
                        dprintk("workaround worked.\n");
@@ -295,7 +325,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
        speed = speedstep_freqs[state].frequency;
 
        dprintk("currently at %s speed setting - %i MHz\n",
-               (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
+               (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
+               ? "low" : "high",
                (speed / 1000));
 
        /* cpuinfo and default policy values */
@@ -304,7 +335,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
 
        result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
        if (result)
-               return (result);
+               return result;
 
        cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
 
@@ -321,7 +352,7 @@ static unsigned int speedstep_get(unsigned int cpu)
 {
        if (cpu)
                return -ENODEV;
-       return speedstep_get_processor_frequency(speedstep_processor);
+       return speedstep_get_frequency(speedstep_processor);
 }
 
 
@@ -335,7 +366,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
        return result;
 }
 
-static struct freq_attrspeedstep_attr[] = {
+static struct freq_attr *speedstep_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        NULL,
 };
@@ -364,21 +395,23 @@ static int __init speedstep_init(void)
        speedstep_processor = speedstep_detect_processor();
 
        switch (speedstep_processor) {
-       case SPEEDSTEP_PROCESSOR_PIII_T:
-       case SPEEDSTEP_PROCESSOR_PIII_C:
-       case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
+       case SPEEDSTEP_CPU_PIII_T:
+       case SPEEDSTEP_CPU_PIII_C:
+       case SPEEDSTEP_CPU_PIII_C_EARLY:
                break;
        default:
                speedstep_processor = 0;
        }
 
        if (!speedstep_processor) {
-               dprintk ("No supported Intel CPU detected.\n");
+               dprintk("No supported Intel CPU detected.\n");
                return -ENODEV;
        }
 
-       dprintk("signature:0x%.8lx, command:0x%.8lx, event:0x%.8lx, perf_level:0x%.8lx.\n",
-               ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level);
+       dprintk("signature:0x%.8lx, command:0x%.8lx, "
+               "event:0x%.8lx, perf_level:0x%.8lx.\n",
+               ist_info.signature, ist_info.command,
+               ist_info.event, ist_info.perf_level);
 
        /* Error if no IST-SMI BIOS or no PARM
                 sig= 'ISGE' aka 'Intel Speedstep Gate E' */
@@ -416,17 +449,20 @@ static void __exit speedstep_exit(void)
        cpufreq_unregister_driver(&speedstep_driver);
 }
 
-module_param(smi_port,  int, 0444);
-module_param(smi_cmd,   int, 0444);
-module_param(smi_sig,  uint, 0444);
+module_param(smi_port, int, 0444);
+module_param(smi_cmd,  int, 0444);
+module_param(smi_sig, uint, 0444);
 
-MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value -- Intel's default setting is 0xb2");
-MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value -- Intel's default setting is 0x82");
-MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the SMI interface.");
+MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
+               "-- Intel's default setting is 0xb2");
+MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value "
+               "-- Intel's default setting is 0x82");
+MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the "
+               "SMI interface.");
 
-MODULE_AUTHOR ("Hiroshi Miura");
-MODULE_DESCRIPTION ("Speedstep driver for IST applet SMI interface.");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Hiroshi Miura");
+MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
+MODULE_LICENSE("GPL");
 
 module_init(speedstep_init);
 module_exit(speedstep_exit);
index d5cebb52d45ba3e30844b8171e275eb76647493c..b8e7aaf7ef751eee1fc338b79094a6a15dba6d4d 100644 (file)
@@ -543,8 +543,6 @@ unsigned long native_calibrate_tsc(void)
        return tsc_pit_min;
 }
 
-#ifdef CONFIG_X86_32
-/* Only called from the Powernow K7 cpu freq driver */
 int recalibrate_cpu_khz(void)
 {
 #ifndef CONFIG_SMP
@@ -566,7 +564,6 @@ int recalibrate_cpu_khz(void)
 
 EXPORT_SYMBOL(recalibrate_cpu_khz);
 
-#endif /* CONFIG_X86_32 */
 
 /* Accelerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
index 8dde4fcf99c947b7c292be0a775b102e43260879..74d0e622a5153beb758ca95123da6c07628ebc23 100644 (file)
@@ -56,6 +56,7 @@ config CRYPTO_BLKCIPHER2
        tristate
        select CRYPTO_ALGAPI2
        select CRYPTO_RNG2
+       select CRYPTO_WORKQUEUE
 
 config CRYPTO_HASH
        tristate
@@ -75,6 +76,10 @@ config CRYPTO_RNG2
        tristate
        select CRYPTO_ALGAPI2
 
+config CRYPTO_PCOMP
+       tristate
+       select CRYPTO_ALGAPI2
+
 config CRYPTO_MANAGER
        tristate "Cryptographic algorithm manager"
        select CRYPTO_MANAGER2
@@ -87,6 +92,7 @@ config CRYPTO_MANAGER2
        select CRYPTO_AEAD2
        select CRYPTO_HASH2
        select CRYPTO_BLKCIPHER2
+       select CRYPTO_PCOMP
 
 config CRYPTO_GF128MUL
        tristate "GF(2^128) multiplication functions (EXPERIMENTAL)"
@@ -106,11 +112,15 @@ config CRYPTO_NULL
        help
          These are 'Null' algorithms, used by IPsec, which do nothing.
 
+config CRYPTO_WORKQUEUE
+       tristate
+
 config CRYPTO_CRYPTD
        tristate "Software async crypto daemon"
        select CRYPTO_BLKCIPHER
        select CRYPTO_HASH
        select CRYPTO_MANAGER
+       select CRYPTO_WORKQUEUE
        help
          This is a generic software asynchronous crypto daemon that
          converts an arbitrary synchronous software crypto algorithm
@@ -470,6 +480,31 @@ config CRYPTO_AES_X86_64
 
          See <http://csrc.nist.gov/encryption/aes/> for more information.
 
+config CRYPTO_AES_NI_INTEL
+       tristate "AES cipher algorithms (AES-NI)"
+       depends on (X86 || UML_X86) && 64BIT
+       select CRYPTO_AES_X86_64
+       select CRYPTO_CRYPTD
+       select CRYPTO_ALGAPI
+       help
+         Use Intel AES-NI instructions for AES algorithm.
+
+         AES cipher algorithms (FIPS-197). AES uses the Rijndael
+         algorithm.
+
+         Rijndael appears to be consistently a very good performer in
+         both hardware and software across a wide range of computing
+         environments regardless of its use in feedback or non-feedback
+         modes. Its key setup time is excellent, and its key agility is
+         good. Rijndael's very low memory requirements make it very well
+         suited for restricted-space environments, in which it also
+         demonstrates excellent performance. Rijndael's operations are
+         among the easiest to defend against power and timing attacks.
+
+         The AES specifies three key sizes: 128, 192 and 256 bits
+
+         See <http://csrc.nist.gov/encryption/aes/> for more information.
+
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
        select CRYPTO_ALGAPI
@@ -714,6 +749,15 @@ config CRYPTO_DEFLATE
 
          You will most probably want this if using IPSec.
 
+config CRYPTO_ZLIB
+       tristate "Zlib compression algorithm"
+       select CRYPTO_PCOMP
+       select ZLIB_INFLATE
+       select ZLIB_DEFLATE
+       select NLATTR
+       help
+         This is the zlib algorithm.
+
 config CRYPTO_LZO
        tristate "LZO compression algorithm"
        select CRYPTO_ALGAPI
index 46b08bf2035fdfd5e404953aa2b5f8740efa4c82..673d9f7c1bda564be9869c763caf722b9bfc5d8b 100644 (file)
@@ -5,6 +5,8 @@
 obj-$(CONFIG_CRYPTO) += crypto.o
 crypto-objs := api.o cipher.o digest.o compress.o
 
+obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
+
 obj-$(CONFIG_CRYPTO_FIPS) += fips.o
 
 crypto_algapi-$(CONFIG_PROC_FS) += proc.o
@@ -25,6 +27,8 @@ crypto_hash-objs += ahash.o
 crypto_hash-objs += shash.o
 obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
 
+obj-$(CONFIG_CRYPTO_PCOMP) += pcompress.o
+
 cryptomgr-objs := algboss.o testmgr.o
 
 obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
@@ -70,6 +74,7 @@ obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
 obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
+obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
index 94140b3756fcd598d49179deac34ed5a80a83ed5..e11ce37c71043c4948b492a1fc97074a8164a436 100644 (file)
@@ -282,6 +282,25 @@ static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
                                          alg->cra_ablkcipher.ivsize))
                return alg;
 
+       crypto_mod_put(alg);
+       alg = crypto_alg_mod_lookup(name, type | CRYPTO_ALG_TESTED,
+                                   mask & ~CRYPTO_ALG_TESTED);
+       if (IS_ERR(alg))
+               return alg;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_GIVCIPHER) {
+               if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) {
+                       crypto_mod_put(alg);
+                       alg = ERR_PTR(-ENOENT);
+               }
+               return alg;
+       }
+
+       BUG_ON(!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+                CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+                                            alg->cra_ablkcipher.ivsize));
+
        return ERR_PTR(crypto_givcipher_default(alg, type, mask));
 }
 
index 3a6f3f52c7c71911ac6cd7506493fb24ccd8eb50..d9aa733db1647b51c1eea32de4840dc21cd9659d 100644 (file)
@@ -422,6 +422,22 @@ static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type,
        if (!alg->cra_aead.ivsize)
                return alg;
 
+       crypto_mod_put(alg);
+       alg = crypto_alg_mod_lookup(name, type | CRYPTO_ALG_TESTED,
+                                   mask & ~CRYPTO_ALG_TESTED);
+       if (IS_ERR(alg))
+               return alg;
+
+       if (alg->cra_type == &crypto_aead_type) {
+               if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) {
+                       crypto_mod_put(alg);
+                       alg = ERR_PTR(-ENOENT);
+               }
+               return alg;
+       }
+
+       BUG_ON(!alg->cra_aead.ivsize);
+
        return ERR_PTR(crypto_nivaead_default(alg, type, mask));
 }
 
index 4601e4267c886182d6b037983fe2630fffb5d8dd..6906f92aeac03330653a9539550861f1f6cffb9f 100644 (file)
@@ -10,7 +10,7 @@
  *
  */
 
-#include <linux/crypto.h>
+#include <crypto/internal/aead.h>
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -206,8 +206,7 @@ static int cryptomgr_test(void *data)
        u32 type = param->type;
        int err = 0;
 
-       if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
-             CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV))
+       if (type & CRYPTO_ALG_TESTED)
                goto skiptest;
 
        err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
@@ -223,6 +222,7 @@ static int cryptomgr_schedule_test(struct crypto_alg *alg)
 {
        struct task_struct *thread;
        struct crypto_test_param *param;
+       u32 type;
 
        if (!try_module_get(THIS_MODULE))
                goto err;
@@ -233,7 +233,19 @@ static int cryptomgr_schedule_test(struct crypto_alg *alg)
 
        memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
        memcpy(param->alg, alg->cra_name, sizeof(param->alg));
-       param->type = alg->cra_flags;
+       type = alg->cra_flags;
+
+       /* This piece of crap needs to disappear into per-type test hooks. */
+       if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
+              CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
+            ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+             CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+                                         alg->cra_ablkcipher.ivsize)) ||
+           (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) &&
+            alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize))
+               type |= CRYPTO_ALG_TESTED;
+
+       param->type = type;
 
        thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
        if (IS_ERR(thread))
index 0fac8ffc2fb7ef5dc6d39cca05d0292b584bb472..d80ed4c1e009da061b4d35d2e4bf3187e267b454 100644 (file)
@@ -132,9 +132,15 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
                         */
                        if (!memcmp(ctx->rand_data, ctx->last_rand_data,
                                        DEFAULT_BLK_SZ)) {
+                               if (fips_enabled) {
+                                       panic("cprng %p Failed repetition check!\n",
+                                               ctx);
+                               }
+
                                printk(KERN_ERR
                                        "ctx %p Failed repetition check!\n",
                                        ctx);
+
                                ctx->flags |= PRNG_NEED_RESET;
                                return -EINVAL;
                        }
@@ -338,7 +344,16 @@ static int cprng_init(struct crypto_tfm *tfm)
 
        spin_lock_init(&ctx->prng_lock);
 
-       return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL);
+       if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0)
+               return -EINVAL;
+
+       /*
+        * after allocation, we should always force the user to reset
+        * so they don't inadvertently use the insecure default values
+        * without specifying them intentially
+        */
+       ctx->flags |= PRNG_NEED_RESET;
+       return 0;
 }
 
 static void cprng_exit(struct crypto_tfm *tfm)
index 38a2bc02a98c7f6648f7a7a3388c6182b88c07f9..314dab96840e2792ee7af4b205b2ab63722faac4 100644 (file)
@@ -255,7 +255,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
        struct crypto_alg *larval;
        int ok;
 
-       if (!(mask & CRYPTO_ALG_TESTED)) {
+       if (!((type | mask) & CRYPTO_ALG_TESTED)) {
                type |= CRYPTO_ALG_TESTED;
                mask |= CRYPTO_ALG_TESTED;
        }
@@ -464,8 +464,8 @@ err:
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_base);
 
-struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
-                                    const struct crypto_type *frontend)
+void *crypto_create_tfm(struct crypto_alg *alg,
+                       const struct crypto_type *frontend)
 {
        char *mem;
        struct crypto_tfm *tfm = NULL;
@@ -499,9 +499,9 @@ out_free_tfm:
                crypto_shoot_alg(alg);
        kfree(mem);
 out_err:
-       tfm = ERR_PTR(err);
+       mem = ERR_PTR(err);
 out:
-       return tfm;
+       return mem;
 }
 EXPORT_SYMBOL_GPL(crypto_create_tfm);
 
@@ -525,12 +525,11 @@ EXPORT_SYMBOL_GPL(crypto_create_tfm);
  *
  *     In case of error the return value is an error pointer.
  */
-struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
-                                   const struct crypto_type *frontend,
-                                   u32 type, u32 mask)
+void *crypto_alloc_tfm(const char *alg_name,
+                      const struct crypto_type *frontend, u32 type, u32 mask)
 {
        struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
-       struct crypto_tfm *tfm;
+       void *tfm;
        int err;
 
        type &= frontend->maskclear;
index d70a41c002df192e49f77871cd0837732fbad861..90d26c91f4e9e183b2a41363318344e3d646c20a 100644 (file)
@@ -521,7 +521,7 @@ static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn,
        int err;
 
        type = crypto_skcipher_type(type);
-       mask = crypto_skcipher_mask(mask) | CRYPTO_ALG_GENIV;
+       mask = crypto_skcipher_mask(mask)| CRYPTO_ALG_GENIV;
 
        alg = crypto_alg_mod_lookup(name, type, mask);
        if (IS_ERR(alg))
index 7c37a497b860a27733eac07c4f7ff018c0abb4a3..ba200b07449d259cebf846a43e3f768e335606ef 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <crypto/internal/skcipher.h>
 #include <crypto/rng.h>
+#include <crypto/crypto_wq.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -133,7 +134,7 @@ static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx)
                        goto out;
        }
 
-       queued = schedule_work(&ctx->postponed);
+       queued = queue_work(kcrypto_wq, &ctx->postponed);
        BUG_ON(!queued);
 
 out:
index d29e06b350ffffb55d91fe62a00e7a804a324bbd..d14b22658d7a57d907344ba9145ae6c2c809660a 100644 (file)
 
 #include <crypto/algapi.h>
 #include <crypto/internal/hash.h>
+#include <crypto/cryptd.h>
+#include <crypto/crypto_wq.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 
-#define CRYPTD_MAX_QLEN 100
+#define CRYPTD_MAX_CPU_QLEN 100
 
-struct cryptd_state {
-       spinlock_t lock;
-       struct mutex mutex;
+struct cryptd_cpu_queue {
        struct crypto_queue queue;
-       struct task_struct *task;
+       struct work_struct work;
+};
+
+struct cryptd_queue {
+       struct cryptd_cpu_queue *cpu_queue;
 };
 
 struct cryptd_instance_ctx {
        struct crypto_spawn spawn;
-       struct cryptd_state *state;
+       struct cryptd_queue *queue;
 };
 
 struct cryptd_blkcipher_ctx {
@@ -54,11 +55,85 @@ struct cryptd_hash_request_ctx {
        crypto_completion_t complete;
 };
 
-static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm)
+static void cryptd_queue_worker(struct work_struct *work);
+
+static int cryptd_init_queue(struct cryptd_queue *queue,
+                            unsigned int max_cpu_qlen)
+{
+       int cpu;
+       struct cryptd_cpu_queue *cpu_queue;
+
+       queue->cpu_queue = alloc_percpu(struct cryptd_cpu_queue);
+       if (!queue->cpu_queue)
+               return -ENOMEM;
+       for_each_possible_cpu(cpu) {
+               cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu);
+               crypto_init_queue(&cpu_queue->queue, max_cpu_qlen);
+               INIT_WORK(&cpu_queue->work, cryptd_queue_worker);
+       }
+       return 0;
+}
+
+static void cryptd_fini_queue(struct cryptd_queue *queue)
+{
+       int cpu;
+       struct cryptd_cpu_queue *cpu_queue;
+
+       for_each_possible_cpu(cpu) {
+               cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu);
+               BUG_ON(cpu_queue->queue.qlen);
+       }
+       free_percpu(queue->cpu_queue);
+}
+
+static int cryptd_enqueue_request(struct cryptd_queue *queue,
+                                 struct crypto_async_request *request)
+{
+       int cpu, err;
+       struct cryptd_cpu_queue *cpu_queue;
+
+       cpu = get_cpu();
+       cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu);
+       err = crypto_enqueue_request(&cpu_queue->queue, request);
+       queue_work_on(cpu, kcrypto_wq, &cpu_queue->work);
+       put_cpu();
+
+       return err;
+}
+
+/* Called in workqueue context, do one real cryption work (via
+ * req->complete) and reschedule itself if there are more work to
+ * do. */
+static void cryptd_queue_worker(struct work_struct *work)
+{
+       struct cryptd_cpu_queue *cpu_queue;
+       struct crypto_async_request *req, *backlog;
+
+       cpu_queue = container_of(work, struct cryptd_cpu_queue, work);
+       /* Only handle one request at a time to avoid hogging crypto
+        * workqueue. preempt_disable/enable is used to prevent
+        * being preempted by cryptd_enqueue_request() */
+       preempt_disable();
+       backlog = crypto_get_backlog(&cpu_queue->queue);
+       req = crypto_dequeue_request(&cpu_queue->queue);
+       preempt_enable();
+
+       if (!req)
+               return;
+
+       if (backlog)
+               backlog->complete(backlog, -EINPROGRESS);
+       req->complete(req, 0);
+
+       if (cpu_queue->queue.qlen)
+               queue_work(kcrypto_wq, &cpu_queue->work);
+}
+
+static inline struct cryptd_queue *cryptd_get_queue(struct crypto_tfm *tfm)
 {
        struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
        struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
-       return ictx->state;
+       return ictx->queue;
 }
 
 static int cryptd_blkcipher_setkey(struct crypto_ablkcipher *parent,
@@ -130,19 +205,13 @@ static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req,
 {
        struct cryptd_blkcipher_request_ctx *rctx = ablkcipher_request_ctx(req);
        struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
-       struct cryptd_state *state =
-               cryptd_get_state(crypto_ablkcipher_tfm(tfm));
-       int err;
+       struct cryptd_queue *queue;
 
+       queue = cryptd_get_queue(crypto_ablkcipher_tfm(tfm));
        rctx->complete = req->base.complete;
        req->base.complete = complete;
 
-       spin_lock_bh(&state->lock);
-       err = ablkcipher_enqueue_request(&state->queue, req);
-       spin_unlock_bh(&state->lock);
-
-       wake_up_process(state->task);
-       return err;
+       return cryptd_enqueue_request(queue, &req->base);
 }
 
 static int cryptd_blkcipher_encrypt_enqueue(struct ablkcipher_request *req)
@@ -176,21 +245,12 @@ static int cryptd_blkcipher_init_tfm(struct crypto_tfm *tfm)
 static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm)
 {
        struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct cryptd_state *state = cryptd_get_state(tfm);
-       int active;
-
-       mutex_lock(&state->mutex);
-       active = ablkcipher_tfm_in_queue(&state->queue,
-                                        __crypto_ablkcipher_cast(tfm));
-       mutex_unlock(&state->mutex);
-
-       BUG_ON(active);
 
        crypto_free_blkcipher(ctx->child);
 }
 
 static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
-                                                    struct cryptd_state *state)
+                                                    struct cryptd_queue *queue)
 {
        struct crypto_instance *inst;
        struct cryptd_instance_ctx *ctx;
@@ -213,7 +273,7 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
        if (err)
                goto out_free_inst;
 
-       ctx->state = state;
+       ctx->queue = queue;
 
        memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
 
@@ -231,7 +291,7 @@ out_free_inst:
 }
 
 static struct crypto_instance *cryptd_alloc_blkcipher(
-       struct rtattr **tb, struct cryptd_state *state)
+       struct rtattr **tb, struct cryptd_queue *queue)
 {
        struct crypto_instance *inst;
        struct crypto_alg *alg;
@@ -241,7 +301,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
        if (IS_ERR(alg))
                return ERR_CAST(alg);
 
-       inst = cryptd_alloc_instance(alg, state);
+       inst = cryptd_alloc_instance(alg, queue);
        if (IS_ERR(inst))
                goto out_put_alg;
 
@@ -289,15 +349,6 @@ static int cryptd_hash_init_tfm(struct crypto_tfm *tfm)
 static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm)
 {
        struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct cryptd_state *state = cryptd_get_state(tfm);
-       int active;
-
-       mutex_lock(&state->mutex);
-       active = ahash_tfm_in_queue(&state->queue,
-                               __crypto_ahash_cast(tfm));
-       mutex_unlock(&state->mutex);
-
-       BUG_ON(active);
 
        crypto_free_hash(ctx->child);
 }
@@ -323,19 +374,13 @@ static int cryptd_hash_enqueue(struct ahash_request *req,
 {
        struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
        struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
-       struct cryptd_state *state =
-               cryptd_get_state(crypto_ahash_tfm(tfm));
-       int err;
+       struct cryptd_queue *queue =
+               cryptd_get_queue(crypto_ahash_tfm(tfm));
 
        rctx->complete = req->base.complete;
        req->base.complete = complete;
 
-       spin_lock_bh(&state->lock);
-       err = ahash_enqueue_request(&state->queue, req);
-       spin_unlock_bh(&state->lock);
-
-       wake_up_process(state->task);
-       return err;
+       return cryptd_enqueue_request(queue, &req->base);
 }
 
 static void cryptd_hash_init(struct crypto_async_request *req_async, int err)
@@ -468,7 +513,7 @@ static int cryptd_hash_digest_enqueue(struct ahash_request *req)
 }
 
 static struct crypto_instance *cryptd_alloc_hash(
-       struct rtattr **tb, struct cryptd_state *state)
+       struct rtattr **tb, struct cryptd_queue *queue)
 {
        struct crypto_instance *inst;
        struct crypto_alg *alg;
@@ -478,7 +523,7 @@ static struct crypto_instance *cryptd_alloc_hash(
        if (IS_ERR(alg))
                return ERR_PTR(PTR_ERR(alg));
 
-       inst = cryptd_alloc_instance(alg, state);
+       inst = cryptd_alloc_instance(alg, queue);
        if (IS_ERR(inst))
                goto out_put_alg;
 
@@ -502,7 +547,7 @@ out_put_alg:
        return inst;
 }
 
-static struct cryptd_state state;
+static struct cryptd_queue queue;
 
 static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
 {
@@ -514,9 +559,9 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
 
        switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
        case CRYPTO_ALG_TYPE_BLKCIPHER:
-               return cryptd_alloc_blkcipher(tb, &state);
+               return cryptd_alloc_blkcipher(tb, &queue);
        case CRYPTO_ALG_TYPE_DIGEST:
-               return cryptd_alloc_hash(tb, &state);
+               return cryptd_alloc_hash(tb, &queue);
        }
 
        return ERR_PTR(-EINVAL);
@@ -537,82 +582,58 @@ static struct crypto_template cryptd_tmpl = {
        .module = THIS_MODULE,
 };
 
-static inline int cryptd_create_thread(struct cryptd_state *state,
-                                      int (*fn)(void *data), const char *name)
-{
-       spin_lock_init(&state->lock);
-       mutex_init(&state->mutex);
-       crypto_init_queue(&state->queue, CRYPTD_MAX_QLEN);
-
-       state->task = kthread_run(fn, state, name);
-       if (IS_ERR(state->task))
-               return PTR_ERR(state->task);
+struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask)
+{
+       char cryptd_alg_name[CRYPTO_MAX_ALG_NAME];
+       struct crypto_ablkcipher *tfm;
+
+       if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME,
+                    "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-EINVAL);
+       tfm = crypto_alloc_ablkcipher(cryptd_alg_name, type, mask);
+       if (IS_ERR(tfm))
+               return ERR_CAST(tfm);
+       if (crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_module != THIS_MODULE) {
+               crypto_free_ablkcipher(tfm);
+               return ERR_PTR(-EINVAL);
+       }
 
-       return 0;
+       return __cryptd_ablkcipher_cast(tfm);
 }
+EXPORT_SYMBOL_GPL(cryptd_alloc_ablkcipher);
 
-static inline void cryptd_stop_thread(struct cryptd_state *state)
+struct crypto_blkcipher *cryptd_ablkcipher_child(struct cryptd_ablkcipher *tfm)
 {
-       BUG_ON(state->queue.qlen);
-       kthread_stop(state->task);
+       struct cryptd_blkcipher_ctx *ctx = crypto_ablkcipher_ctx(&tfm->base);
+       return ctx->child;
 }
+EXPORT_SYMBOL_GPL(cryptd_ablkcipher_child);
 
-static int cryptd_thread(void *data)
+void cryptd_free_ablkcipher(struct cryptd_ablkcipher *tfm)
 {
-       struct cryptd_state *state = data;
-       int stop;
-
-       current->flags |= PF_NOFREEZE;
-
-       do {
-               struct crypto_async_request *req, *backlog;
-
-               mutex_lock(&state->mutex);
-               __set_current_state(TASK_INTERRUPTIBLE);
-
-               spin_lock_bh(&state->lock);
-               backlog = crypto_get_backlog(&state->queue);
-               req = crypto_dequeue_request(&state->queue);
-               spin_unlock_bh(&state->lock);
-
-               stop = kthread_should_stop();
-
-               if (stop || req) {
-                       __set_current_state(TASK_RUNNING);
-                       if (req) {
-                               if (backlog)
-                                       backlog->complete(backlog,
-                                                         -EINPROGRESS);
-                               req->complete(req, 0);
-                       }
-               }
-
-               mutex_unlock(&state->mutex);
-
-               schedule();
-       } while (!stop);
-
-       return 0;
+       crypto_free_ablkcipher(&tfm->base);
 }
+EXPORT_SYMBOL_GPL(cryptd_free_ablkcipher);
 
 static int __init cryptd_init(void)
 {
        int err;
 
-       err = cryptd_create_thread(&state, cryptd_thread, "cryptd");
+       err = cryptd_init_queue(&queue, CRYPTD_MAX_CPU_QLEN);
        if (err)
                return err;
 
        err = crypto_register_template(&cryptd_tmpl);
        if (err)
-               kthread_stop(state.task);
+               cryptd_fini_queue(&queue);
 
        return err;
 }
 
 static void __exit cryptd_exit(void)
 {
-       cryptd_stop_thread(&state);
+       cryptd_fini_queue(&queue);
        crypto_unregister_template(&cryptd_tmpl);
 }
 
diff --git a/crypto/crypto_wq.c b/crypto/crypto_wq.c
new file mode 100644 (file)
index 0000000..fdcf624
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Workqueue for crypto subsystem
+ *
+ * Copyright (c) 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <crypto/algapi.h>
+#include <crypto/crypto_wq.h>
+
+struct workqueue_struct *kcrypto_wq;
+EXPORT_SYMBOL_GPL(kcrypto_wq);
+
+static int __init crypto_wq_init(void)
+{
+       kcrypto_wq = create_workqueue("crypto");
+       if (unlikely(!kcrypto_wq))
+               return -ENOMEM;
+       return 0;
+}
+
+static void __exit crypto_wq_exit(void)
+{
+       destroy_workqueue(kcrypto_wq);
+}
+
+module_init(crypto_wq_init);
+module_exit(crypto_wq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Workqueue for crypto subsystem");
index ecbeaa1f17e1eae7f17b04c05e922283b0472dd1..a90d260528d4fbe09e3df8832736dc627f25de21 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006, Rik Snel <rsnel@cube.dyndns.org>
  *
  * Based on Dr Brian Gladman's (GPL'd) work published at
- * http://fp.gladman.plus.com/cryptography_technology/index.htm
+ * http://gladman.plushost.co.uk/oldsite/cryptography_technology/index.php
  * See the original copyright notice below.
  *
  * This program is free software; you can redistribute it and/or modify it
index 3c19a27a7563cd628513a777a59121a24caadf85..fc76e1f37fc35d0fd4928ec9326b330c22937d53 100644 (file)
@@ -109,8 +109,10 @@ void crypto_alg_tested(const char *name, int err);
 void crypto_shoot_alg(struct crypto_alg *alg);
 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
                                      u32 mask);
-struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
-                                    const struct crypto_type *frontend);
+void *crypto_create_tfm(struct crypto_alg *alg,
+                       const struct crypto_type *frontend);
+void *crypto_alloc_tfm(const char *alg_name,
+                      const struct crypto_type *frontend, u32 type, u32 mask);
 
 int crypto_register_instance(struct crypto_template *tmpl,
                             struct crypto_instance *inst);
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
new file mode 100644 (file)
index 0000000..ca9a4af
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Cryptographic API.
+ *
+ * Partial (de)compression operations.
+ *
+ * Copyright 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+#include <crypto/compress.h>
+
+#include "internal.h"
+
+
+static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+       return 0;
+}
+
+static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg,
+                                        const struct crypto_type *frontend)
+{
+       return alg->cra_ctxsize;
+}
+
+static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm,
+                                const struct crypto_type *frontend)
+{
+       return 0;
+}
+
+static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
+       __attribute__ ((unused));
+static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
+{
+       seq_printf(m, "type         : pcomp\n");
+}
+
+static const struct crypto_type crypto_pcomp_type = {
+       .extsize        = crypto_pcomp_extsize,
+       .init           = crypto_pcomp_init,
+       .init_tfm       = crypto_pcomp_init_tfm,
+#ifdef CONFIG_PROC_FS
+       .show           = crypto_pcomp_show,
+#endif
+       .maskclear      = ~CRYPTO_ALG_TYPE_MASK,
+       .maskset        = CRYPTO_ALG_TYPE_MASK,
+       .type           = CRYPTO_ALG_TYPE_PCOMPRESS,
+       .tfmsize        = offsetof(struct crypto_pcomp, base),
+};
+
+struct crypto_pcomp *crypto_alloc_pcomp(const char *alg_name, u32 type,
+                                       u32 mask)
+{
+       return crypto_alloc_tfm(alg_name, &crypto_pcomp_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_pcomp);
+
+int crypto_register_pcomp(struct pcomp_alg *alg)
+{
+       struct crypto_alg *base = &alg->base;
+
+       base->cra_type = &crypto_pcomp_type;
+       base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+       base->cra_flags |= CRYPTO_ALG_TYPE_PCOMPRESS;
+
+       return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_pcomp);
+
+int crypto_unregister_pcomp(struct pcomp_alg *alg)
+{
+       return crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_pcomp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Partial (de)compression type");
+MODULE_AUTHOR("Sony Corporation");
index caa3542e6ce8943a2b5ed5f9a0f0aaded9a486cc..6349d8339d379cc6862dba1fadf54bc2cdfe3eb3 100644 (file)
@@ -2,7 +2,7 @@
  * Cryptographic API.
  *
  * SHA-256, as specified in
- * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
+ * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
  *
  * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
  *
index d5a2b619c55f79e3b7cbff1f1d06d3048364b49c..7a659733f94a4e1087fabcfc8d5e48fd6c5c4521 100644 (file)
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 
-static const struct crypto_type crypto_shash_type;
-
-static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm)
-{
-       return container_of(tfm, struct crypto_shash, base);
-}
-
 #include "internal.h"
 
+static const struct crypto_type crypto_shash_type;
+
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
                                  unsigned int keylen)
 {
@@ -282,8 +277,7 @@ static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
        if (!crypto_mod_get(calg))
                return -EAGAIN;
 
-       shash = __crypto_shash_cast(crypto_create_tfm(
-               calg, &crypto_shash_type));
+       shash = crypto_create_tfm(calg, &crypto_shash_type);
        if (IS_ERR(shash)) {
                crypto_mod_put(calg);
                return PTR_ERR(shash);
@@ -391,8 +385,7 @@ static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
        if (!crypto_mod_get(calg))
                return -EAGAIN;
 
-       shash = __crypto_shash_cast(crypto_create_tfm(
-               calg, &crypto_shash_type));
+       shash = crypto_create_tfm(calg, &crypto_shash_type);
        if (IS_ERR(shash)) {
                crypto_mod_put(calg);
                return PTR_ERR(shash);
@@ -442,8 +435,6 @@ static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
 static int crypto_shash_init_tfm(struct crypto_tfm *tfm,
                                 const struct crypto_type *frontend)
 {
-       if (frontend->type != CRYPTO_ALG_TYPE_SHASH)
-               return -EINVAL;
        return 0;
 }
 
@@ -482,8 +473,7 @@ static const struct crypto_type crypto_shash_type = {
 struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
                                        u32 mask)
 {
-       return __crypto_shash_cast(
-               crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask));
+       return crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask);
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_shash);
 
index 28a45a1e6f423603a563ef40c821736a88ef266b..c3c9124209a1901baae3f8e6d9b1a6e437e97901 100644 (file)
@@ -53,7 +53,7 @@ static char *check[] = {
        "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
        "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
        "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",
-       "lzo", "cts", NULL
+       "lzo", "cts", "zlib", NULL
 };
 
 static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc,
@@ -661,6 +661,10 @@ static void do_test(int m)
                tcrypt_test("ecb(seed)");
                break;
 
+       case 44:
+               tcrypt_test("zlib");
+               break;
+
        case 100:
                tcrypt_test("hmac(md5)");
                break;
index a75f11ffb957257d15d67b7eecf55c666466b0f5..b50c3c6b17a26301a8a799bf62a29fe5e0c89d46 100644 (file)
@@ -72,6 +72,13 @@ struct comp_test_suite {
        } comp, decomp;
 };
 
+struct pcomp_test_suite {
+       struct {
+               struct pcomp_testvec *vecs;
+               unsigned int count;
+       } comp, decomp;
+};
+
 struct hash_test_suite {
        struct hash_testvec *vecs;
        unsigned int count;
@@ -86,6 +93,7 @@ struct alg_test_desc {
                struct aead_test_suite aead;
                struct cipher_test_suite cipher;
                struct comp_test_suite comp;
+               struct pcomp_test_suite pcomp;
                struct hash_test_suite hash;
        } suite;
 };
@@ -898,6 +906,159 @@ out:
        return ret;
 }
 
+static int test_pcomp(struct crypto_pcomp *tfm,
+                     struct pcomp_testvec *ctemplate,
+                     struct pcomp_testvec *dtemplate, int ctcount,
+                     int dtcount)
+{
+       const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
+       unsigned int i;
+       char result[COMP_BUF_SIZE];
+       int error;
+
+       for (i = 0; i < ctcount; i++) {
+               struct comp_request req;
+
+               error = crypto_compress_setup(tfm, ctemplate[i].params,
+                                             ctemplate[i].paramsize);
+               if (error) {
+                       pr_err("alg: pcomp: compression setup failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               error = crypto_compress_init(tfm);
+               if (error) {
+                       pr_err("alg: pcomp: compression init failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               memset(result, 0, sizeof(result));
+
+               req.next_in = ctemplate[i].input;
+               req.avail_in = ctemplate[i].inlen / 2;
+               req.next_out = result;
+               req.avail_out = ctemplate[i].outlen / 2;
+
+               error = crypto_compress_update(tfm, &req);
+               if (error && (error != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               /* Add remaining input data */
+               req.avail_in += (ctemplate[i].inlen + 1) / 2;
+
+               error = crypto_compress_update(tfm, &req);
+               if (error && (error != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: compression update failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
+
+               error = crypto_compress_final(tfm, &req);
+               if (error) {
+                       pr_err("alg: pcomp: compression final failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
+                       pr_err("alg: comp: Compression test %d failed for %s: "
+                              "output len = %d (expected %d)\n", i + 1, algo,
+                              COMP_BUF_SIZE - req.avail_out,
+                              ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Compression test %d failed for "
+                              "%s\n", i + 1, algo);
+                       hexdump(result, ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < dtcount; i++) {
+               struct comp_request req;
+
+               error = crypto_decompress_setup(tfm, dtemplate[i].params,
+                                               dtemplate[i].paramsize);
+               if (error) {
+                       pr_err("alg: pcomp: decompression setup failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo,
+                              error);
+                       return error;
+               }
+
+               error = crypto_decompress_init(tfm);
+               if (error) {
+                       pr_err("alg: pcomp: decompression init failed on test "
+                              "%d for %s: error=%d\n", i + 1, algo, error);
+                       return error;
+               }
+
+               memset(result, 0, sizeof(result));
+
+               req.next_in = dtemplate[i].input;
+               req.avail_in = dtemplate[i].inlen / 2;
+               req.next_out = result;
+               req.avail_out = dtemplate[i].outlen / 2;
+
+               error = crypto_decompress_update(tfm, &req);
+               if (error  && (error != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo,
+                              error);
+                       return error;
+               }
+
+               /* Add remaining input data */
+               req.avail_in += (dtemplate[i].inlen + 1) / 2;
+
+               error = crypto_decompress_update(tfm, &req);
+               if (error  && (error != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression update failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo,
+                              error);
+                       return error;
+               }
+
+               /* Provide remaining output space */
+               req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
+
+               error = crypto_decompress_final(tfm, &req);
+               if (error  && (error != -EAGAIN || req.avail_in)) {
+                       pr_err("alg: pcomp: decompression final failed on "
+                              "test %d for %s: error=%d\n", i + 1, algo,
+                              error);
+                       return error;
+               }
+
+               if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
+                       pr_err("alg: comp: Decompression test %d failed for "
+                              "%s: output len = %d (expected %d)\n", i + 1,
+                              algo, COMP_BUF_SIZE - req.avail_out,
+                              dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+
+               if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
+                       pr_err("alg: pcomp: Decompression test %d failed for "
+                              "%s\n", i + 1, algo);
+                       hexdump(result, dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -1007,6 +1168,28 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver,
        return err;
 }
 
+static int alg_test_pcomp(const struct alg_test_desc *desc, const char *driver,
+                         u32 type, u32 mask)
+{
+       struct crypto_pcomp *tfm;
+       int err;
+
+       tfm = crypto_alloc_pcomp(driver, type, mask);
+       if (IS_ERR(tfm)) {
+               pr_err("alg: pcomp: Failed to load transform for %s: %ld\n",
+                      driver, PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+
+       err = test_pcomp(tfm, desc->suite.pcomp.comp.vecs,
+                        desc->suite.pcomp.decomp.vecs,
+                        desc->suite.pcomp.comp.count,
+                        desc->suite.pcomp.decomp.count);
+
+       crypto_free_pcomp(tfm);
+       return err;
+}
+
 static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -1835,6 +2018,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "zlib",
+               .test = alg_test_pcomp,
+               .suite = {
+                       .pcomp = {
+                               .comp = {
+                                       .vecs = zlib_comp_tv_template,
+                                       .count = ZLIB_COMP_TEST_VECTORS
+                               },
+                               .decomp = {
+                                       .vecs = zlib_decomp_tv_template,
+                                       .count = ZLIB_DECOMP_TEST_VECTORS
+                               }
+                       }
+               }
        }
 };
 
index 132953e144d34bcb0766f4eebfce32107c7a489b..526f00a9c72feba6acd49b42f0281a79944657e5 100644 (file)
 #ifndef _CRYPTO_TESTMGR_H
 #define _CRYPTO_TESTMGR_H
 
+#include <linux/netlink.h>
+#include <linux/zlib.h>
+
+#include <crypto/compress.h>
+
 #define MAX_DIGEST_SIZE                64
 #define MAX_TAP                        8
 
@@ -8347,10 +8352,19 @@ struct comp_testvec {
        char output[COMP_BUF_SIZE];
 };
 
+struct pcomp_testvec {
+       void *params;
+       unsigned int paramsize;
+       int inlen, outlen;
+       char input[COMP_BUF_SIZE];
+       char output[COMP_BUF_SIZE];
+};
+
 /*
  * Deflate test vectors (null-terminated strings).
  * Params: winbits=-11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
  */
+
 #define DEFLATE_COMP_TEST_VECTORS 2
 #define DEFLATE_DECOMP_TEST_VECTORS 2
 
@@ -8426,6 +8440,139 @@ static struct comp_testvec deflate_decomp_tv_template[] = {
        },
 };
 
+#define ZLIB_COMP_TEST_VECTORS 2
+#define ZLIB_DECOMP_TEST_VECTORS 2
+
+static const struct {
+       struct nlattr nla;
+       int val;
+} deflate_comp_params[] = {
+       {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_COMP_LEVEL,
+               },
+               .val                    = Z_DEFAULT_COMPRESSION,
+       }, {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_COMP_METHOD,
+               },
+               .val                    = Z_DEFLATED,
+       }, {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_COMP_WINDOWBITS,
+               },
+               .val                    = -11,
+       }, {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_COMP_MEMLEVEL,
+               },
+               .val                    = MAX_MEM_LEVEL,
+       }, {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_COMP_STRATEGY,
+               },
+               .val                    = Z_DEFAULT_STRATEGY,
+       }
+};
+
+static const struct {
+       struct nlattr nla;
+       int val;
+} deflate_decomp_params[] = {
+       {
+               .nla = {
+                       .nla_len        = NLA_HDRLEN + sizeof(int),
+                       .nla_type       = ZLIB_DECOMP_WINDOWBITS,
+               },
+               .val                    = -11,
+       }
+};
+
+static struct pcomp_testvec zlib_comp_tv_template[] = {
+       {
+               .params = &deflate_comp_params,
+               .paramsize = sizeof(deflate_comp_params),
+               .inlen  = 70,
+               .outlen = 38,
+               .input  = "Join us now and share the software "
+                       "Join us now and share the software ",
+               .output = "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
+                         "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
+                         "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
+                         "\x48\x55\x28\xce\x4f\x2b\x29\x07"
+                         "\x71\xbc\x08\x2b\x01\x00",
+       }, {
+               .params = &deflate_comp_params,
+               .paramsize = sizeof(deflate_comp_params),
+               .inlen  = 191,
+               .outlen = 122,
+               .input  = "This document describes a compression method based on the DEFLATE"
+                       "compression algorithm.  This document defines the application of "
+                       "the DEFLATE algorithm to the IP Payload Compression Protocol.",
+               .output = "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
+                         "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
+                         "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
+                         "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
+                         "\x68\x12\x51\xae\x76\x67\xd6\x27"
+                         "\x19\x88\x1a\xde\x85\xab\x21\xf2"
+                         "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
+                         "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
+                         "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
+                         "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
+                         "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
+                         "\x52\x37\xed\x0e\x52\x6b\x59\x02"
+                         "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
+                         "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
+                         "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
+                         "\xfa\x02",
+       },
+};
+
+static struct pcomp_testvec zlib_decomp_tv_template[] = {
+       {
+               .params = &deflate_decomp_params,
+               .paramsize = sizeof(deflate_decomp_params),
+               .inlen  = 122,
+               .outlen = 191,
+               .input  = "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
+                         "\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
+                         "\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
+                         "\x24\xdb\x67\xd9\x47\xc1\xef\x49"
+                         "\x68\x12\x51\xae\x76\x67\xd6\x27"
+                         "\x19\x88\x1a\xde\x85\xab\x21\xf2"
+                         "\x08\x5d\x16\x1e\x20\x04\x2d\xad"
+                         "\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
+                         "\x42\x83\x23\xb6\x6c\x89\x71\x9b"
+                         "\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
+                         "\xed\x62\xa9\x4c\x80\xff\x13\xaf"
+                         "\x52\x37\xed\x0e\x52\x6b\x59\x02"
+                         "\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
+                         "\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
+                         "\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
+                         "\xfa\x02",
+               .output = "This document describes a compression method based on the DEFLATE"
+                       "compression algorithm.  This document defines the application of "
+                       "the DEFLATE algorithm to the IP Payload Compression Protocol.",
+       }, {
+               .params = &deflate_decomp_params,
+               .paramsize = sizeof(deflate_decomp_params),
+               .inlen  = 38,
+               .outlen = 70,
+               .input  = "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
+                         "\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
+                         "\x28\xce\x48\x2c\x4a\x55\x28\xc9"
+                         "\x48\x55\x28\xce\x4f\x2b\x29\x07"
+                         "\x71\xbc\x08\x2b\x01\x00",
+               .output = "Join us now and share the software "
+                       "Join us now and share the software ",
+       },
+};
+
 /*
  * LZO test vectors (null-terminated strings).
  */
diff --git a/crypto/zlib.c b/crypto/zlib.c
new file mode 100644 (file)
index 0000000..33609ba
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Cryptographic API.
+ *
+ * Zlib algorithm
+ *
+ * Copyright 2008 Sony Corporation
+ *
+ * Based on deflate.c, which is
+ * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * FIXME: deflate transforms will require up to a total of about 436k of kernel
+ * memory on i386 (390k for compression, the rest for decompression), as the
+ * current zlib kernel code uses a worst case pre-allocation system by default.
+ * This needs to be fixed so that the amount of memory required is properly
+ * related to the winbits and memlevel parameters.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/zlib.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+
+#include <crypto/internal/compress.h>
+
+#include <net/netlink.h>
+
+
+struct zlib_ctx {
+       struct z_stream_s comp_stream;
+       struct z_stream_s decomp_stream;
+       int decomp_windowBits;
+};
+
+
+static void zlib_comp_exit(struct zlib_ctx *ctx)
+{
+       struct z_stream_s *stream = &ctx->comp_stream;
+
+       if (stream->workspace) {
+               zlib_deflateEnd(stream);
+               vfree(stream->workspace);
+               stream->workspace = NULL;
+       }
+}
+
+static void zlib_decomp_exit(struct zlib_ctx *ctx)
+{
+       struct z_stream_s *stream = &ctx->decomp_stream;
+
+       if (stream->workspace) {
+               zlib_inflateEnd(stream);
+               kfree(stream->workspace);
+               stream->workspace = NULL;
+       }
+}
+
+static int zlib_init(struct crypto_tfm *tfm)
+{
+       return 0;
+}
+
+static void zlib_exit(struct crypto_tfm *tfm)
+{
+       struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       zlib_comp_exit(ctx);
+       zlib_decomp_exit(ctx);
+}
+
+
+static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
+                              unsigned int len)
+{
+       struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &ctx->comp_stream;
+       struct nlattr *tb[ZLIB_COMP_MAX + 1];
+       size_t workspacesize;
+       int ret;
+
+       ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
+       if (ret)
+               return ret;
+
+       zlib_comp_exit(ctx);
+
+       workspacesize = zlib_deflate_workspacesize();
+       stream->workspace = vmalloc(workspacesize);
+       if (!stream->workspace)
+               return -ENOMEM;
+
+       memset(stream->workspace, 0, workspacesize);
+       ret = zlib_deflateInit2(stream,
+                               tb[ZLIB_COMP_LEVEL]
+                                       ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
+                                       : Z_DEFAULT_COMPRESSION,
+                               tb[ZLIB_COMP_METHOD]
+                                       ? nla_get_u32(tb[ZLIB_COMP_METHOD])
+                                       : Z_DEFLATED,
+                               tb[ZLIB_COMP_WINDOWBITS]
+                                       ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
+                                       : MAX_WBITS,
+                               tb[ZLIB_COMP_MEMLEVEL]
+                                       ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
+                                       : DEF_MEM_LEVEL,
+                               tb[ZLIB_COMP_STRATEGY]
+                                       ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
+                                       : Z_DEFAULT_STRATEGY);
+       if (ret != Z_OK) {
+               vfree(stream->workspace);
+               stream->workspace = NULL;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int zlib_compress_init(struct crypto_pcomp *tfm)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->comp_stream;
+
+       ret = zlib_deflateReset(stream);
+       if (ret != Z_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int zlib_compress_update(struct crypto_pcomp *tfm,
+                               struct comp_request *req)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->comp_stream;
+
+       pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
+       stream->next_in = req->next_in;
+       stream->avail_in = req->avail_in;
+       stream->next_out = req->next_out;
+       stream->avail_out = req->avail_out;
+
+       ret = zlib_deflate(stream, Z_NO_FLUSH);
+       switch (ret) {
+       case Z_OK:
+               break;
+
+       case Z_BUF_ERROR:
+               pr_debug("zlib_deflate could not make progress\n");
+               return -EAGAIN;
+
+       default:
+               pr_debug("zlib_deflate failed %d\n", ret);
+               return -EINVAL;
+       }
+
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+                req->avail_in - stream->avail_in,
+                req->avail_out - stream->avail_out);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+       return 0;
+}
+
+static int zlib_compress_final(struct crypto_pcomp *tfm,
+                              struct comp_request *req)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->comp_stream;
+
+       pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
+       stream->next_in = req->next_in;
+       stream->avail_in = req->avail_in;
+       stream->next_out = req->next_out;
+       stream->avail_out = req->avail_out;
+
+       ret = zlib_deflate(stream, Z_FINISH);
+       if (ret != Z_STREAM_END) {
+               pr_debug("zlib_deflate failed %d\n", ret);
+               return -EINVAL;
+       }
+
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+                req->avail_in - stream->avail_in,
+                req->avail_out - stream->avail_out);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+       return 0;
+}
+
+
+static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
+                                unsigned int len)
+{
+       struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &ctx->decomp_stream;
+       struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
+       int ret = 0;
+
+       ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
+       if (ret)
+               return ret;
+
+       zlib_decomp_exit(ctx);
+
+       ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
+                                ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
+                                : DEF_WBITS;
+
+       stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+       if (!stream->workspace)
+               return -ENOMEM;
+
+       ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
+       if (ret != Z_OK) {
+               kfree(stream->workspace);
+               stream->workspace = NULL;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int zlib_decompress_init(struct crypto_pcomp *tfm)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->decomp_stream;
+
+       ret = zlib_inflateReset(stream);
+       if (ret != Z_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int zlib_decompress_update(struct crypto_pcomp *tfm,
+                                 struct comp_request *req)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->decomp_stream;
+
+       pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
+       stream->next_in = req->next_in;
+       stream->avail_in = req->avail_in;
+       stream->next_out = req->next_out;
+       stream->avail_out = req->avail_out;
+
+       ret = zlib_inflate(stream, Z_SYNC_FLUSH);
+       switch (ret) {
+       case Z_OK:
+       case Z_STREAM_END:
+               break;
+
+       case Z_BUF_ERROR:
+               pr_debug("zlib_inflate could not make progress\n");
+               return -EAGAIN;
+
+       default:
+               pr_debug("zlib_inflate failed %d\n", ret);
+               return -EINVAL;
+       }
+
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+                req->avail_in - stream->avail_in,
+                req->avail_out - stream->avail_out);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+       return 0;
+}
+
+static int zlib_decompress_final(struct crypto_pcomp *tfm,
+                                struct comp_request *req)
+{
+       int ret;
+       struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
+       struct z_stream_s *stream = &dctx->decomp_stream;
+
+       pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
+       stream->next_in = req->next_in;
+       stream->avail_in = req->avail_in;
+       stream->next_out = req->next_out;
+       stream->avail_out = req->avail_out;
+
+       if (dctx->decomp_windowBits < 0) {
+               ret = zlib_inflate(stream, Z_SYNC_FLUSH);
+               /*
+                * Work around a bug in zlib, which sometimes wants to taste an
+                * extra byte when being used in the (undocumented) raw deflate
+                * mode. (From USAGI).
+                */
+               if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
+                       const void *saved_next_in = stream->next_in;
+                       u8 zerostuff = 0;
+
+                       stream->next_in = &zerostuff;
+                       stream->avail_in = 1;
+                       ret = zlib_inflate(stream, Z_FINISH);
+                       stream->next_in = saved_next_in;
+                       stream->avail_in = 0;
+               }
+       } else
+               ret = zlib_inflate(stream, Z_FINISH);
+       if (ret != Z_STREAM_END) {
+               pr_debug("zlib_inflate failed %d\n", ret);
+               return -EINVAL;
+       }
+
+       pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
+                stream->avail_in, stream->avail_out,
+                req->avail_in - stream->avail_in,
+                req->avail_out - stream->avail_out);
+       req->next_in = stream->next_in;
+       req->avail_in = stream->avail_in;
+       req->next_out = stream->next_out;
+       req->avail_out = stream->avail_out;
+       return 0;
+}
+
+
+static struct pcomp_alg zlib_alg = {
+       .compress_setup         = zlib_compress_setup,
+       .compress_init          = zlib_compress_init,
+       .compress_update        = zlib_compress_update,
+       .compress_final         = zlib_compress_final,
+       .decompress_setup       = zlib_decompress_setup,
+       .decompress_init        = zlib_decompress_init,
+       .decompress_update      = zlib_decompress_update,
+       .decompress_final       = zlib_decompress_final,
+
+       .base                   = {
+               .cra_name       = "zlib",
+               .cra_flags      = CRYPTO_ALG_TYPE_PCOMPRESS,
+               .cra_ctxsize    = sizeof(struct zlib_ctx),
+               .cra_module     = THIS_MODULE,
+               .cra_init       = zlib_init,
+               .cra_exit       = zlib_exit,
+       }
+};
+
+static int __init zlib_mod_init(void)
+{
+       return crypto_register_pcomp(&zlib_alg);
+}
+
+static void __exit zlib_mod_fini(void)
+{
+       crypto_unregister_pcomp(&zlib_alg);
+}
+
+module_init(zlib_mod_init);
+module_exit(zlib_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Zlib Compression Algorithm");
+MODULE_AUTHOR("Sony Corporation");
index 35094f230b1e339d2d969ca27cb89816c7d3d9de..7af7db1ba8c452c05ef730ab432cabb8c7b59309 100644 (file)
@@ -977,7 +977,7 @@ static int dock_add(acpi_handle handle)
                sizeof(struct dock_station *));
 
        /* we want the dock device to send uevents */
-       dock_device->dev.uevent_suppress = 0;
+       dev_set_uevent_suppress(&dock_device->dev, 0);
 
        if (is_dock(handle))
                dock_station->flags |= DOCK_IS_DOCK;
index 00c46e0b40e47eec54b2710f06cbe59d7308905f..3d763fdf99b7d2409f8dbf425822ace5f1063cea 100644 (file)
@@ -210,7 +210,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        dev->dev.release = amba_device_release;
        dev->dev.bus = &amba_bustype;
        dev->dev.dma_mask = &dev->dma_mask;
-       dev->res.name = dev->dev.bus_id;
+       dev->res.name = dev_name(&dev->dev);
 
        if (!dev->dev.coherent_dma_mask && dev->dma_mask)
                dev_warn(&dev->dev, "coherent dma mask is unset\n");
@@ -294,7 +294,7 @@ static int amba_find_match(struct device *dev, void *data)
        if (d->parent)
                r &= d->parent == dev->parent;
        if (d->busid)
-               r &= strcmp(dev->bus_id, d->busid) == 0;
+               r &= strcmp(dev_name(dev), d->busid) == 0;
 
        if (r) {
                get_device(dev);
index 9f50f1b545dc49de323135663628da1566797175..ddc97496db4a4af3a1c7438b43622d621264ab13 100644 (file)
@@ -63,6 +63,32 @@ struct class_private {
 #define to_class(obj)  \
        container_of(obj, struct class_private, class_subsys.kobj)
 
+/**
+ * struct device_private - structure to hold the private to the driver core portions of the device structure.
+ *
+ * @klist_children - klist containing all children of this device
+ * @knode_parent - node in sibling list
+ * @knode_driver - node in driver list
+ * @knode_bus - node in bus list
+ * @device - pointer back to the struct class that this structure is
+ * associated with.
+ *
+ * Nothing outside of the driver core should ever touch these fields.
+ */
+struct device_private {
+       struct klist klist_children;
+       struct klist_node knode_parent;
+       struct klist_node knode_driver;
+       struct klist_node knode_bus;
+       struct device *device;
+};
+#define to_device_private_parent(obj)  \
+       container_of(obj, struct device_private, knode_parent)
+#define to_device_private_driver(obj)  \
+       container_of(obj, struct device_private, knode_driver)
+#define to_device_private_bus(obj)     \
+       container_of(obj, struct device_private, knode_bus)
+
 /* initialisation functions */
 extern int devices_init(void);
 extern int buses_init(void);
@@ -86,6 +112,11 @@ extern void bus_remove_driver(struct device_driver *drv);
 
 extern void driver_detach(struct device_driver *drv);
 extern int driver_probe_device(struct device_driver *drv, struct device *dev);
+static inline int driver_match_device(struct device_driver *drv,
+                                     struct device *dev)
+{
+       return drv->bus->match && drv->bus->match(dev, drv);
+}
 
 extern void sysdev_shutdown(void);
 
index 83f32b891fa95db9156680a6275cc87ad9620e81..dc030f1f00f19706a4c5e5d0a077a085b0885187 100644 (file)
@@ -198,7 +198,7 @@ static ssize_t driver_bind(struct device_driver *drv,
        int err = -ENODEV;
 
        dev = bus_find_device_by_name(bus, NULL, buf);
-       if (dev && dev->driver == NULL) {
+       if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
                if (dev->parent)        /* Needed for USB */
                        down(&dev->parent->sem);
                down(&dev->sem);
@@ -253,7 +253,14 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
-       return n ? container_of(n, struct device, knode_bus) : NULL;
+       struct device *dev = NULL;
+       struct device_private *dev_prv;
+
+       if (n) {
+               dev_prv = to_device_private_bus(n);
+               dev = dev_prv->device;
+       }
+       return dev;
 }
 
 /**
@@ -286,7 +293,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
                return -EINVAL;
 
        klist_iter_init_node(&bus->p->klist_devices, &i,
-                            (start ? &start->knode_bus : NULL));
+                            (start ? &start->p->knode_bus : NULL));
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
        klist_iter_exit(&i);
@@ -320,7 +327,7 @@ struct device *bus_find_device(struct bus_type *bus,
                return NULL;
 
        klist_iter_init_node(&bus->p->klist_devices, &i,
-                            (start ? &start->knode_bus : NULL));
+                            (start ? &start->p->knode_bus : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
                        break;
@@ -507,7 +514,8 @@ void bus_attach_device(struct device *dev)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
-                       klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
+                       klist_add_tail(&dev->p->knode_bus,
+                                      &bus->p->klist_devices);
        }
 }
 
@@ -528,8 +536,8 @@ void bus_remove_device(struct device *dev)
                sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
                                  dev_name(dev));
                device_remove_attrs(dev->bus, dev);
-               if (klist_node_attached(&dev->knode_bus))
-                       klist_del(&dev->knode_bus);
+               if (klist_node_attached(&dev->p->knode_bus))
+                       klist_del(&dev->p->knode_bus);
 
                pr_debug("bus: '%s': remove device %s\n",
                         dev->bus->name, dev_name(dev));
@@ -831,14 +839,16 @@ static void bus_remove_attrs(struct bus_type *bus)
 
 static void klist_devices_get(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_bus);
+       struct device_private *dev_prv = to_device_private_bus(n);
+       struct device *dev = dev_prv->device;
 
        get_device(dev);
 }
 
 static void klist_devices_put(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_bus);
+       struct device_private *dev_prv = to_device_private_bus(n);
+       struct device *dev = dev_prv->device;
 
        put_device(dev);
 }
@@ -932,6 +942,7 @@ bus_uevent_fail:
        kset_unregister(&bus->p->subsys);
        kfree(bus->p);
 out:
+       bus->p = NULL;
        return retval;
 }
 EXPORT_SYMBOL_GPL(bus_register);
@@ -953,6 +964,7 @@ void bus_unregister(struct bus_type *bus)
        bus_remove_file(bus, &bus_attr_uevent);
        kset_unregister(&bus->p->subsys);
        kfree(bus->p);
+       bus->p = NULL;
 }
 EXPORT_SYMBOL_GPL(bus_unregister);
 
@@ -993,18 +1005,20 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list
 {
        struct list_head *pos;
        struct klist_node *n;
+       struct device_private *dev_prv;
        struct device *b;
 
        list_for_each(pos, list) {
                n = container_of(pos, struct klist_node, n_node);
-               b = container_of(n, struct device, knode_bus);
+               dev_prv = to_device_private_bus(n);
+               b = dev_prv->device;
                if (compare(a, b) <= 0) {
-                       list_move_tail(&a->knode_bus.n_node,
-                                      &b->knode_bus.n_node);
+                       list_move_tail(&a->p->knode_bus.n_node,
+                                      &b->p->knode_bus.n_node);
                        return;
                }
        }
-       list_move_tail(&a->knode_bus.n_node, list);
+       list_move_tail(&a->p->knode_bus.n_node, list);
 }
 
 void bus_sort_breadthfirst(struct bus_type *bus,
@@ -1014,6 +1028,7 @@ void bus_sort_breadthfirst(struct bus_type *bus,
        LIST_HEAD(sorted_devices);
        struct list_head *pos, *tmp;
        struct klist_node *n;
+       struct device_private *dev_prv;
        struct device *dev;
        struct klist *device_klist;
 
@@ -1022,7 +1037,8 @@ void bus_sort_breadthfirst(struct bus_type *bus,
        spin_lock(&device_klist->k_lock);
        list_for_each_safe(pos, tmp, &device_klist->k_list) {
                n = container_of(pos, struct klist_node, n_node);
-               dev = container_of(n, struct device, knode_bus);
+               dev_prv = to_device_private_bus(n);
+               dev = dev_prv->device;
                device_insertion_sort_klist(dev, &sorted_devices, compare);
        }
        list_splice(&sorted_devices, &device_klist->k_list);
index f3eae630e5899707e485396b3d427255ef9964d1..e73c92d13a23dfcd0e5ead18322584de1bb3a154 100644 (file)
@@ -109,6 +109,7 @@ static struct sysfs_ops dev_sysfs_ops = {
 static void device_release(struct kobject *kobj)
 {
        struct device *dev = to_dev(kobj);
+       struct device_private *p = dev->p;
 
        if (dev->release)
                dev->release(dev);
@@ -120,6 +121,7 @@ static void device_release(struct kobject *kobj)
                WARN(1, KERN_ERR "Device '%s' does not have a release() "
                        "function, it is broken and must be fixed.\n",
                        dev_name(dev));
+       kfree(p);
 }
 
 static struct kobj_type device_ktype = {
@@ -134,8 +136,6 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
 
        if (ktype == &device_ktype) {
                struct device *dev = to_dev(kobj);
-               if (dev->uevent_suppress)
-                       return 0;
                if (dev->bus)
                        return 1;
                if (dev->class)
@@ -507,14 +507,16 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
 
 static void klist_children_get(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_parent);
+       struct device_private *p = to_device_private_parent(n);
+       struct device *dev = p->device;
 
        get_device(dev);
 }
 
 static void klist_children_put(struct klist_node *n)
 {
-       struct device *dev = container_of(n, struct device, knode_parent);
+       struct device_private *p = to_device_private_parent(n);
+       struct device *dev = p->device;
 
        put_device(dev);
 }
@@ -538,8 +540,6 @@ void device_initialize(struct device *dev)
 {
        dev->kobj.kset = devices_kset;
        kobject_init(&dev->kobj, &device_ktype);
-       klist_init(&dev->klist_children, klist_children_get,
-                  klist_children_put);
        INIT_LIST_HEAD(&dev->dma_pools);
        init_MUTEX(&dev->sem);
        spin_lock_init(&dev->devres_lock);
@@ -777,17 +777,12 @@ static void device_remove_class_symlinks(struct device *dev)
 int dev_set_name(struct device *dev, const char *fmt, ...)
 {
        va_list vargs;
-       char *s;
+       int err;
 
        va_start(vargs, fmt);
-       vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs);
+       err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
        va_end(vargs);
-
-       /* ewww... some of these buggers have / in the name... */
-       while ((s = strchr(dev->bus_id, '/')))
-               *s = '!';
-
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(dev_set_name);
 
@@ -864,12 +859,26 @@ int device_add(struct device *dev)
        if (!dev)
                goto done;
 
-       /* Temporarily support init_name if it is set.
-        * It will override bus_id for now */
-       if (dev->init_name)
-               dev_set_name(dev, "%s", dev->init_name);
+       dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
+       if (!dev->p) {
+               error = -ENOMEM;
+               goto done;
+       }
+       dev->p->device = dev;
+       klist_init(&dev->p->klist_children, klist_children_get,
+                  klist_children_put);
+
+       /*
+        * for statically allocated devices, which should all be converted
+        * some day, we need to initialize the name. We prevent reading back
+        * the name, and force the use of dev_name()
+        */
+       if (dev->init_name) {
+               dev_set_name(dev, dev->init_name);
+               dev->init_name = NULL;
+       }
 
-       if (!strlen(dev->bus_id))
+       if (!dev_name(dev))
                goto done;
 
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
@@ -928,7 +937,8 @@ int device_add(struct device *dev)
        kobject_uevent(&dev->kobj, KOBJ_ADD);
        bus_attach_device(dev);
        if (parent)
-               klist_add_tail(&dev->knode_parent, &parent->klist_children);
+               klist_add_tail(&dev->p->knode_parent,
+                              &parent->p->klist_children);
 
        if (dev->class) {
                mutex_lock(&dev->class->p->class_mutex);
@@ -1042,7 +1052,7 @@ void device_del(struct device *dev)
        device_pm_remove(dev);
        dpm_sysfs_remove(dev);
        if (parent)
-               klist_del(&dev->knode_parent);
+               klist_del(&dev->p->knode_parent);
        if (MAJOR(dev->devt)) {
                device_remove_sys_dev_entry(dev);
                device_remove_file(dev, &devt_attr);
@@ -1103,7 +1113,14 @@ void device_unregister(struct device *dev)
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
-       return n ? container_of(n, struct device, knode_parent) : NULL;
+       struct device *dev = NULL;
+       struct device_private *p;
+
+       if (n) {
+               p = to_device_private_parent(n);
+               dev = p->device;
+       }
+       return dev;
 }
 
 /**
@@ -1125,7 +1142,7 @@ int device_for_each_child(struct device *parent, void *data,
        struct device *child;
        int error = 0;
 
-       klist_iter_init(&parent->klist_children, &i);
+       klist_iter_init(&parent->p->klist_children, &i);
        while ((child = next_device(&i)) && !error)
                error = fn(child, data);
        klist_iter_exit(&i);
@@ -1156,7 +1173,7 @@ struct device *device_find_child(struct device *parent, void *data,
        if (!parent)
                return NULL;
 
-       klist_iter_init(&parent->klist_children, &i);
+       klist_iter_init(&parent->p->klist_children, &i);
        while ((child = next_device(&i)))
                if (match(child, data) && get_device(child))
                        break;
@@ -1348,7 +1365,10 @@ struct device *device_create_vargs(struct class *class, struct device *parent,
        dev->release = device_create_release;
        dev_set_drvdata(dev, drvdata);
 
-       vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
+       retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
+       if (retval)
+               goto error;
+
        retval = device_register(dev);
        if (retval)
                goto error;
@@ -1452,19 +1472,15 @@ int device_rename(struct device *dev, char *new_name)
                old_class_name = make_class_name(dev->class->name, &dev->kobj);
 #endif
 
-       old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+       old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
        if (!old_device_name) {
                error = -ENOMEM;
                goto out;
        }
-       strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
-       strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
        error = kobject_rename(&dev->kobj, new_name);
-       if (error) {
-               strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+       if (error)
                goto out;
-       }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
        if (old_class_name) {
@@ -1545,8 +1561,10 @@ out:
  * device_move - moves a device to a new parent
  * @dev: the pointer to the struct device to be moved
  * @new_parent: the new parent of the device (can by NULL)
+ * @dpm_order: how to reorder the dpm_list
  */
-int device_move(struct device *dev, struct device *new_parent)
+int device_move(struct device *dev, struct device *new_parent,
+               enum dpm_order dpm_order)
 {
        int error;
        struct device *old_parent;
@@ -1556,6 +1574,7 @@ int device_move(struct device *dev, struct device *new_parent)
        if (!dev)
                return -EINVAL;
 
+       device_pm_lock();
        new_parent = get_device(new_parent);
        new_parent_kobj = get_device_parent(dev, new_parent);
 
@@ -1570,9 +1589,10 @@ int device_move(struct device *dev, struct device *new_parent)
        old_parent = dev->parent;
        dev->parent = new_parent;
        if (old_parent)
-               klist_remove(&dev->knode_parent);
+               klist_remove(&dev->p->knode_parent);
        if (new_parent) {
-               klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+               klist_add_tail(&dev->p->knode_parent,
+                              &new_parent->p->klist_children);
                set_dev_node(dev, dev_to_node(new_parent));
        }
 
@@ -1584,11 +1604,11 @@ int device_move(struct device *dev, struct device *new_parent)
                device_move_class_links(dev, new_parent, old_parent);
                if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
                        if (new_parent)
-                               klist_remove(&dev->knode_parent);
+                               klist_remove(&dev->p->knode_parent);
                        dev->parent = old_parent;
                        if (old_parent) {
-                               klist_add_tail(&dev->knode_parent,
-                                              &old_parent->klist_children);
+                               klist_add_tail(&dev->p->knode_parent,
+                                              &old_parent->p->klist_children);
                                set_dev_node(dev, dev_to_node(old_parent));
                        }
                }
@@ -1596,9 +1616,23 @@ int device_move(struct device *dev, struct device *new_parent)
                put_device(new_parent);
                goto out;
        }
+       switch (dpm_order) {
+       case DPM_ORDER_NONE:
+               break;
+       case DPM_ORDER_DEV_AFTER_PARENT:
+               device_pm_move_after(dev, new_parent);
+               break;
+       case DPM_ORDER_PARENT_BEFORE_DEV:
+               device_pm_move_before(new_parent, dev);
+               break;
+       case DPM_ORDER_DEV_LAST:
+               device_pm_move_last(dev);
+               break;
+       }
 out_put:
        put_device(old_parent);
 out:
+       device_pm_unlock();
        put_device(dev);
        return error;
 }
index 1352312391032fcda76f672c5b43a76e5c6df6f0..f17c3266a0e045f963eabebbc3009df5e356839b 100644 (file)
@@ -30,7 +30,7 @@
 
 static void driver_bound(struct device *dev)
 {
-       if (klist_node_attached(&dev->knode_driver)) {
+       if (klist_node_attached(&dev->p->knode_driver)) {
                printk(KERN_WARNING "%s: device %s already bound\n",
                        __func__, kobject_name(&dev->kobj));
                return;
@@ -43,7 +43,7 @@ static void driver_bound(struct device *dev)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_BOUND_DRIVER, dev);
 
-       klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
+       klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
 }
 
 static int driver_sysfs_add(struct device *dev)
@@ -172,16 +172,12 @@ int driver_probe_done(void)
 /**
  * wait_for_device_probe
  * Wait for device probing to be completed.
- *
- * Note: this function polls at 100 msec intervals.
  */
-int wait_for_device_probe(void)
+void wait_for_device_probe(void)
 {
        /* wait for the known devices to complete their probing */
-       while (driver_probe_done() != 0)
-               msleep(100);
+       wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
        async_synchronize_full();
-       return 0;
 }
 
 /**
@@ -189,14 +185,8 @@ int wait_for_device_probe(void)
  * @drv: driver to bind a device to
  * @dev: device to try to bind to the driver
  *
- * First, we call the bus's match function, if one present, which should
- * compare the device IDs the driver supports with the device IDs of the
- * device. Note we don't do this ourselves because we don't know the
- * format of the ID structures, nor what is to be considered a match and
- * what is not.
- *
- * This function returns 1 if a match is found, -ENODEV if the device is
- * not registered, and 0 otherwise.
+ * This function returns -ENODEV if the device is not registered,
+ * 1 if the device is bound sucessfully 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.
@@ -207,21 +197,22 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
 
        if (!device_is_registered(dev))
                return -ENODEV;
-       if (drv->bus->match && !drv->bus->match(dev, drv))
-               goto done;
 
        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
                 drv->bus->name, __func__, dev_name(dev), drv->name);
 
        ret = really_probe(dev, drv);
 
-done:
        return ret;
 }
 
 static int __device_attach(struct device_driver *drv, void *data)
 {
        struct device *dev = data;
+
+       if (!driver_match_device(drv, dev))
+               return 0;
+
        return driver_probe_device(drv, dev);
 }
 
@@ -274,7 +265,7 @@ static int __driver_attach(struct device *dev, void *data)
         * is an error.
         */
 
-       if (drv->bus->match && !drv->bus->match(dev, drv))
+       if (!driver_match_device(drv, dev))
                return 0;
 
        if (dev->parent)        /* Needed for USB */
@@ -327,7 +318,7 @@ static void __device_release_driver(struct device *dev)
                        drv->remove(dev);
                devres_release_all(dev);
                dev->driver = NULL;
-               klist_remove(&dev->knode_driver);
+               klist_remove(&dev->p->knode_driver);
        }
 }
 
@@ -357,6 +348,7 @@ EXPORT_SYMBOL_GPL(device_release_driver);
  */
 void driver_detach(struct device_driver *drv)
 {
+       struct device_private *dev_prv;
        struct device *dev;
 
        for (;;) {
@@ -365,8 +357,10 @@ void driver_detach(struct device_driver *drv)
                        spin_unlock(&drv->p->klist_devices.k_lock);
                        break;
                }
-               dev = list_entry(drv->p->klist_devices.k_list.prev,
-                               struct device, knode_driver.n_node);
+               dev_prv = list_entry(drv->p->klist_devices.k_list.prev,
+                                    struct device_private,
+                                    knode_driver.n_node);
+               dev = dev_prv->device;
                get_device(dev);
                spin_unlock(&drv->p->klist_devices.k_lock);
 
index 1e2bda780e48268eb38b834f7078644689b5dc7b..c51f11bb29ae2bdd0a13077147e6db357da8be27 100644 (file)
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
-       return n ? container_of(n, struct device, knode_driver) : NULL;
+       struct device *dev = NULL;
+       struct device_private *dev_prv;
+
+       if (n) {
+               dev_prv = to_device_private_driver(n);
+               dev = dev_prv->device;
+       }
+       return dev;
 }
 
 /**
@@ -42,7 +49,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start,
                return -EINVAL;
 
        klist_iter_init_node(&drv->p->klist_devices, &i,
-                            start ? &start->knode_driver : NULL);
+                            start ? &start->p->knode_driver : NULL);
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
        klist_iter_exit(&i);
@@ -76,7 +83,7 @@ struct device *driver_find_device(struct device_driver *drv,
                return NULL;
 
        klist_iter_init_node(&drv->p->klist_devices, &i,
-                            (start ? &start->knode_driver : NULL));
+                            (start ? &start->p->knode_driver : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
                        break;
@@ -216,6 +223,8 @@ int driver_register(struct device_driver *drv)
        int ret;
        struct device_driver *other;
 
+       BUG_ON(!drv->bus->p);
+
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
index 44699d9dd85c8de9c81d5aa1bc7807d69b370103..d3a59c688fe4fcaf0f7ebf514f44f59a08e90693 100644 (file)
@@ -319,7 +319,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        f_dev->parent = device;
        f_dev->class = &firmware_class;
        dev_set_drvdata(f_dev, fw_priv);
-       f_dev->uevent_suppress = 1;
+       dev_set_uevent_suppress(f_dev, 1);
        retval = device_register(f_dev);
        if (retval) {
                dev_err(device, "%s: device_register failed\n", __func__);
@@ -366,7 +366,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
        }
 
        if (uevent)
-               f_dev->uevent_suppress = 0;
+               dev_set_uevent_suppress(f_dev, 0);
        *dev_p = f_dev;
        goto out;
 
index 349a1013603fdb2485b3d82b2454ad1c3b2b3002..d2198f64ad4e3d8acccf61599b32fa620b916175 100644 (file)
@@ -217,6 +217,7 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
        if (d) {
                memcpy(d, data, size);
                pdev->dev.platform_data = d;
+               pdev->platform_data = d;
        }
        return d ? 0 : -ENOMEM;
 }
@@ -246,6 +247,21 @@ int platform_device_add(struct platform_device *pdev)
        else
                dev_set_name(&pdev->dev, pdev->name);
 
+       /* We will remove platform_data field from struct device
+       * if all platform devices pass its platform specific data
+       * from platform_device. The conversion is going to be a
+       * long time, so we allow the two cases coexist to make
+       * this kind of fix more easily*/
+       if (pdev->platform_data && pdev->dev.platform_data) {
+               printk(KERN_ERR
+                              "%s: use which platform_data?\n",
+                              dev_name(&pdev->dev));
+       } else if (pdev->platform_data) {
+               pdev->dev.platform_data = pdev->platform_data;
+       } else if (pdev->dev.platform_data) {
+               pdev->platform_data = pdev->dev.platform_data;
+       }
+
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource[i];
 
@@ -584,10 +600,25 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct platform_device  *pdev = to_platform_device(dev);
 
-       add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
+       add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
+               (pdev->id_entry) ? pdev->id_entry->name : pdev->name);
        return 0;
 }
 
+static const struct platform_device_id *platform_match_id(
+                       struct platform_device_id *id,
+                       struct platform_device *pdev)
+{
+       while (id->name[0]) {
+               if (strcmp(pdev->name, id->name) == 0) {
+                       pdev->id_entry = id;
+                       return id;
+               }
+               id++;
+       }
+       return NULL;
+}
+
 /**
  * platform_match - bind platform device to platform driver.
  * @dev: device.
@@ -603,9 +634,14 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
  */
 static int platform_match(struct device *dev, struct device_driver *drv)
 {
-       struct platform_device *pdev;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct platform_driver *pdrv = to_platform_driver(drv);
 
-       pdev = container_of(dev, struct platform_device, dev);
+       /* match against the id table first */
+       if (pdrv->id_table)
+               return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+       /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);
 }
 
@@ -623,26 +659,24 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
 
 static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
 {
-       struct platform_driver *drv = to_platform_driver(dev->driver);
-       struct platform_device *pdev;
+       struct platform_driver *pdrv = to_platform_driver(dev->driver);
+       struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       pdev = container_of(dev, struct platform_device, dev);
-       if (dev->driver && drv->suspend_late)
-               ret = drv->suspend_late(pdev, mesg);
+       if (dev->driver && pdrv->suspend_late)
+               ret = pdrv->suspend_late(pdev, mesg);
 
        return ret;
 }
 
 static int platform_legacy_resume_early(struct device *dev)
 {
-       struct platform_driver *drv = to_platform_driver(dev->driver);
-       struct platform_device *pdev;
+       struct platform_driver *pdrv = to_platform_driver(dev->driver);
+       struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       pdev = container_of(dev, struct platform_device, dev);
-       if (dev->driver && drv->resume_early)
-               ret = drv->resume_early(pdev);
+       if (dev->driver && pdrv->resume_early)
+               ret = pdrv->resume_early(pdev);
 
        return ret;
 }
index 2d14f4ae6c01da28be636629db5e50b9205b5699..e255341682c88d4a0955f1151595c1334e005dd5 100644 (file)
@@ -106,6 +106,50 @@ void device_pm_remove(struct device *dev)
        mutex_unlock(&dpm_list_mtx);
 }
 
+/**
+ *     device_pm_move_before - move device in dpm_list
+ *     @deva:  Device to move in dpm_list
+ *     @devb:  Device @deva should come before
+ */
+void device_pm_move_before(struct device *deva, struct device *devb)
+{
+       pr_debug("PM: Moving %s:%s before %s:%s\n",
+                deva->bus ? deva->bus->name : "No Bus",
+                kobject_name(&deva->kobj),
+                devb->bus ? devb->bus->name : "No Bus",
+                kobject_name(&devb->kobj));
+       /* Delete deva from dpm_list and reinsert before devb. */
+       list_move_tail(&deva->power.entry, &devb->power.entry);
+}
+
+/**
+ *     device_pm_move_after - move device in dpm_list
+ *     @deva:  Device to move in dpm_list
+ *     @devb:  Device @deva should come after
+ */
+void device_pm_move_after(struct device *deva, struct device *devb)
+{
+       pr_debug("PM: Moving %s:%s after %s:%s\n",
+                deva->bus ? deva->bus->name : "No Bus",
+                kobject_name(&deva->kobj),
+                devb->bus ? devb->bus->name : "No Bus",
+                kobject_name(&devb->kobj));
+       /* Delete deva from dpm_list and reinsert after devb. */
+       list_move(&deva->power.entry, &devb->power.entry);
+}
+
+/**
+ *     device_pm_move_last - move device to end of dpm_list
+ *     @dev:   Device to move in dpm_list
+ */
+void device_pm_move_last(struct device *dev)
+{
+       pr_debug("PM: Moving %s:%s to end of list\n",
+                dev->bus ? dev->bus->name : "No Bus",
+                kobject_name(&dev->kobj));
+       list_move_tail(&dev->power.entry, &dpm_list);
+}
+
 /**
  *     pm_op - execute the PM operation appropiate for given PM event
  *     @dev:   Device.
index 41f51fae042f06f06d7548f4ad10463b7b399f4f..c7cb4fc3735c5594cdb26530c81d92fbcacaf438 100644 (file)
@@ -18,11 +18,19 @@ static inline struct device *to_device(struct list_head *entry)
 
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
+extern void device_pm_move_before(struct device *, struct device *);
+extern void device_pm_move_after(struct device *, struct device *);
+extern void device_pm_move_last(struct device *);
 
 #else /* CONFIG_PM_SLEEP */
 
 static inline void device_pm_add(struct device *dev) {}
 static inline void device_pm_remove(struct device *dev) {}
+static inline void device_pm_move_before(struct device *deva,
+                                        struct device *devb) {}
+static inline void device_pm_move_after(struct device *deva,
+                                       struct device *devb) {}
+static inline void device_pm_move_last(struct device *dev) {}
 
 #endif
 
index b428c8c4bc6464177ea32524341e85992346ce3b..cbd36cf59a0f2e2af74ddc9255f64380299a6666 100644 (file)
 
 
 static ssize_t
-sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
+sysdev_show(struct kobject *kobj, struct attribute *attr, char *buffer)
 {
-       struct sys_device * sysdev = to_sysdev(kobj);
-       struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+       struct sys_device *sysdev = to_sysdev(kobj);
+       struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
 
        if (sysdev_attr->show)
                return sysdev_attr->show(sysdev, sysdev_attr, buffer);
@@ -42,11 +42,11 @@ sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
 
 
 static ssize_t
-sysdev_store(struct kobject * kobj, struct attribute * attr,
-            const char * buffer, size_t count)
+sysdev_store(struct kobject *kobj, struct attribute *attr,
+            const char *buffer, size_t count)
 {
-       struct sys_device * sysdev = to_sysdev(kobj);
-       struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+       struct sys_device *sysdev = to_sysdev(kobj);
+       struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
 
        if (sysdev_attr->store)
                return sysdev_attr->store(sysdev, sysdev_attr, buffer, count);
@@ -63,13 +63,13 @@ static struct kobj_type ktype_sysdev = {
 };
 
 
-int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a)
+int sysdev_create_file(struct sys_device *s, struct sysdev_attribute *a)
 {
        return sysfs_create_file(&s->kobj, &a->attr);
 }
 
 
-void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
+void sysdev_remove_file(struct sys_device *s, struct sysdev_attribute *a)
 {
        sysfs_remove_file(&s->kobj, &a->attr);
 }
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(sysdev_remove_file);
 static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
                                 char *buffer)
 {
-       struct sysdev_class * class = to_sysdev_class(kobj);
+       struct sysdev_class *class = to_sysdev_class(kobj);
        struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
 
        if (class_attr->show)
@@ -95,8 +95,8 @@ static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
 static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
                                  const char *buffer, size_t count)
 {
-       struct sysdev_class * class = to_sysdev_class(kobj);
-       struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr);
+       struct sysdev_class *class = to_sysdev_class(kobj);
+       struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
 
        if (class_attr->store)
                return class_attr->store(class, buffer, count);
@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
 
 static struct kset *system_kset;
 
-int sysdev_class_register(struct sysdev_class * cls)
+int sysdev_class_register(struct sysdev_class *cls)
 {
        pr_debug("Registering sysdev class '%s'\n", cls->name);
 
@@ -141,7 +141,7 @@ int sysdev_class_register(struct sysdev_class * cls)
        return kset_register(&cls->kset);
 }
 
-void sysdev_class_unregister(struct sysdev_class * cls)
+void sysdev_class_unregister(struct sysdev_class *cls)
 {
        pr_debug("Unregistering sysdev class '%s'\n",
                 kobject_name(&cls->kset.kobj));
@@ -203,8 +203,8 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
  *     @cls:   Class driver belongs to.
  *     @drv:   Driver.
  */
-void sysdev_driver_unregister(struct sysdev_class * cls,
-                             struct sysdev_driver * drv)
+void sysdev_driver_unregister(struct sysdev_class *cls,
+                             struct sysdev_driver *drv)
 {
        mutex_lock(&sysdev_drivers_lock);
        list_del_init(&drv->entry);
@@ -229,10 +229,10 @@ EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
  *     @sysdev:        device in question
  *
  */
-int sysdev_register(struct sys_device * sysdev)
+int sysdev_register(struct sys_device *sysdev)
 {
        int error;
-       struct sysdev_class * cls = sysdev->cls;
+       struct sysdev_class *cls = sysdev->cls;
 
        if (!cls)
                return -EINVAL;
@@ -252,7 +252,7 @@ int sysdev_register(struct sys_device * sysdev)
                                     sysdev->id);
 
        if (!error) {
-               struct sysdev_driver * drv;
+               struct sysdev_driver *drv;
 
                pr_debug("Registering sys device '%s'\n",
                         kobject_name(&sysdev->kobj));
@@ -274,9 +274,9 @@ int sysdev_register(struct sys_device * sysdev)
        return error;
 }
 
-void sysdev_unregister(struct sys_device * sysdev)
+void sysdev_unregister(struct sys_device *sysdev)
 {
-       struct sysdev_driver * drv;
+       struct sysdev_driver *drv;
 
        mutex_lock(&sysdev_drivers_lock);
        list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
@@ -305,19 +305,19 @@ void sysdev_unregister(struct sys_device * sysdev)
  */
 void sysdev_shutdown(void)
 {
-       struct sysdev_class * cls;
+       struct sysdev_class *cls;
 
        pr_debug("Shutting Down System Devices\n");
 
        mutex_lock(&sysdev_drivers_lock);
        list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
-               struct sys_device * sysdev;
+               struct sys_device *sysdev;
 
                pr_debug("Shutting down type '%s':\n",
                         kobject_name(&cls->kset.kobj));
 
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver * drv;
+                       struct sysdev_driver *drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
                        /* Call auxillary drivers first */
@@ -364,7 +364,7 @@ static void __sysdev_resume(struct sys_device *dev)
  */
 int sysdev_suspend(pm_message_t state)
 {
-       struct sysdev_class * cls;
+       struct sysdev_class *cls;
        struct sys_device *sysdev, *err_dev;
        struct sysdev_driver *drv, *err_drv;
        int ret;
@@ -442,12 +442,12 @@ EXPORT_SYMBOL_GPL(sysdev_suspend);
  */
 int sysdev_resume(void)
 {
-       struct sysdev_class * cls;
+       struct sysdev_class *cls;
 
        pr_debug("Resuming System Devices\n");
 
        list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
-               struct sys_device * sysdev;
+               struct sys_device *sysdev;
 
                pr_debug("Resuming type '%s':\n",
                         kobject_name(&cls->kset.kobj));
index 83d8ed39433d058f70896057e52fc4d1e4dc99f3..c2c95e614506761a98ace446e02219203e5530dd 100644 (file)
@@ -4135,10 +4135,9 @@ static int have_no_fdc = -ENODEV;
 static ssize_t floppy_cmos_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct platform_device *p;
+       struct platform_device *p = to_platform_device(dev);
        int drive;
 
-       p = container_of(dev, struct platform_device,dev);
        drive = p->id;
        return sprintf(buf, "%X\n", UDP->cmos);
 }
index 8822eca58ffaca1b573f96a11c2f3949b61b93e1..5fab6470f4b2beabbdd353063946bd513ef07554 100644 (file)
@@ -20,6 +20,20 @@ config HW_RANDOM
 
          If unsure, say Y.
 
+config HW_RANDOM_TIMERIOMEM
+       tristate "Timer IOMEM HW Random Number Generator support"
+       depends on HW_RANDOM && HAS_IOMEM
+       ---help---
+         This driver provides kernel-side support for a generic Random
+         Number Generator used by reading a 'dumb' iomem address that
+         is to be read no faster than, for example, once a second;
+         the default FPGA bitstream on the TS-7800 has such functionality.
+
+         To compile this driver as a module, choose M here: the
+         module will be called timeriomem-rng.
+
+         If unsure, say Y.
+
 config HW_RANDOM_INTEL
        tristate "Intel HW Random Number Generator support"
        depends on HW_RANDOM && (X86 || IA64) && PCI
index b6effb7522c2997570d811414cc121b53779c0a9..e81d21a5f28fb443c370fe5b00bc1eee3be85abb 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_HW_RANDOM) += rng-core.o
 rng-core-y := core.o
+obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
new file mode 100644 (file)
index 0000000..10ad41b
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * drivers/char/hw_random/timeriomem-rng.c
+ *
+ * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk>
+ *
+ * Derived from drivers/char/hw_random/omap-rng.c
+ *   Copyright 2005 (c) MontaVista Software, Inc.
+ *   Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ *   This driver is useful for platforms that have an IO range that provides
+ *   periodic random data from a single IO memory address.  All the platform
+ *   has to do is provide the address and 'wait time' that new data becomes
+ *   available.
+ *
+ * TODO: add support for reading sizes other than 32bits and masking
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/timeriomem-rng.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+
+static struct timeriomem_rng_data *timeriomem_rng_data;
+
+static void timeriomem_rng_trigger(unsigned long);
+static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0);
+
+/*
+ * have data return 1, however return 0 if we have nothing
+ */
+static int timeriomem_rng_data_present(struct hwrng *rng, int wait)
+{
+       if (rng->priv == 0)
+               return 1;
+
+       if (!wait || timeriomem_rng_data->present)
+               return timeriomem_rng_data->present;
+
+       wait_for_completion(&timeriomem_rng_data->completion);
+
+       return 1;
+}
+
+static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       unsigned long cur;
+       s32 delay;
+
+       *data = readl(timeriomem_rng_data->address);
+
+       if (rng->priv != 0) {
+               cur = jiffies;
+
+               delay = cur - timeriomem_rng_timer.expires;
+               delay = rng->priv - (delay % rng->priv);
+
+               timeriomem_rng_timer.expires = cur + delay;
+               timeriomem_rng_data->present = 0;
+
+               init_completion(&timeriomem_rng_data->completion);
+               add_timer(&timeriomem_rng_timer);
+       }
+
+       return 4;
+}
+
+static void timeriomem_rng_trigger(unsigned long dummy)
+{
+       timeriomem_rng_data->present = 1;
+       complete(&timeriomem_rng_data->completion);
+}
+
+static struct hwrng timeriomem_rng_ops = {
+       .name           = "timeriomem",
+       .data_present   = timeriomem_rng_data_present,
+       .data_read      = timeriomem_rng_data_read,
+       .priv           = 0,
+};
+
+static int __init timeriomem_rng_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       timeriomem_rng_data = pdev->dev.platform_data;
+
+       if (timeriomem_rng_data->period != 0
+               && usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
+               timeriomem_rng_timer.expires = jiffies;
+
+               timeriomem_rng_ops.priv = usecs_to_jiffies(
+                                               timeriomem_rng_data->period);
+       }
+       timeriomem_rng_data->present = 1;
+
+       ret = hwrng_register(&timeriomem_rng_ops);
+       if (ret) {
+               dev_err(&pdev->dev, "problem registering\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
+                       timeriomem_rng_data->address,
+                       timeriomem_rng_data->period);
+
+       return 0;
+}
+
+static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
+{
+       del_timer_sync(&timeriomem_rng_timer);
+       hwrng_unregister(&timeriomem_rng_ops);
+
+       return 0;
+}
+
+static struct platform_driver timeriomem_rng_driver = {
+       .driver = {
+               .name           = "timeriomem_rng",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = timeriomem_rng_probe,
+       .remove         = __devexit_p(timeriomem_rng_remove),
+};
+
+static int __init timeriomem_rng_init(void)
+{
+       return platform_driver_register(&timeriomem_rng_driver);
+}
+
+static void __exit timeriomem_rng_exit(void)
+{
+       platform_driver_unregister(&timeriomem_rng_driver);
+}
+
+module_init(timeriomem_rng_init);
+module_exit(timeriomem_rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
+MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");
index 9c47dc48c9fd4526ac8e8972fb80c6b21ba2cae8..ccdd828adcef2711e2ed91a7c52f38b1a6dca844 100644 (file)
@@ -429,134 +429,148 @@ out:
 #define TPM_DIGEST_SIZE 20
 #define TPM_ERROR_SIZE 10
 #define TPM_RET_CODE_IDX 6
-#define TPM_GET_CAP_RET_SIZE_IDX 10
-#define TPM_GET_CAP_RET_UINT32_1_IDX 14
-#define TPM_GET_CAP_RET_UINT32_2_IDX 18
-#define TPM_GET_CAP_RET_UINT32_3_IDX 22
-#define TPM_GET_CAP_RET_UINT32_4_IDX 26
-#define TPM_GET_CAP_PERM_DISABLE_IDX 16
-#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
-#define TPM_GET_CAP_RET_BOOL_1_IDX 14
-#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16
-
-#define TPM_CAP_IDX 13
-#define TPM_CAP_SUBCAP_IDX 21
 
 enum tpm_capabilities {
-       TPM_CAP_FLAG = 4,
-       TPM_CAP_PROP = 5,
+       TPM_CAP_FLAG = cpu_to_be32(4),
+       TPM_CAP_PROP = cpu_to_be32(5),
+       CAP_VERSION_1_1 = cpu_to_be32(0x06),
+       CAP_VERSION_1_2 = cpu_to_be32(0x1A)
 };
 
 enum tpm_sub_capabilities {
-       TPM_CAP_PROP_PCR = 0x1,
-       TPM_CAP_PROP_MANUFACTURER = 0x3,
-       TPM_CAP_FLAG_PERM = 0x8,
-       TPM_CAP_FLAG_VOL = 0x9,
-       TPM_CAP_PROP_OWNER = 0x11,
-       TPM_CAP_PROP_TIS_TIMEOUT = 0x15,
-       TPM_CAP_PROP_TIS_DURATION = 0x20,
-};
+       TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
+       TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
+       TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
+       TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
+       TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
+       TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
+       TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
 
-/*
- * This is a semi generic GetCapability command for use
- * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
- * and their associated sub_capabilities.
- */
-
-static const u8 tpm_cap[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 22,            /* length */
-       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
-       0, 0, 0, 0,             /* TPM_CAP_<TYPE> */
-       0, 0, 0, 4,             /* TPM_CAP_SUB_<TYPE> size */
-       0, 0, 1, 0              /* TPM_CAP_SUB_<TYPE> */
 };
 
-static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len,
-                           char *desc)
+static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
+                           int len, const char *desc)
 {
        int err;
 
-       len = tpm_transmit(chip, data, len);
+       len = tpm_transmit(chip,(u8 *) cmd, len);
        if (len <  0)
                return len;
        if (len == TPM_ERROR_SIZE) {
-               err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
+               err = be32_to_cpu(cmd->header.out.return_code);
                dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
                return err;
        }
        return 0;
 }
 
+#define TPM_INTERNAL_RESULT_SIZE 200
+#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
+#define TPM_ORD_GET_CAP cpu_to_be32(101)
+
+static const struct tpm_input_header tpm_getcap_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(22),
+       .ordinal = TPM_ORD_GET_CAP
+};
+
+ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
+                  const char *desc)
+{
+       struct tpm_cmd_t tpm_cmd;
+       int rc;
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       tpm_cmd.header.in = tpm_getcap_header;
+       if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
+               tpm_cmd.params.getcap_in.cap = subcap_id;
+               /*subcap field not necessary */
+               tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
+               tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
+       } else {
+               if (subcap_id == TPM_CAP_FLAG_PERM ||
+                   subcap_id == TPM_CAP_FLAG_VOL)
+                       tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
+               else
+                       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+               tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+               tpm_cmd.params.getcap_in.subcap = subcap_id;
+       }
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+       if (!rc)
+               *cap = tpm_cmd.params.getcap_out.cap;
+       return rc;
+}
+
 void tpm_gen_interrupt(struct tpm_chip *chip)
 {
-       u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
+       struct  tpm_cmd_t tpm_cmd;
        ssize_t rc;
 
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+       tpm_cmd.header.in = tpm_getcap_header;
+       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+       tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+       tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-       rc = transmit_cmd(chip, data, sizeof(data),
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
                        "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
 void tpm_get_timeouts(struct tpm_chip *chip)
 {
-       u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
+       struct tpm_cmd_t tpm_cmd;
+       struct timeout_t *timeout_cap;
+       struct duration_t *duration_cap;
        ssize_t rc;
        u32 timeout;
 
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+       tpm_cmd.header.in = tpm_getcap_header;
+       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+       tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+       tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-       rc = transmit_cmd(chip, data, sizeof(data),
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
                        "attempting to determine the timeouts");
        if (rc)
                goto duration;
 
-       if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
+       if (be32_to_cpu(tpm_cmd.header.out.length)
            != 4 * sizeof(u32))
                goto duration;
 
+       timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
        /* Don't overwrite default if value is 0 */
-       timeout =
-           be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
+       timeout = be32_to_cpu(timeout_cap->a);
        if (timeout)
                chip->vendor.timeout_a = usecs_to_jiffies(timeout);
-       timeout =
-           be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
+       timeout = be32_to_cpu(timeout_cap->b);
        if (timeout)
                chip->vendor.timeout_b = usecs_to_jiffies(timeout);
-       timeout =
-           be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
+       timeout = be32_to_cpu(timeout_cap->c);
        if (timeout)
                chip->vendor.timeout_c = usecs_to_jiffies(timeout);
-       timeout =
-           be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
+       timeout = be32_to_cpu(timeout_cap->d);
        if (timeout)
                chip->vendor.timeout_d = usecs_to_jiffies(timeout);
 
 duration:
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
+       tpm_cmd.header.in = tpm_getcap_header;
+       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+       tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+       tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 
-       rc = transmit_cmd(chip, data, sizeof(data),
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
                        "attempting to determine the durations");
        if (rc)
                return;
 
-       if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
+       if (be32_to_cpu(tpm_cmd.header.out.return_code)
            != 3 * sizeof(u32))
                return;
-
+       duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
        chip->vendor.duration[TPM_SHORT] =
-           usecs_to_jiffies(be32_to_cpu
-                            (*((__be32 *) (data +
-                                           TPM_GET_CAP_RET_UINT32_1_IDX))));
+           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
         * value wrong and apparently reports msecs rather than usecs. So we
         * fix up the resulting too-small TPM_SHORT value to make things work.
@@ -565,13 +579,9 @@ duration:
                chip->vendor.duration[TPM_SHORT] = HZ;
 
        chip->vendor.duration[TPM_MEDIUM] =
-           usecs_to_jiffies(be32_to_cpu
-                            (*((__be32 *) (data +
-                                           TPM_GET_CAP_RET_UINT32_2_IDX))));
+           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
        chip->vendor.duration[TPM_LONG] =
-           usecs_to_jiffies(be32_to_cpu
-                            (*((__be32 *) (data +
-                                           TPM_GET_CAP_RET_UINT32_3_IDX))));
+           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
 }
 EXPORT_SYMBOL_GPL(tpm_get_timeouts);
 
@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_continue_selftest);
 
-#define  TPM_INTERNAL_RESULT_SIZE 200
-
 ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
                        char *buf)
 {
-       u8 *data;
+       cap_t cap;
        ssize_t rc;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_FLAG;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
-
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                       "attemtping to determine the permanent enabled state");
-       if (rc) {
-               kfree(data);
+       rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
+                        "attempting to determine the permanent enabled state");
+       if (rc)
                return 0;
-       }
-
-       rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
 
-       kfree(data);
+       rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_show_enabled);
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled);
 ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
                        char *buf)
 {
-       u8 *data;
+       cap_t cap;
        ssize_t rc;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_FLAG;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
-
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                       "attemtping to determine the permanent active state");
-       if (rc) {
-               kfree(data);
+       rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
+                        "attempting to determine the permanent active state");
+       if (rc)
                return 0;
-       }
 
-       rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);
-
-       kfree(data);
+       rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_show_active);
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active);
 ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
                        char *buf)
 {
-       u8 *data;
+       cap_t cap;
        ssize_t rc;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
-
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                       "attempting to determine the owner state");
-       if (rc) {
-               kfree(data);
+       rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
+                        "attempting to determine the owner state");
+       if (rc)
                return 0;
-       }
-
-       rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
 
-       kfree(data);
+       rc = sprintf(buf, "%d\n", cap.owned);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_show_owned);
@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned);
 ssize_t tpm_show_temp_deactivated(struct device * dev,
                                struct device_attribute * attr, char *buf)
 {
-       u8 *data;
+       cap_t cap;
        ssize_t rc;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
+       rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
+                        "attempting to determine the temporary state");
+       if (rc)
+               return 0;
 
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
+       rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
 
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_FLAG;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
+/*
+ * tpm_chip_find_get - return tpm_chip for given chip number
+ */
+static struct tpm_chip *tpm_chip_find_get(int chip_num)
+{
+       struct tpm_chip *pos, *chip = NULL;
 
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                       "attempting to determine the temporary state");
-       if (rc) {
-               kfree(data);
-               return 0;
+       rcu_read_lock();
+       list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+               if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
+                       continue;
+
+               if (try_module_get(pos->dev->driver->owner)) {
+                       chip = pos;
+                       break;
+               }
        }
+       rcu_read_unlock();
+       return chip;
+}
 
-       rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
+#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
+#define READ_PCR_RESULT_SIZE 30
+static struct tpm_input_header pcrread_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(14),
+       .ordinal = TPM_ORDINAL_PCRREAD
+};
 
-       kfree(data);
+int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
+{
+       int rc;
+       struct tpm_cmd_t cmd;
+
+       cmd.header.in = pcrread_header;
+       cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
+       BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
+       rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
+                         "attempting to read a pcr value");
+
+       if (rc == 0)
+               memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
+                      TPM_DIGEST_SIZE);
        return rc;
 }
-EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
 
-static const u8 pcrread[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 14,            /* length */
-       0, 0, 0, 21,            /* TPM_ORD_PcrRead */
-       0, 0, 0, 0              /* PCR index */
+/**
+ * tpm_pcr_read - read a pcr value
+ * @chip_num:  tpm idx # or ANY
+ * @pcr_idx:   pcr idx to retrieve
+ * @res_buf:   TPM_PCR value
+ *             size of res_buf is 20 bytes (or NULL if you don't care)
+ *
+ * The TPM driver should be built-in, but for whatever reason it
+ * isn't, protect against the chip disappearing, by incrementing
+ * the module usage count.
+ */
+int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
+{
+       struct tpm_chip *chip;
+       int rc;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL)
+               return -ENODEV;
+       rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
+       module_put(chip->dev->driver->owner);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_read);
+
+/**
+ * tpm_pcr_extend - extend pcr value with hash
+ * @chip_num:  tpm idx # or AN&
+ * @pcr_idx:   pcr idx to extend
+ * @hash:      hash value used to extend pcr value
+ *
+ * The TPM driver should be built-in, but for whatever reason it
+ * isn't, protect against the chip disappearing, by incrementing
+ * the module usage count.
+ */
+#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
+#define EXTEND_PCR_SIZE 34
+static struct tpm_input_header pcrextend_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(34),
+       .ordinal = TPM_ORD_PCR_EXTEND
 };
 
+int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
+{
+       struct tpm_cmd_t cmd;
+       int rc;
+       struct tpm_chip *chip;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL)
+               return -ENODEV;
+
+       cmd.header.in = pcrextend_header;
+       BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE);
+       cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
+       memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
+       rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
+                         "attempting extend a PCR value");
+
+       module_put(chip->dev->driver->owner);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_pcr_extend);
+
 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
                      char *buf)
 {
-       u8 *data;
+       cap_t cap;
+       u8 digest[TPM_DIGEST_SIZE];
        ssize_t rc;
        int i, j, num_pcrs;
-       __be32 index;
        char *str = buf;
-
        struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
 
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
-
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+       rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
                        "attempting to determine the number of PCRS");
-       if (rc) {
-               kfree(data);
+       if (rc)
                return 0;
-       }
 
-       num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
+       num_pcrs = be32_to_cpu(cap.num_pcrs);
        for (i = 0; i < num_pcrs; i++) {
-               memcpy(data, pcrread, sizeof(pcrread));
-               index = cpu_to_be32(i);
-               memcpy(data + 10, &index, 4);
-               rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                               "attempting to read a PCR");
+               rc = __tpm_pcr_read(chip, i, digest);
                if (rc)
-                       goto out;
+                       break;
                str += sprintf(str, "PCR-%02d: ", i);
                for (j = 0; j < TPM_DIGEST_SIZE; j++)
-                       str += sprintf(str, "%02X ", *(data + 10 + j));
+                       str += sprintf(str, "%02X ", digest[j]);
                str += sprintf(str, "\n");
        }
-out:
-       kfree(data);
        return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
 
 #define  READ_PUBEK_RESULT_SIZE 314
-static const u8 readpubek[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 30,            /* length */
-       0, 0, 0, 124,           /* TPM_ORD_ReadPubek */
+#define TPM_ORD_READPUBEK cpu_to_be32(124)
+struct tpm_input_header tpm_readpubek_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(30),
+       .ordinal = TPM_ORD_READPUBEK
 };
 
 ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
                       char *buf)
 {
        u8 *data;
+       struct tpm_cmd_t tpm_cmd;
        ssize_t err;
        int i, rc;
        char *str = buf;
 
        struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
 
-       data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, readpubek, sizeof(readpubek));
-
-       err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
+       tpm_cmd.header.in = tpm_readpubek_header;
+       err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
                        "attempting to read the PUBEK");
        if (err)
                goto out;
@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
           256 byte modulus
           ignore checksum 20 bytes
         */
-
+       data = tpm_cmd.params.readpubek_out_buffer;
        str +=
            sprintf(str,
                    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
        }
 out:
        rc = str - buf;
-       kfree(data);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_show_pubek);
 
-#define CAP_VERSION_1_1 6
-#define CAP_VERSION_1_2 0x1A
-#define CAP_VERSION_IDX 13
-static const u8 cap_version[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 18,            /* length */
-       0, 0, 0, 101,           /* TPM_ORD_GetCapability */
-       0, 0, 0, 0,
-       0, 0, 0, 0
-};
 
 ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
                      char *buf)
 {
-       u8 *data;
+       cap_t cap;
        ssize_t rc;
        char *str = buf;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
-
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
+       rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
                        "attempting to determine the manufacturer");
-       if (rc) {
-               kfree(data);
+       if (rc)
                return 0;
-       }
-
        str += sprintf(str, "Manufacturer: 0x%x\n",
-                      be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+                      be32_to_cpu(cap.manufacturer_id));
 
-       memcpy(data, cap_version, sizeof(cap_version));
-       data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
-       rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
-                       "attempting to determine the 1.1 version");
+       rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
+                       "attempting to determine the 1.1 version");
        if (rc)
-               goto out;
-
+               return 0;
        str += sprintf(str,
                       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-                      (int) data[14], (int) data[15], (int) data[16],
-                      (int) data[17]);
-
-out:
-       kfree(data);
+                      cap.tpm_version.Major, cap.tpm_version.Minor,
+                      cap.tpm_version.revMajor, cap.tpm_version.revMinor);
        return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps);
@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps);
 ssize_t tpm_show_caps_1_2(struct device * dev,
                          struct device_attribute * attr, char *buf)
 {
-       u8 *data;
-       ssize_t len;
+       cap_t cap;
+       ssize_t rc;
        char *str = buf;
 
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       if (chip == NULL)
-               return -ENODEV;
-
-       data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       memcpy(data, tpm_cap, sizeof(tpm_cap));
-       data[TPM_CAP_IDX] = TPM_CAP_PROP;
-       data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
-
-       len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
-       if (len <= TPM_ERROR_SIZE) {
-               dev_dbg(chip->dev, "A TPM error (%d) occurred "
-                       "attempting to determine the manufacturer\n",
-                       be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
-               kfree(data);
+       rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
+                       "attempting to determine the manufacturer");
+       if (rc)
                return 0;
-       }
-
        str += sprintf(str, "Manufacturer: 0x%x\n",
-                      be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
-
-       memcpy(data, cap_version, sizeof(cap_version));
-       data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
-
-       len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
-       if (len <= TPM_ERROR_SIZE) {
-               dev_err(chip->dev, "A TPM error (%d) occurred "
-                       "attempting to determine the 1.2 version\n",
-                       be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
-               goto out;
-       }
+                      be32_to_cpu(cap.manufacturer_id));
+       rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
+                        "attempting to determine the 1.2 version");
+       if (rc)
+               return 0;
        str += sprintf(str,
                       "TCG version: %d.%d\nFirmware version: %d.%d\n",
-                      (int) data[16], (int) data[17], (int) data[18],
-                      (int) data[19]);
-
-out:
-       kfree(data);
+                      cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
+                      cap.tpm_version_1_2.revMajor,
+                      cap.tpm_version_1_2.revMinor);
        return str - buf;
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
index 8e30df4a4388166343af7bfed2aadefdd4f809bc..8e00b4ddd0830699bca8bab65c3e855657b21978 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/tpm.h>
 
 enum tpm_timeout {
        TPM_TIMEOUT = 5,        /* msecs */
@@ -123,6 +124,147 @@ static inline void tpm_write_index(int base, int index, int value)
        outb(index, base);
        outb(value & 0xFF, base+1);
 }
+struct tpm_input_header {
+       __be16  tag;
+       __be32  length;
+       __be32  ordinal;
+}__attribute__((packed));
+
+struct tpm_output_header {
+       __be16  tag;
+       __be32  length;
+       __be32  return_code;
+}__attribute__((packed));
+
+struct stclear_flags_t {
+       __be16  tag;
+       u8      deactivated;
+       u8      disableForceClear;
+       u8      physicalPresence;
+       u8      physicalPresenceLock;
+       u8      bGlobalLock;
+}__attribute__((packed));
+
+struct tpm_version_t {
+       u8      Major;
+       u8      Minor;
+       u8      revMajor;
+       u8      revMinor;
+}__attribute__((packed));
+
+struct tpm_version_1_2_t {
+       __be16  tag;
+       u8      Major;
+       u8      Minor;
+       u8      revMajor;
+       u8      revMinor;
+}__attribute__((packed));
+
+struct timeout_t {
+       __be32  a;
+       __be32  b;
+       __be32  c;
+       __be32  d;
+}__attribute__((packed));
+
+struct duration_t {
+       __be32  tpm_short;
+       __be32  tpm_medium;
+       __be32  tpm_long;
+}__attribute__((packed));
+
+struct permanent_flags_t {
+       __be16  tag;
+       u8      disable;
+       u8      ownership;
+       u8      deactivated;
+       u8      readPubek;
+       u8      disableOwnerClear;
+       u8      allowMaintenance;
+       u8      physicalPresenceLifetimeLock;
+       u8      physicalPresenceHWEnable;
+       u8      physicalPresenceCMDEnable;
+       u8      CEKPUsed;
+       u8      TPMpost;
+       u8      TPMpostLock;
+       u8      FIPS;
+       u8      operator;
+       u8      enableRevokeEK;
+       u8      nvLocked;
+       u8      readSRKPub;
+       u8      tpmEstablished;
+       u8      maintenanceDone;
+       u8      disableFullDALogicInfo;
+}__attribute__((packed));
+
+typedef union {
+       struct  permanent_flags_t perm_flags;
+       struct  stclear_flags_t stclear_flags;
+       bool    owned;
+       __be32  num_pcrs;
+       struct  tpm_version_t   tpm_version;
+       struct  tpm_version_1_2_t tpm_version_1_2;
+       __be32  manufacturer_id;
+       struct timeout_t  timeout;
+       struct duration_t duration;
+} cap_t;
+
+struct tpm_getcap_params_in {
+       __be32  cap;
+       __be32  subcap_size;
+       __be32  subcap;
+}__attribute__((packed));
+
+struct tpm_getcap_params_out {
+       __be32  cap_size;
+       cap_t   cap;
+}__attribute__((packed));
+
+struct tpm_readpubek_params_out {
+       u8      algorithm[4];
+       u8      encscheme[2];
+       u8      sigscheme[2];
+       u8      parameters[12]; /*assuming RSA*/
+       __be32  keysize;
+       u8      modulus[256];
+       u8      checksum[20];
+}__attribute__((packed));
+
+typedef union {
+       struct  tpm_input_header in;
+       struct  tpm_output_header out;
+} tpm_cmd_header;
+
+#define TPM_DIGEST_SIZE 20
+struct tpm_pcrread_out {
+       u8      pcr_result[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+struct tpm_pcrread_in {
+       __be32  pcr_idx;
+}__attribute__((packed));
+
+struct tpm_pcrextend_in {
+       __be32  pcr_idx;
+       u8      hash[TPM_DIGEST_SIZE];
+}__attribute__((packed));
+
+typedef union {
+       struct  tpm_getcap_params_out getcap_out;
+       struct  tpm_readpubek_params_out readpubek_out;
+       u8      readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
+       struct  tpm_getcap_params_in getcap_in;
+       struct  tpm_pcrread_in  pcrread_in;
+       struct  tpm_pcrread_out pcrread_out;
+       struct  tpm_pcrextend_in pcrextend_in;
+} tpm_cmd_params;
+
+struct tpm_cmd_t {
+       tpm_cmd_header  header;
+       tpm_cmd_params  params;
+}__attribute__((packed));
+
+ssize_t        tpm_getcap(struct device *, __be32, cap_t *, const char *);
 
 extern void tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
index d0e7926eb4865d31b906fab70ef266c1dbf7bbdb..c64a1bc65349cc3959c488034fbfd892e7ac04cf 100644 (file)
@@ -168,12 +168,22 @@ static void atml_plat_remove(void)
        }
 }
 
-static struct device_driver atml_drv = {
-       .name = "tpm_atmel",
-       .bus = &platform_bus_type,
-       .owner = THIS_MODULE,
-       .suspend = tpm_pm_suspend,
-       .resume = tpm_pm_resume,
+static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_atml_resume(struct platform_device *dev)
+{
+       return tpm_pm_resume(&dev->dev);
+}
+static struct platform_driver atml_drv = {
+       .driver = {
+               .name = "tpm_atmel",
+               .owner          = THIS_MODULE,
+       },
+       .suspend = tpm_atml_suspend,
+       .resume = tpm_atml_resume,
 };
 
 static int __init init_atmel(void)
@@ -184,7 +194,7 @@ static int __init init_atmel(void)
        unsigned long base;
        struct  tpm_chip *chip;
 
-       rc = driver_register(&atml_drv);
+       rc = platform_driver_register(&atml_drv);
        if (rc)
                return rc;
 
@@ -223,13 +233,13 @@ err_rel_reg:
                atmel_release_region(base,
                                     region_size);
 err_unreg_drv:
-       driver_unregister(&atml_drv);
+       platform_driver_unregister(&atml_drv);
        return rc;
 }
 
 static void __exit cleanup_atmel(void)
 {
-       driver_unregister(&atml_drv);
+       platform_driver_unregister(&atml_drv);
        atml_plat_remove();
 }
 
index 717af7ad1bdf5ca28e784b350386182c086f9321..aec1931608aa28e3645463735c299805a50ab2b8 100644 (file)
@@ -654,12 +654,22 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
                    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 
-static struct device_driver tis_drv = {
-       .name = "tpm_tis",
-       .bus = &platform_bus_type,
-       .owner = THIS_MODULE,
-       .suspend = tpm_pm_suspend,
-       .resume = tpm_pm_resume,
+static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_tis_resume(struct platform_device *dev)
+{
+       return tpm_pm_resume(&dev->dev);
+}
+static struct platform_driver tis_drv = {
+       .driver = {
+               .name = "tpm_tis",
+               .owner          = THIS_MODULE,
+       },
+       .suspend = tpm_tis_suspend,
+       .resume = tpm_tis_resume,
 };
 
 static struct platform_device *pdev;
@@ -672,14 +682,14 @@ static int __init init_tis(void)
        int rc;
 
        if (force) {
-               rc = driver_register(&tis_drv);
+               rc = platform_driver_register(&tis_drv);
                if (rc < 0)
                        return rc;
                if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
                        return PTR_ERR(pdev);
                if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
                        platform_device_unregister(pdev);
-                       driver_unregister(&tis_drv);
+                       platform_driver_unregister(&tis_drv);
                }
                return rc;
        }
@@ -711,7 +721,7 @@ static void __exit cleanup_tis(void)
 
        if (force) {
                platform_device_unregister(pdev);
-               driver_unregister(&tis_drv);
+               platform_driver_unregister(&tis_drv);
        } else
                pnp_unregister_driver(&tis_pnp_driver);
 }
index 4f3b3f95fc42b4bb7bcf03a561aa5f69c48a393d..d94d25c12aa87ccacfe12d72ea5e72d4f3f4f93c 100644 (file)
@@ -479,18 +479,18 @@ static const struct file_operations vcs_fops = {
 
 static struct class *vc_class;
 
-void vcs_make_sysfs(struct tty_struct *tty)
+void vcs_make_sysfs(int index)
 {
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), NULL,
-                     "vcs%u", tty->index + 1);
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), NULL,
-                     "vcsa%u", tty->index + 1);
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
+                     "vcs%u", index + 1);
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
+                     "vcsa%u", index + 1);
 }
 
-void vcs_remove_sysfs(struct tty_struct *tty)
+void vcs_remove_sysfs(int index)
 {
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
 }
 
 int __init vcs_init(void)
index 7900bd63b36da74529eb76bf2923c165cf8d8a1f..2c1d133819b5e575e69928458bc292226eab8b59 100644 (file)
@@ -778,6 +778,7 @@ int vc_allocate(unsigned int currcons)      /* return 0 on success */
            }
            vc->vc_kmalloced = 1;
            vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+           vcs_make_sysfs(currcons);
            atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
        }
        return 0;
@@ -987,7 +988,9 @@ void vc_deallocate(unsigned int currcons)
        if (vc_cons_allocated(currcons)) {
                struct vc_data *vc = vc_cons[currcons].d;
                struct vt_notifier_param param = { .vc = vc };
+
                atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
+               vcs_remove_sysfs(currcons);
                vc->vc_sw->con_deinit(vc);
                put_pid(vc->vt_pid);
                module_put(vc->vc_sw->owner);
@@ -2775,7 +2778,6 @@ static int con_open(struct tty_struct *tty, struct file *filp)
                                tty->termios->c_iflag |= IUTF8;
                        else
                                tty->termios->c_iflag &= ~IUTF8;
-                       vcs_make_sysfs(tty);
                        release_console_sem();
                        return ret;
                }
@@ -2795,7 +2797,6 @@ static void con_shutdown(struct tty_struct *tty)
        BUG_ON(vc == NULL);
        acquire_console_sem();
        vc->vc_tty = NULL;
-       vcs_remove_sysfs(tty);
        release_console_sem();
        tty_shutdown(tty);
 }
index 1525882190fdac24d6ce01eb50e3a31d3b5dbca3..1efb2879a94f48b30b3f100608328cd3a46b8bd9 100644 (file)
@@ -2,3 +2,4 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC)  += tcb_clksrc.o
 obj-$(CONFIG_X86_CYCLONE_TIMER)        += cyclone.o
 obj-$(CONFIG_X86_PM_TIMER)     += acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)   += scx200_hrt.o
+obj-$(CONFIG_SH_TIMER_CMT)     += sh_cmt.o
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
new file mode 100644 (file)
index 0000000..7783b42
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * SuperH Timer Support - CMT
+ *
+ *  Copyright (C) 2008 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/sh_cmt.h>
+
+struct sh_cmt_priv {
+       void __iomem *mapbase;
+       struct clk *clk;
+       unsigned long width; /* 16 or 32 bit version of hardware block */
+       unsigned long overflow_bit;
+       unsigned long clear_bits;
+       struct irqaction irqaction;
+       struct platform_device *pdev;
+
+       unsigned long flags;
+       unsigned long match_value;
+       unsigned long next_match_value;
+       unsigned long max_match_value;
+       unsigned long rate;
+       spinlock_t lock;
+       struct clock_event_device ced;
+       unsigned long total_cycles;
+};
+
+static DEFINE_SPINLOCK(sh_cmt_lock);
+
+#define CMSTR -1 /* shared register */
+#define CMCSR 0 /* channel register */
+#define CMCNT 1 /* channel register */
+#define CMCOR 2 /* channel register */
+
+static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == CMSTR) {
+               offs = 0;
+               base -= cfg->channel_offset;
+       } else
+               offs = reg_nr;
+
+       if (p->width == 16)
+               offs <<= 1;
+       else {
+               offs <<= 2;
+               if ((reg_nr == CMCNT) || (reg_nr == CMCOR))
+                       return ioread32(base + offs);
+       }
+
+       return ioread16(base + offs);
+}
+
+static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
+                               unsigned long value)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       void __iomem *base = p->mapbase;
+       unsigned long offs;
+
+       if (reg_nr == CMSTR) {
+               offs = 0;
+               base -= cfg->channel_offset;
+       } else
+               offs = reg_nr;
+
+       if (p->width == 16)
+               offs <<= 1;
+       else {
+               offs <<= 2;
+               if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) {
+                       iowrite32(value, base + offs);
+                       return;
+               }
+       }
+
+       iowrite16(value, base + offs);
+}
+
+static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
+                                       int *has_wrapped)
+{
+       unsigned long v1, v2, v3;
+
+       /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+       do {
+               v1 = sh_cmt_read(p, CMCNT);
+               v2 = sh_cmt_read(p, CMCNT);
+               v3 = sh_cmt_read(p, CMCNT);
+       } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+                         || (v3 > v1 && v3 < v2)));
+
+       *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+       return v2;
+}
+
+
+static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       unsigned long flags, value;
+
+       /* start stop register shared by multiple timer channels */
+       spin_lock_irqsave(&sh_cmt_lock, flags);
+       value = sh_cmt_read(p, CMSTR);
+
+       if (start)
+               value |= 1 << cfg->timer_bit;
+       else
+               value &= ~(1 << cfg->timer_bit);
+
+       sh_cmt_write(p, CMSTR, value);
+       spin_unlock_irqrestore(&sh_cmt_lock, flags);
+}
+
+static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
+{
+       struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
+       int ret;
+
+       /* enable clock */
+       ret = clk_enable(p->clk);
+       if (ret) {
+               pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
+               return ret;
+       }
+       *rate = clk_get_rate(p->clk) / 8;
+
+       /* make sure channel is disabled */
+       sh_cmt_start_stop_ch(p, 0);
+
+       /* configure channel, periodic mode and maximum timeout */
+       if (p->width == 16)
+               sh_cmt_write(p, CMCSR, 0);
+       else
+               sh_cmt_write(p, CMCSR, 0x01a4);
+
+       sh_cmt_write(p, CMCOR, 0xffffffff);
+       sh_cmt_write(p, CMCNT, 0);
+
+       /* enable channel */
+       sh_cmt_start_stop_ch(p, 1);
+       return 0;
+}
+
+static void sh_cmt_disable(struct sh_cmt_priv *p)
+{
+       /* disable channel */
+       sh_cmt_start_stop_ch(p, 0);
+
+       /* stop clock */
+       clk_disable(p->clk);
+}
+
+/* private flags */
+#define FLAG_CLOCKEVENT (1 << 0)
+#define FLAG_CLOCKSOURCE (1 << 1)
+#define FLAG_REPROGRAM (1 << 2)
+#define FLAG_SKIPEVENT (1 << 3)
+#define FLAG_IRQCONTEXT (1 << 4)
+
+static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,
+                                             int absolute)
+{
+       unsigned long new_match;
+       unsigned long value = p->next_match_value;
+       unsigned long delay = 0;
+       unsigned long now = 0;
+       int has_wrapped;
+
+       now = sh_cmt_get_counter(p, &has_wrapped);
+       p->flags |= FLAG_REPROGRAM; /* force reprogram */
+
+       if (has_wrapped) {
+               /* we're competing with the interrupt handler.
+                *  -> let the interrupt handler reprogram the timer.
+                *  -> interrupt number two handles the event.
+                */
+               p->flags |= FLAG_SKIPEVENT;
+               return;
+       }
+
+       if (absolute)
+               now = 0;
+
+       do {
+               /* reprogram the timer hardware,
+                * but don't save the new match value yet.
+                */
+               new_match = now + value + delay;
+               if (new_match > p->max_match_value)
+                       new_match = p->max_match_value;
+
+               sh_cmt_write(p, CMCOR, new_match);
+
+               now = sh_cmt_get_counter(p, &has_wrapped);
+               if (has_wrapped && (new_match > p->match_value)) {
+                       /* we are changing to a greater match value,
+                        * so this wrap must be caused by the counter
+                        * matching the old value.
+                        * -> first interrupt reprograms the timer.
+                        * -> interrupt number two handles the event.
+                        */
+                       p->flags |= FLAG_SKIPEVENT;
+                       break;
+               }
+
+               if (has_wrapped) {
+                       /* we are changing to a smaller match value,
+                        * so the wrap must be caused by the counter
+                        * matching the new value.
+                        * -> save programmed match value.
+                        * -> let isr handle the event.
+                        */
+                       p->match_value = new_match;
+                       break;
+               }
+
+               /* be safe: verify hardware settings */
+               if (now < new_match) {
+                       /* timer value is below match value, all good.
+                        * this makes sure we won't miss any match events.
+                        * -> save programmed match value.
+                        * -> let isr handle the event.
+                        */
+                       p->match_value = new_match;
+                       break;
+               }
+
+               /* the counter has reached a value greater
+                * than our new match value. and since the
+                * has_wrapped flag isn't set we must have
+                * programmed a too close event.
+                * -> increase delay and retry.
+                */
+               if (delay)
+                       delay <<= 1;
+               else
+                       delay = 1;
+
+               if (!delay)
+                       pr_warning("sh_cmt: too long delay\n");
+
+       } while (delay);
+}
+
+static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+{
+       unsigned long flags;
+
+       if (delta > p->max_match_value)
+               pr_warning("sh_cmt: delta out of range\n");
+
+       spin_lock_irqsave(&p->lock, flags);
+       p->next_match_value = delta;
+       sh_cmt_clock_event_program_verify(p, 0);
+       spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
+{
+       struct sh_cmt_priv *p = dev_id;
+
+       /* clear flags */
+       sh_cmt_write(p, CMCSR, sh_cmt_read(p, CMCSR) & p->clear_bits);
+
+       /* update clock source counter to begin with if enabled
+        * the wrap flag should be cleared by the timer specific
+        * isr before we end up here.
+        */
+       if (p->flags & FLAG_CLOCKSOURCE)
+               p->total_cycles += p->match_value;
+
+       if (!(p->flags & FLAG_REPROGRAM))
+               p->next_match_value = p->max_match_value;
+
+       p->flags |= FLAG_IRQCONTEXT;
+
+       if (p->flags & FLAG_CLOCKEVENT) {
+               if (!(p->flags & FLAG_SKIPEVENT)) {
+                       if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) {
+                               p->next_match_value = p->max_match_value;
+                               p->flags |= FLAG_REPROGRAM;
+                       }
+
+                       p->ced.event_handler(&p->ced);
+               }
+       }
+
+       p->flags &= ~FLAG_SKIPEVENT;
+
+       if (p->flags & FLAG_REPROGRAM) {
+               p->flags &= ~FLAG_REPROGRAM;
+               sh_cmt_clock_event_program_verify(p, 1);
+
+               if (p->flags & FLAG_CLOCKEVENT)
+                       if ((p->ced.mode == CLOCK_EVT_MODE_SHUTDOWN)
+                           || (p->match_value == p->next_match_value))
+                               p->flags &= ~FLAG_REPROGRAM;
+       }
+
+       p->flags &= ~FLAG_IRQCONTEXT;
+
+       return IRQ_HANDLED;
+}
+
+static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       if (!(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
+               ret = sh_cmt_enable(p, &p->rate);
+
+       if (ret)
+               goto out;
+       p->flags |= flag;
+
+       /* setup timeout if no clockevent */
+       if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT)))
+               sh_cmt_set_next(p, p->max_match_value);
+ out:
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return ret;
+}
+
+static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
+{
+       unsigned long flags;
+       unsigned long f;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       f = p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
+       p->flags &= ~flag;
+
+       if (f && !(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
+               sh_cmt_disable(p);
+
+       /* adjust the timeout to maximum if only clocksource left */
+       if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE))
+               sh_cmt_set_next(p, p->max_match_value);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
+{
+       return container_of(ced, struct sh_cmt_priv, ced);
+}
+
+static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic)
+{
+       struct clock_event_device *ced = &p->ced;
+
+       sh_cmt_start(p, FLAG_CLOCKEVENT);
+
+       /* TODO: calculate good shift from rate and counter bit width */
+
+       ced->shift = 32;
+       ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
+       ced->max_delta_ns = clockevent_delta2ns(p->max_match_value, ced);
+       ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
+
+       if (periodic)
+               sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+       else
+               sh_cmt_set_next(p, p->max_match_value);
+}
+
+static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
+                                   struct clock_event_device *ced)
+{
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       /* deal with old setting first */
+       switch (ced->mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               sh_cmt_stop(p, FLAG_CLOCKEVENT);
+               break;
+       default:
+               break;
+       }
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               pr_info("sh_cmt: %s used for periodic clock events\n",
+                       ced->name);
+               sh_cmt_clock_event_start(p, 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               pr_info("sh_cmt: %s used for oneshot clock events\n",
+                       ced->name);
+               sh_cmt_clock_event_start(p, 0);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               sh_cmt_stop(p, FLAG_CLOCKEVENT);
+               break;
+       default:
+               break;
+       }
+}
+
+static int sh_cmt_clock_event_next(unsigned long delta,
+                                  struct clock_event_device *ced)
+{
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
+       if (likely(p->flags & FLAG_IRQCONTEXT))
+               p->next_match_value = delta;
+       else
+               sh_cmt_set_next(p, delta);
+
+       return 0;
+}
+
+static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
+                                      char *name, unsigned long rating)
+{
+       struct clock_event_device *ced = &p->ced;
+
+       memset(ced, 0, sizeof(*ced));
+
+       ced->name = name;
+       ced->features = CLOCK_EVT_FEAT_PERIODIC;
+       ced->features |= CLOCK_EVT_FEAT_ONESHOT;
+       ced->rating = rating;
+       ced->cpumask = cpumask_of(0);
+       ced->set_next_event = sh_cmt_clock_event_next;
+       ced->set_mode = sh_cmt_clock_event_mode;
+
+       pr_info("sh_cmt: %s used for clock events\n", ced->name);
+       ced->mult = 1; /* work around misplaced WARN_ON() in clockevents.c */
+       clockevents_register_device(ced);
+}
+
+int sh_cmt_register(struct sh_cmt_priv *p, char *name,
+                   unsigned long clockevent_rating,
+                   unsigned long clocksource_rating)
+{
+       if (p->width == (sizeof(p->max_match_value) * 8))
+               p->max_match_value = ~0;
+       else
+               p->max_match_value = (1 << p->width) - 1;
+
+       p->match_value = p->max_match_value;
+       spin_lock_init(&p->lock);
+
+       if (clockevent_rating)
+               sh_cmt_register_clockevent(p, name, clockevent_rating);
+
+       return 0;
+}
+
+static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
+{
+       struct sh_cmt_config *cfg = pdev->dev.platform_data;
+       struct resource *res;
+       int irq, ret;
+       ret = -ENXIO;
+
+       memset(p, 0, sizeof(*p));
+       p->pdev = pdev;
+
+       if (!cfg) {
+               dev_err(&p->pdev->dev, "missing platform data\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, p);
+
+       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+               goto err0;
+       }
+
+       irq = platform_get_irq(p->pdev, 0);
+       if (irq < 0) {
+               dev_err(&p->pdev->dev, "failed to get irq\n");
+               goto err0;
+       }
+
+       /* map memory, let mapbase point to our channel */
+       p->mapbase = ioremap_nocache(res->start, resource_size(res));
+       if (p->mapbase == NULL) {
+               pr_err("sh_cmt: failed to remap I/O memory\n");
+               goto err0;
+       }
+
+       /* request irq using setup_irq() (too early for request_irq()) */
+       p->irqaction.name = cfg->name;
+       p->irqaction.handler = sh_cmt_interrupt;
+       p->irqaction.dev_id = p;
+       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+       p->irqaction.mask = CPU_MASK_NONE;
+       ret = setup_irq(irq, &p->irqaction);
+       if (ret) {
+               pr_err("sh_cmt: failed to request irq %d\n", irq);
+               goto err1;
+       }
+
+       /* get hold of clock */
+       p->clk = clk_get(&p->pdev->dev, cfg->clk);
+       if (IS_ERR(p->clk)) {
+               pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
+               ret = PTR_ERR(p->clk);
+               goto err2;
+       }
+
+       if (resource_size(res) == 6) {
+               p->width = 16;
+               p->overflow_bit = 0x80;
+               p->clear_bits = ~0xc0;
+       } else {
+               p->width = 32;
+               p->overflow_bit = 0x8000;
+               p->clear_bits = ~0xc000;
+       }
+
+       return sh_cmt_register(p, cfg->name,
+                              cfg->clockevent_rating,
+                              cfg->clocksource_rating);
+ err2:
+       free_irq(irq, p);
+ err1:
+       iounmap(p->mapbase);
+ err0:
+       return ret;
+}
+
+static int __devinit sh_cmt_probe(struct platform_device *pdev)
+{
+       struct sh_cmt_priv *p = platform_get_drvdata(pdev);
+       int ret;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       ret = sh_cmt_setup(p, pdev);
+       if (ret) {
+               kfree(p);
+
+               platform_set_drvdata(pdev, NULL);
+       }
+       return ret;
+}
+
+static int __devexit sh_cmt_remove(struct platform_device *pdev)
+{
+       return -EBUSY; /* cannot unregister clockevent and clocksource */
+}
+
+static struct platform_driver sh_cmt_device_driver = {
+       .probe          = sh_cmt_probe,
+       .remove         = __devexit_p(sh_cmt_remove),
+       .driver         = {
+               .name   = "sh_cmt",
+       }
+};
+
+static int __init sh_cmt_init(void)
+{
+       return platform_driver_register(&sh_cmt_device_driver);
+}
+
+static void __exit sh_cmt_exit(void)
+{
+       platform_driver_unregister(&sh_cmt_device_driver);
+}
+
+module_init(sh_cmt_init);
+module_exit(sh_cmt_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("SuperH CMT Timer Driver");
+MODULE_LICENSE("GPL v2");
index d6daf3c507d3491b0e78a75f2366820114027f03..d270e8eb3e67f3fb0af2af1b6d4ea7a36521cf07 100644 (file)
@@ -104,7 +104,8 @@ EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
 
 
 /* internal prototypes */
-static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
+static int __cpufreq_governor(struct cpufreq_policy *policy,
+               unsigned int event);
 static unsigned int __cpufreq_get(unsigned int cpu);
 static void handle_update(struct work_struct *work);
 
@@ -128,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void)
 pure_initcall(init_cpufreq_transition_notifier_list);
 
 static LIST_HEAD(cpufreq_governor_list);
-static DEFINE_MUTEX (cpufreq_governor_mutex);
+static DEFINE_MUTEX(cpufreq_governor_mutex);
 
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
@@ -371,7 +372,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
        struct cpufreq_governor *t;
 
        list_for_each_entry(t, &cpufreq_governor_list, governor_list)
-               if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN))
+               if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN))
                        return t;
 
        return NULL;
@@ -429,15 +430,11 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
 
                mutex_unlock(&cpufreq_governor_mutex);
        }
-  out:
+out:
        return err;
 }
 
 
-/* drivers/base/cpu.c */
-extern struct sysdev_class cpu_sysdev_class;
-
-
 /**
  * cpufreq_per_cpu_attr_read() / show_##file_name() -
  * print out cpufreq information
@@ -450,11 +447,12 @@ extern struct sysdev_class cpu_sysdev_class;
 static ssize_t show_##file_name                                \
 (struct cpufreq_policy *policy, char *buf)             \
 {                                                      \
-       return sprintf (buf, "%u\n", policy->object);   \
+       return sprintf(buf, "%u\n", policy->object);    \
 }
 
 show_one(cpuinfo_min_freq, cpuinfo.min_freq);
 show_one(cpuinfo_max_freq, cpuinfo.max_freq);
+show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
 show_one(scaling_min_freq, min);
 show_one(scaling_max_freq, max);
 show_one(scaling_cur_freq, cur);
@@ -476,7 +474,7 @@ static ssize_t store_##file_name                                    \
        if (ret)                                                        \
                return -EINVAL;                                         \
                                                                        \
-       ret = sscanf (buf, "%u", &new_policy.object);                   \
+       ret = sscanf(buf, "%u", &new_policy.object);                    \
        if (ret != 1)                                                   \
                return -EINVAL;                                         \
                                                                        \
@@ -486,8 +484,8 @@ static ssize_t store_##file_name                                    \
        return ret ? ret : count;                                       \
 }
 
-store_one(scaling_min_freq,min);
-store_one(scaling_max_freq,max);
+store_one(scaling_min_freq, min);
+store_one(scaling_max_freq, max);
 
 /**
  * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
@@ -507,12 +505,13 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
  */
 static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
 {
-       if(policy->policy == CPUFREQ_POLICY_POWERSAVE)
+       if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
                return sprintf(buf, "powersave\n");
        else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
                return sprintf(buf, "performance\n");
        else if (policy->governor)
-               return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", policy->governor->name);
+               return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n",
+                               policy->governor->name);
        return -EINVAL;
 }
 
@@ -531,7 +530,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
        if (ret)
                return ret;
 
-       ret = sscanf (buf, "%15s", str_governor);
+       ret = sscanf(buf, "%15s", str_governor);
        if (ret != 1)
                return -EINVAL;
 
@@ -575,7 +574,8 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
        }
 
        list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
-               if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2)))
+               if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
+                   - (CPUFREQ_NAME_LEN + 2)))
                        goto out;
                i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name);
        }
@@ -594,7 +594,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
                        i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
                i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
                if (i >= (PAGE_SIZE - 5))
-                   break;
+                       break;
        }
        i += sprintf(&buf[i], "\n");
        return i;
@@ -660,6 +660,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
 define_one_ro0400(cpuinfo_cur_freq);
 define_one_ro(cpuinfo_min_freq);
 define_one_ro(cpuinfo_max_freq);
+define_one_ro(cpuinfo_transition_latency);
 define_one_ro(scaling_available_governors);
 define_one_ro(scaling_driver);
 define_one_ro(scaling_cur_freq);
@@ -673,6 +674,7 @@ define_one_rw(scaling_setspeed);
 static struct attribute *default_attrs[] = {
        &cpuinfo_min_freq.attr,
        &cpuinfo_max_freq.attr,
+       &cpuinfo_transition_latency.attr,
        &scaling_min_freq.attr,
        &scaling_max_freq.attr,
        &affected_cpus.attr,
@@ -684,10 +686,10 @@ static struct attribute *default_attrs[] = {
        NULL
 };
 
-#define to_policy(k) container_of(k,struct cpufreq_policy,kobj)
-#define to_attr(a) container_of(a,struct freq_attr,attr)
+#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
+#define to_attr(a) container_of(a, struct freq_attr, attr)
 
-static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf)
+static ssize_t show(struct kobject *kobj, struct attribute *attrchar *buf)
 {
        struct cpufreq_policy *policy = to_policy(kobj);
        struct freq_attr *fattr = to_attr(attr);
@@ -853,10 +855,10 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
                if (cpu == j)
                        continue;
 
-               /* check for existing affected CPUs.  They may not be aware
-                * of it due to CPU Hotplug.
+               /* Check for existing affected CPUs.
+                * They may not be aware of it due to CPU Hotplug.
                 */
-               managed_policy = cpufreq_cpu_get(j);            // FIXME: Where is this released?  What about error paths?
+               managed_policy = cpufreq_cpu_get(j);            /* FIXME: Where is this released?  What about error paths? */
                if (unlikely(managed_policy)) {
 
                        /* Set proper policy_cpu */
@@ -1127,8 +1129,8 @@ static void handle_update(struct work_struct *work)
  *     @old_freq: CPU frequency the kernel thinks the CPU runs at
  *     @new_freq: CPU frequency the CPU actually runs at
  *
- *     We adjust to current frequency first, and need to clean up later. So either call
- *     to cpufreq_update_policy() or schedule handle_update()).
+ *     We adjust to current frequency first, and need to clean up later.
+ *     So either call to cpufreq_update_policy() or schedule handle_update()).
  */
 static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
                                unsigned int new_freq)
@@ -1610,7 +1612,8 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
 
 /**
  * cpufreq_get_policy - get the current cpufreq_policy
- * @policy: struct cpufreq_policy into which the current cpufreq_policy is written
+ * @policy: struct cpufreq_policy into which the current cpufreq_policy
+ *     is written
  *
  * Reads the current cpufreq policy.
  */
index 0320962c4ec5c73b20fefc8dd2b5145f3d5d2411..2ecd95e4ab1aca33c6e858698d0c16f1b28a19ba 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (C)  2001 Russell King
  *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
  *                      Jun Nakajima <jun.nakajima@intel.com>
- *            (C)  2004 Alexander Clouter <alex-kernel@digriz.org.uk>
+ *            (C)  2009 Alexander Clouter <alex@digriz.org.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ctype.h>
 #include <linux/cpufreq.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/sysfs.h>
 #include <linux/cpu.h>
-#include <linux/kmod.h>
-#include <linux/workqueue.h>
 #include <linux/jiffies.h>
 #include <linux/kernel_stat.h>
-#include <linux/percpu.h>
 #include <linux/mutex.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/ktime.h>
+#include <linux/sched.h>
+
 /*
  * dbs is used in this file as a shortform for demandbased switching
  * It helps to keep variable names smaller, simpler
  * latency of the processor. The governor will work on any processor with
  * transition latency <= 10mS, using appropriate sampling
  * rate.
- * For CPUs with transition latency > 10mS (mostly drivers
- * with CPUFREQ_ETERNAL), this governor will not work.
+ * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work.
  * All times here are in uS.
  */
 static unsigned int def_sampling_rate;
 #define MIN_SAMPLING_RATE_RATIO                        (2)
 /* for correct statistics, we need at least 10 ticks between each measure */
-#define MIN_STAT_SAMPLING_RATE                 \
+#define MIN_STAT_SAMPLING_RATE                         \
                        (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
 #define MIN_SAMPLING_RATE                      \
                        (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
+/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon
+ * Define the minimal settable sampling rate to the greater of:
+ *   - "HW transition latency" * 100 (same as default sampling / 10)
+ *   - MIN_STAT_SAMPLING_RATE
+ * To avoid that userspace shoots itself.
+*/
+static unsigned int minimum_sampling_rate(void)
+{
+       return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE);
+}
+
+/* This will also vanish soon with removing sampling_rate_max */
 #define MAX_SAMPLING_RATE                      (500 * def_sampling_rate)
-#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
+#define LATENCY_MULTIPLIER                     (1000)
 #define DEF_SAMPLING_DOWN_FACTOR               (1)
 #define MAX_SAMPLING_DOWN_FACTOR               (10)
 #define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
@@ -63,12 +70,15 @@ static unsigned int def_sampling_rate;
 static void do_dbs_timer(struct work_struct *work);
 
 struct cpu_dbs_info_s {
+       cputime64_t prev_cpu_idle;
+       cputime64_t prev_cpu_wall;
+       cputime64_t prev_cpu_nice;
        struct cpufreq_policy *cur_policy;
-       unsigned int prev_cpu_idle_up;
-       unsigned int prev_cpu_idle_down;
-       unsigned int enable;
+       struct delayed_work work;
        unsigned int down_skip;
        unsigned int requested_freq;
+       int cpu;
+       unsigned int enable:1;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
@@ -82,19 +92,18 @@ static unsigned int dbs_enable;     /* number of CPUs using this policy */
  * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
  * is recursive for the same process. -Venki
  */
-static DEFINE_MUTEX (dbs_mutex);
-static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer);
+static DEFINE_MUTEX(dbs_mutex);
 
-struct dbs_tuners {
+static struct workqueue_struct *kconservative_wq;
+
+static struct dbs_tuners {
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
        unsigned int up_threshold;
        unsigned int down_threshold;
        unsigned int ignore_nice;
        unsigned int freq_step;
-};
-
-static struct dbs_tuners dbs_tuners_ins = {
+} dbs_tuners_ins = {
        .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
        .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
        .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
@@ -102,18 +111,37 @@ static struct dbs_tuners dbs_tuners_ins = {
        .freq_step = 5,
 };
 
-static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+                                                       cputime64_t *wall)
 {
-       unsigned int add_nice = 0, ret;
+       cputime64_t idle_time;
+       cputime64_t cur_wall_time;
+       cputime64_t busy_time;
 
-       if (dbs_tuners_ins.ignore_nice)
-               add_nice = kstat_cpu(cpu).cpustat.nice;
+       cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+       busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
+                       kstat_cpu(cpu).cpustat.system);
+
+       busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq);
+       busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq);
+       busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal);
+       busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.nice);
+
+       idle_time = cputime64_sub(cur_wall_time, busy_time);
+       if (wall)
+               *wall = cur_wall_time;
+
+       return idle_time;
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+{
+       u64 idle_time = get_cpu_idle_time_us(cpu, wall);
 
-       ret = kstat_cpu(cpu).cpustat.idle +
-               kstat_cpu(cpu).cpustat.iowait +
-               add_nice;
+       if (idle_time == -1ULL)
+               return get_cpu_idle_time_jiffy(cpu, wall);
 
-       return ret;
+       return idle_time;
 }
 
 /* keep track of frequency transitions */
@@ -125,10 +153,21 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
        struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
                                                        freq->cpu);
 
+       struct cpufreq_policy *policy;
+
        if (!this_dbs_info->enable)
                return 0;
 
-       this_dbs_info->requested_freq = freq->new;
+       policy = this_dbs_info->cur_policy;
+
+       /*
+        * we only care if our internally tracked freq moves outside
+        * the 'valid' ranges of freqency available to us otherwise
+        * we do not change it
+       */
+       if (this_dbs_info->requested_freq > policy->max
+                       || this_dbs_info->requested_freq < policy->min)
+               this_dbs_info->requested_freq = freq->new;
 
        return 0;
 }
@@ -140,16 +179,31 @@ static struct notifier_block dbs_cpufreq_notifier_block = {
 /************************** sysfs interface ************************/
 static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+       static int print_once;
+
+       if (!print_once) {
+               printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max "
+                      "sysfs file is deprecated - used by: %s\n",
+                      current->comm);
+               print_once = 1;
+       }
+       return sprintf(buf, "%u\n", MAX_SAMPLING_RATE);
 }
 
 static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+       static int print_once;
+
+       if (!print_once) {
+               printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max "
+                      "sysfs file is deprecated - used by: %s\n", current->comm);
+               print_once = 1;
+       }
+       return sprintf(buf, "%u\n", MIN_SAMPLING_RATE);
 }
 
-#define define_one_ro(_name)                           \
-static struct freq_attr _name =                                \
+#define define_one_ro(_name)           \
+static struct freq_attr _name =                \
 __ATTR(_name, 0444, show_##_name, NULL)
 
 define_one_ro(sampling_rate_max);
@@ -174,7 +228,8 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
 {
        unsigned int input;
        int ret;
-       ret = sscanf (buf, "%u", &input);
+       ret = sscanf(buf, "%u", &input);
+
        if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
                return -EINVAL;
 
@@ -190,15 +245,13 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
 {
        unsigned int input;
        int ret;
-       ret = sscanf (buf, "%u", &input);
+       ret = sscanf(buf, "%u", &input);
 
-       mutex_lock(&dbs_mutex);
-       if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
-               mutex_unlock(&dbs_mutex);
+       if (ret != 1)
                return -EINVAL;
-       }
 
-       dbs_tuners_ins.sampling_rate = input;
+       mutex_lock(&dbs_mutex);
+       dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
        mutex_unlock(&dbs_mutex);
 
        return count;
@@ -209,10 +262,11 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
 {
        unsigned int input;
        int ret;
-       ret = sscanf (buf, "%u", &input);
+       ret = sscanf(buf, "%u", &input);
 
        mutex_lock(&dbs_mutex);
-       if (ret != 1 || input > 100 || input <= dbs_tuners_ins.down_threshold) {
+       if (ret != 1 || input > 100 ||
+                       input <= dbs_tuners_ins.down_threshold) {
                mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
@@ -228,10 +282,12 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
 {
        unsigned int input;
        int ret;
-       ret = sscanf (buf, "%u", &input);
+       ret = sscanf(buf, "%u", &input);
 
        mutex_lock(&dbs_mutex);
-       if (ret != 1 || input > 100 || input >= dbs_tuners_ins.up_threshold) {
+       /* cannot be lower than 11 otherwise freq will not fall */
+       if (ret != 1 || input < 11 || input > 100 ||
+                       input >= dbs_tuners_ins.up_threshold) {
                mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
@@ -264,12 +320,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        }
        dbs_tuners_ins.ignore_nice = input;
 
-       /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+       /* we need to re-evaluate prev_cpu_idle */
        for_each_online_cpu(j) {
-               struct cpu_dbs_info_s *j_dbs_info;
-               j_dbs_info = &per_cpu(cpu_dbs_info, j);
-               j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
-               j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+               struct cpu_dbs_info_s *dbs_info;
+               dbs_info = &per_cpu(cpu_dbs_info, j);
+               dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+                                               &dbs_info->prev_cpu_wall);
+               if (dbs_tuners_ins.ignore_nice)
+                       dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
        }
        mutex_unlock(&dbs_mutex);
 
@@ -281,7 +339,6 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy,
 {
        unsigned int input;
        int ret;
-
        ret = sscanf(buf, "%u", &input);
 
        if (ret != 1)
@@ -310,7 +367,7 @@ define_one_rw(down_threshold);
 define_one_rw(ignore_nice_load);
 define_one_rw(freq_step);
 
-static struct attribute * dbs_attributes[] = {
+static struct attribute *dbs_attributes[] = {
        &sampling_rate_max.attr,
        &sampling_rate_min.attr,
        &sampling_rate.attr,
@@ -329,55 +386,78 @@ static struct attribute_group dbs_attr_group = {
 
 /************************** sysfs end ************************/
 
-static void dbs_check_cpu(int cpu)
+static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 {
-       unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
-       unsigned int tmp_idle_ticks, total_idle_ticks;
+       unsigned int load = 0;
        unsigned int freq_target;
-       unsigned int freq_down_sampling_rate;
-       struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
-       struct cpufreq_policy *policy;
 
-       if (!this_dbs_info->enable)
-               return;
+       struct cpufreq_policy *policy;
+       unsigned int j;
 
        policy = this_dbs_info->cur_policy;
 
        /*
-        * The default safe range is 20% to 80%
-        * Every sampling_rate, we check
-        *      - If current idle time is less than 20%, then we try to
-        *        increase frequency
-        * Every sampling_rate*sampling_down_factor, we check
-        *      - If current idle time is more than 80%, then we try to
-        *        decrease frequency
+        * Every sampling_rate, we check, if current idle time is less
+        * than 20% (default), then we try to increase frequency
+        * Every sampling_rate*sampling_down_factor, we check, if current
+        * idle time is more than 80%, then we try to decrease frequency
         *
         * Any frequency increase takes it to the maximum frequency.
         * Frequency reduction happens at minimum steps of
-        * 5% (default) of max_frequency
+        * 5% (default) of maximum frequency
         */
 
-       /* Check for frequency increase */
-       idle_ticks = UINT_MAX;
+       /* Get Absolute Load */
+       for_each_cpu(j, policy->cpus) {
+               struct cpu_dbs_info_s *j_dbs_info;
+               cputime64_t cur_wall_time, cur_idle_time;
+               unsigned int idle_time, wall_time;
 
-       /* Check for frequency increase */
-       total_idle_ticks = get_cpu_idle_time(cpu);
-       tmp_idle_ticks = total_idle_ticks -
-               this_dbs_info->prev_cpu_idle_up;
-       this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+               j_dbs_info = &per_cpu(cpu_dbs_info, j);
+
+               cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+
+               wall_time = (unsigned int) cputime64_sub(cur_wall_time,
+                               j_dbs_info->prev_cpu_wall);
+               j_dbs_info->prev_cpu_wall = cur_wall_time;
+
+               idle_time = (unsigned int) cputime64_sub(cur_idle_time,
+                               j_dbs_info->prev_cpu_idle);
+               j_dbs_info->prev_cpu_idle = cur_idle_time;
+
+               if (dbs_tuners_ins.ignore_nice) {
+                       cputime64_t cur_nice;
+                       unsigned long cur_nice_jiffies;
+
+                       cur_nice = cputime64_sub(kstat_cpu(j).cpustat.nice,
+                                        j_dbs_info->prev_cpu_nice);
+                       /*
+                        * Assumption: nice time between sampling periods will
+                        * be less than 2^32 jiffies for 32 bit sys
+                        */
+                       cur_nice_jiffies = (unsigned long)
+                                       cputime64_to_jiffies64(cur_nice);
 
-       if (tmp_idle_ticks < idle_ticks)
-               idle_ticks = tmp_idle_ticks;
+                       j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
+                       idle_time += jiffies_to_usecs(cur_nice_jiffies);
+               }
+
+               if (unlikely(!wall_time || wall_time < idle_time))
+                       continue;
+
+               load = 100 * (wall_time - idle_time) / wall_time;
+       }
 
-       /* Scale idle ticks by 100 and compare with up and down ticks */
-       idle_ticks *= 100;
-       up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
-                       usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+       /*
+        * break out if we 'cannot' reduce the speed as the user might
+        * want freq_step to be zero
+        */
+       if (dbs_tuners_ins.freq_step == 0)
+               return;
 
-       if (idle_ticks < up_idle_ticks) {
+       /* Check for frequency increase */
+       if (load > dbs_tuners_ins.up_threshold) {
                this_dbs_info->down_skip = 0;
-               this_dbs_info->prev_cpu_idle_down =
-                       this_dbs_info->prev_cpu_idle_up;
 
                /* if we are already at full speed then break out early */
                if (this_dbs_info->requested_freq == policy->max)
@@ -398,49 +478,24 @@ static void dbs_check_cpu(int cpu)
                return;
        }
 
-       /* Check for frequency decrease */
-       this_dbs_info->down_skip++;
-       if (this_dbs_info->down_skip < dbs_tuners_ins.sampling_down_factor)
-               return;
-
-       /* Check for frequency decrease */
-       total_idle_ticks = this_dbs_info->prev_cpu_idle_up;
-       tmp_idle_ticks = total_idle_ticks -
-               this_dbs_info->prev_cpu_idle_down;
-       this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
-
-       if (tmp_idle_ticks < idle_ticks)
-               idle_ticks = tmp_idle_ticks;
-
-       /* Scale idle ticks by 100 and compare with up and down ticks */
-       idle_ticks *= 100;
-       this_dbs_info->down_skip = 0;
-
-       freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
-               dbs_tuners_ins.sampling_down_factor;
-       down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
-               usecs_to_jiffies(freq_down_sampling_rate);
-
-       if (idle_ticks > down_idle_ticks) {
-               /*
-                * if we are already at the lowest speed then break out early
-                * or if we 'cannot' reduce the speed as the user might want
-                * freq_target to be zero
-                */
-               if (this_dbs_info->requested_freq == policy->min
-                               || dbs_tuners_ins.freq_step == 0)
-                       return;
-
+       /*
+        * The optimal frequency is the frequency that is the lowest that
+        * can support the current CPU usage without triggering the up
+        * policy. To be safe, we focus 10 points under the threshold.
+        */
+       if (load < (dbs_tuners_ins.down_threshold - 10)) {
                freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100;
 
-               /* max freq cannot be less than 100. But who knows.... */
-               if (unlikely(freq_target == 0))
-                       freq_target = 5;
-
                this_dbs_info->requested_freq -= freq_target;
                if (this_dbs_info->requested_freq < policy->min)
                        this_dbs_info->requested_freq = policy->min;
 
+               /*
+                * if we cannot reduce the frequency anymore, break out early
+                */
+               if (policy->cur == policy->min)
+                       return;
+
                __cpufreq_driver_target(policy, this_dbs_info->requested_freq,
                                CPUFREQ_RELATION_H);
                return;
@@ -449,27 +504,45 @@ static void dbs_check_cpu(int cpu)
 
 static void do_dbs_timer(struct work_struct *work)
 {
-       int i;
-       mutex_lock(&dbs_mutex);
-       for_each_online_cpu(i)
-               dbs_check_cpu(i);
-       schedule_delayed_work(&dbs_work,
-                       usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
-       mutex_unlock(&dbs_mutex);
+       struct cpu_dbs_info_s *dbs_info =
+               container_of(work, struct cpu_dbs_info_s, work.work);
+       unsigned int cpu = dbs_info->cpu;
+
+       /* We want all CPUs to do sampling nearly on same jiffy */
+       int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+       delay -= jiffies % delay;
+
+       if (lock_policy_rwsem_write(cpu) < 0)
+               return;
+
+       if (!dbs_info->enable) {
+               unlock_policy_rwsem_write(cpu);
+               return;
+       }
+
+       dbs_check_cpu(dbs_info);
+
+       queue_delayed_work_on(cpu, kconservative_wq, &dbs_info->work, delay);
+       unlock_policy_rwsem_write(cpu);
 }
 
-static inline void dbs_timer_init(void)
+static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 {
-       init_timer_deferrable(&dbs_work.timer);
-       schedule_delayed_work(&dbs_work,
-                       usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
-       return;
+       /* We want all CPUs to do sampling nearly on same jiffy */
+       int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+       delay -= jiffies % delay;
+
+       dbs_info->enable = 1;
+       INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
+       queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
+                               delay);
 }
 
-static inline void dbs_timer_exit(void)
+static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
 {
-       cancel_delayed_work(&dbs_work);
-       return;
+       dbs_info->enable = 0;
+       cancel_delayed_work(&dbs_info->work);
 }
 
 static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -503,11 +576,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        j_dbs_info = &per_cpu(cpu_dbs_info, j);
                        j_dbs_info->cur_policy = policy;
 
-                       j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu);
-                       j_dbs_info->prev_cpu_idle_down
-                               = j_dbs_info->prev_cpu_idle_up;
+                       j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+                                               &j_dbs_info->prev_cpu_wall);
+                       if (dbs_tuners_ins.ignore_nice) {
+                               j_dbs_info->prev_cpu_nice =
+                                               kstat_cpu(j).cpustat.nice;
+                       }
                }
-               this_dbs_info->enable = 1;
                this_dbs_info->down_skip = 0;
                this_dbs_info->requested_freq = policy->cur;
 
@@ -523,38 +598,36 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        if (latency == 0)
                                latency = 1;
 
-                       def_sampling_rate = 10 * latency *
-                                       DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
-
-                       if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
-                               def_sampling_rate = MIN_STAT_SAMPLING_RATE;
+                       def_sampling_rate =
+                               max(latency * LATENCY_MULTIPLIER,
+                                   MIN_STAT_SAMPLING_RATE);
 
                        dbs_tuners_ins.sampling_rate = def_sampling_rate;
 
-                       dbs_timer_init();
                        cpufreq_register_notifier(
                                        &dbs_cpufreq_notifier_block,
                                        CPUFREQ_TRANSITION_NOTIFIER);
                }
+               dbs_timer_init(this_dbs_info);
 
                mutex_unlock(&dbs_mutex);
+
                break;
 
        case CPUFREQ_GOV_STOP:
                mutex_lock(&dbs_mutex);
-               this_dbs_info->enable = 0;
+               dbs_timer_exit(this_dbs_info);
                sysfs_remove_group(&policy->kobj, &dbs_attr_group);
                dbs_enable--;
+
                /*
                 * Stop the timerschedule work, when this governor
                 * is used for first time
                 */
-               if (dbs_enable == 0) {
-                       dbs_timer_exit();
+               if (dbs_enable == 0)
                        cpufreq_unregister_notifier(
                                        &dbs_cpufreq_notifier_block,
                                        CPUFREQ_TRANSITION_NOTIFIER);
-               }
 
                mutex_unlock(&dbs_mutex);
 
@@ -571,6 +644,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                                        this_dbs_info->cur_policy,
                                        policy->min, CPUFREQ_RELATION_L);
                mutex_unlock(&dbs_mutex);
+
                break;
        }
        return 0;
@@ -588,23 +662,33 @@ struct cpufreq_governor cpufreq_gov_conservative = {
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       return cpufreq_register_governor(&cpufreq_gov_conservative);
+       int err;
+
+       kconservative_wq = create_workqueue("kconservative");
+       if (!kconservative_wq) {
+               printk(KERN_ERR "Creation of kconservative failed\n");
+               return -EFAULT;
+       }
+
+       err = cpufreq_register_governor(&cpufreq_gov_conservative);
+       if (err)
+               destroy_workqueue(kconservative_wq);
+
+       return err;
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-       /* Make sure that the scheduled work is indeed not running */
-       flush_scheduled_work();
-
        cpufreq_unregister_governor(&cpufreq_gov_conservative);
+       destroy_workqueue(kconservative_wq);
 }
 
 
-MODULE_AUTHOR ("Alexander Clouter <alex-kernel@digriz.org.uk>");
-MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for "
+MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
+MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
                "Low Latency Frequency Transition capable processors "
                "optimised for use in a battery environment");
-MODULE_LICENSE ("GPL");
+MODULE_LICENSE("GPL");
 
 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
 fs_initcall(cpufreq_gov_dbs_init);
index 6f45b1658a67d0bee41c5156cdca709e639d0b67..338f428a15b765ceaef4686225715d5d2f9f93e3 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/hrtimer.h>
 #include <linux/tick.h>
 #include <linux/ktime.h>
+#include <linux/sched.h>
 
 /*
  * dbs is used in this file as a shortform for demandbased switching
@@ -51,8 +52,20 @@ static unsigned int def_sampling_rate;
                        (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
 #define MIN_SAMPLING_RATE                      \
                        (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
+/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon
+ * Define the minimal settable sampling rate to the greater of:
+ *   - "HW transition latency" * 100 (same as default sampling / 10)
+ *   - MIN_STAT_SAMPLING_RATE
+ * To avoid that userspace shoots itself.
+*/
+static unsigned int minimum_sampling_rate(void)
+{
+       return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE);
+}
+
+/* This will also vanish soon with removing sampling_rate_max */
 #define MAX_SAMPLING_RATE                      (500 * def_sampling_rate)
-#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
+#define LATENCY_MULTIPLIER                     (1000)
 #define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
@@ -65,14 +78,14 @@ struct cpu_dbs_info_s {
        cputime64_t prev_cpu_wall;
        cputime64_t prev_cpu_nice;
        struct cpufreq_policy *cur_policy;
-       struct delayed_work work;
+       struct delayed_work work;
        struct cpufreq_frequency_table *freq_table;
        unsigned int freq_lo;
        unsigned int freq_lo_jiffies;
        unsigned int freq_hi_jiffies;
        int cpu;
        unsigned int enable:1,
-                    sample_type:1;
+               sample_type:1;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
@@ -203,12 +216,28 @@ static void ondemand_powersave_bias_init(void)
 /************************** sysfs interface ************************/
 static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+       static int print_once;
+
+       if (!print_once) {
+               printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_max "
+                      "sysfs file is deprecated - used by: %s\n",
+                      current->comm);
+               print_once = 1;
+       }
+       return sprintf(buf, "%u\n", MAX_SAMPLING_RATE);
 }
 
 static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+       static int print_once;
+
+       if (!print_once) {
+               printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_min "
+                      "sysfs file is deprecated - used by: %s\n",
+                      current->comm);
+               print_once = 1;
+       }
+       return sprintf(buf, "%u\n", MIN_SAMPLING_RATE);
 }
 
 #define define_one_ro(_name)           \
@@ -238,13 +267,11 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
        ret = sscanf(buf, "%u", &input);
 
        mutex_lock(&dbs_mutex);
-       if (ret != 1 || input > MAX_SAMPLING_RATE
-                    || input < MIN_SAMPLING_RATE) {
+       if (ret != 1) {
                mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
-
-       dbs_tuners_ins.sampling_rate = input;
+       dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
        mutex_unlock(&dbs_mutex);
 
        return count;
@@ -279,14 +306,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        unsigned int j;
 
        ret = sscanf(buf, "%u", &input);
-       if ( ret != 1 )
+       if (ret != 1)
                return -EINVAL;
 
-       if ( input > 1 )
+       if (input > 1)
                input = 1;
 
        mutex_lock(&dbs_mutex);
-       if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
+       if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
                mutex_unlock(&dbs_mutex);
                return count;
        }
@@ -337,7 +364,7 @@ define_one_rw(up_threshold);
 define_one_rw(ignore_nice_load);
 define_one_rw(powersave_bias);
 
-static struct attribute * dbs_attributes[] = {
+static struct attribute *dbs_attributes[] = {
        &sampling_rate_max.attr,
        &sampling_rate_min.attr,
        &sampling_rate.attr,
@@ -512,8 +539,7 @@ static void do_dbs_timer(struct work_struct *work)
                }
        } else {
                __cpufreq_driver_target(dbs_info->cur_policy,
-                                       dbs_info->freq_lo,
-                                       CPUFREQ_RELATION_H);
+                       dbs_info->freq_lo, CPUFREQ_RELATION_H);
        }
        queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
        unlock_policy_rwsem_write(cpu);
@@ -530,7 +556,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
        dbs_info->sample_type = DBS_NORMAL_SAMPLE;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
        queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
-                             delay);
+               delay);
 }
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -591,11 +617,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        if (latency == 0)
                                latency = 1;
 
-                       def_sampling_rate = latency *
-                                       DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
-
-                       if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
-                               def_sampling_rate = MIN_STAT_SAMPLING_RATE;
+                       def_sampling_rate =
+                               max(latency * LATENCY_MULTIPLIER,
+                                   MIN_STAT_SAMPLING_RATE);
 
                        dbs_tuners_ins.sampling_rate = def_sampling_rate;
                }
@@ -617,12 +641,10 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                mutex_lock(&dbs_mutex);
                if (policy->max < this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(this_dbs_info->cur_policy,
-                                               policy->max,
-                                               CPUFREQ_RELATION_H);
+                               policy->max, CPUFREQ_RELATION_H);
                else if (policy->min > this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(this_dbs_info->cur_policy,
-                                               policy->min,
-                                               CPUFREQ_RELATION_L);
+                               policy->min, CPUFREQ_RELATION_L);
                mutex_unlock(&dbs_mutex);
                break;
        }
@@ -677,7 +699,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
 MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
 MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
 MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
-                   "Low Latency Frequency Transition capable processors");
+       "Low Latency Frequency Transition capable processors");
 MODULE_LICENSE("GPL");
 
 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
index c0ff97d375d79c83cdd3e52dbf65dc900c94c7a3..5a62d678dd1932f777f17fec0bdbda8d6c9398f9 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/cpufreq/cpufreq_stats.c
  *
  *  Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
- *           (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
+ *  (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,7 @@
 
 static spinlock_t cpufreq_stats_lock;
 
-#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
+#define CPUFREQ_STATDEVICE_ATTR(_name, _mode, _show) \
 static struct freq_attr _attr_##_name = {\
        .attr = {.name = __stringify(_name), .mode = _mode, }, \
        .show = _show,\
@@ -50,8 +50,7 @@ struct cpufreq_stats_attribute {
        ssize_t(*show) (struct cpufreq_stats *, char *);
 };
 
-static int
-cpufreq_stats_update (unsigned int cpu)
+static int cpufreq_stats_update(unsigned int cpu)
 {
        struct cpufreq_stats *stat;
        unsigned long long cur_time;
@@ -68,8 +67,7 @@ cpufreq_stats_update (unsigned int cpu)
        return 0;
 }
 
-static ssize_t
-show_total_trans(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
 {
        struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
        if (!stat)
@@ -78,8 +76,7 @@ show_total_trans(struct cpufreq_policy *policy, char *buf)
                        per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
 }
 
-static ssize_t
-show_time_in_state(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
 {
        ssize_t len = 0;
        int i;
@@ -89,14 +86,14 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
        cpufreq_stats_update(stat->cpu);
        for (i = 0; i < stat->state_num; i++) {
                len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
-                       (unsigned long long)cputime64_to_clock_t(stat->time_in_state[i]));
+                       (unsigned long long)
+                       cputime64_to_clock_t(stat->time_in_state[i]));
        }
        return len;
 }
 
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
-static ssize_t
-show_trans_table(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
 {
        ssize_t len = 0;
        int i, j;
@@ -139,11 +136,11 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
                return PAGE_SIZE;
        return len;
 }
-CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
+CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table);
 #endif
 
-CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
-CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
+CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans);
+CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state);
 
 static struct attribute *default_attrs[] = {
        &_attr_total_trans.attr,
@@ -158,8 +155,7 @@ static struct attribute_group stats_attr_group = {
        .name = "stats"
 };
 
-static int
-freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
+static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
 {
        int index;
        for (index = 0; index < stat->max_state; index++)
@@ -183,8 +179,7 @@ static void cpufreq_stats_free_table(unsigned int cpu)
                cpufreq_cpu_put(policy);
 }
 
-static int
-cpufreq_stats_create_table (struct cpufreq_policy *policy,
+static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
                struct cpufreq_frequency_table *table)
 {
        unsigned int i, j, count = 0, ret = 0;
@@ -194,7 +189,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
        unsigned int cpu = policy->cpu;
        if (per_cpu(cpufreq_stats_table, cpu))
                return -EBUSY;
-       if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL)
+       stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
+       if ((stat) == NULL)
                return -ENOMEM;
 
        data = cpufreq_cpu_get(cpu);
@@ -203,13 +199,14 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
                goto error_get_fail;
        }
 
-       if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group)))
+       ret = sysfs_create_group(&data->kobj, &stats_attr_group);
+       if (ret)
                goto error_out;
 
        stat->cpu = cpu;
        per_cpu(cpufreq_stats_table, cpu) = stat;
 
-       for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
                unsigned int freq = table[i].frequency;
                if (freq == CPUFREQ_ENTRY_INVALID)
                        continue;
@@ -255,9 +252,8 @@ error_get_fail:
        return ret;
 }
 
-static int
-cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
-               void *data)
+static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
+               unsigned long val, void *data)
 {
        int ret;
        struct cpufreq_policy *policy = data;
@@ -268,14 +264,14 @@ cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
        table = cpufreq_frequency_get_table(cpu);
        if (!table)
                return 0;
-       if ((ret = cpufreq_stats_create_table(policy, table)))
+       ret = cpufreq_stats_create_table(policy, table);
+       if (ret)
                return ret;
        return 0;
 }
 
-static int
-cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
-               void *data)
+static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
+               unsigned long val, void *data)
 {
        struct cpufreq_freqs *freq = data;
        struct cpufreq_stats *stat;
@@ -340,19 +336,20 @@ static struct notifier_block notifier_trans_block = {
        .notifier_call = cpufreq_stat_notifier_trans
 };
 
-static int
-__init cpufreq_stats_init(void)
+static int __init cpufreq_stats_init(void)
 {
        int ret;
        unsigned int cpu;
 
        spin_lock_init(&cpufreq_stats_lock);
-       if ((ret = cpufreq_register_notifier(&notifier_policy_block,
-                               CPUFREQ_POLICY_NOTIFIER)))
+       ret = cpufreq_register_notifier(&notifier_policy_block,
+                               CPUFREQ_POLICY_NOTIFIER);
+       if (ret)
                return ret;
 
-       if ((ret = cpufreq_register_notifier(&notifier_trans_block,
-                               CPUFREQ_TRANSITION_NOTIFIER))) {
+       ret = cpufreq_register_notifier(&notifier_trans_block,
+                               CPUFREQ_TRANSITION_NOTIFIER);
+       if (ret) {
                cpufreq_unregister_notifier(&notifier_policy_block,
                                CPUFREQ_POLICY_NOTIFIER);
                return ret;
@@ -364,8 +361,7 @@ __init cpufreq_stats_init(void)
        }
        return 0;
 }
-static void
-__exit cpufreq_stats_exit(void)
+static void __exit cpufreq_stats_exit(void)
 {
        unsigned int cpu;
 
@@ -379,10 +375,10 @@ __exit cpufreq_stats_exit(void)
        }
 }
 
-MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
+MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
+MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
                                "through sysfs filesystem");
-MODULE_LICENSE ("GPL");
+MODULE_LICENSE("GPL");
 
 module_init(cpufreq_stats_init);
 module_exit(cpufreq_stats_exit);
index 1442bbada05303bae02adcd3026f57aed4d55a4d..66d2d1d6c80f1dbc0c17388e4dbea81c18c5628e 100644 (file)
@@ -24,9 +24,6 @@
 #include <linux/sysfs.h>
 #include <linux/mutex.h>
 
-#include <asm/uaccess.h>
-
-
 /**
  * A few values needed by the userspace governor
  */
@@ -37,7 +34,7 @@ static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
                                                        userspace */
 static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
 
-static DEFINE_MUTEX    (userspace_mutex);
+static DEFINE_MUTEX(userspace_mutex);
 static int cpus_using_userspace_governor;
 
 #define dprintk(msg...) \
@@ -46,9 +43,9 @@ static int cpus_using_userspace_governor;
 /* keep track of frequency transitions */
 static int
 userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-                       void *data)
+       void *data)
 {
-        struct cpufreq_freqs *freq = data;
+       struct cpufreq_freqs *freq = data;
 
        if (!per_cpu(cpu_is_managed, freq->cpu))
                return 0;
@@ -57,11 +54,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                        freq->cpu, freq->new);
        per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
 
-        return 0;
+       return 0;
 }
 
 static struct notifier_block userspace_cpufreq_notifier_block = {
-        .notifier_call  = userspace_cpufreq_notifier
+       .notifier_call  = userspace_cpufreq_notifier
 };
 
 
@@ -93,8 +90,11 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
         * We're safe from concurrent calls to ->target() here
         * as we hold the userspace_mutex lock. If we were calling
         * cpufreq_driver_target, a deadlock situation might occur:
-        * A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock)
-        * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex)
+        * A: cpufreq_set (lock userspace_mutex) ->
+        *      cpufreq_driver_target(lock policy->lock)
+        * B: cpufreq_set_policy(lock policy->lock) ->
+        *      __cpufreq_governor ->
+        *         cpufreq_governor_userspace (lock userspace_mutex)
         */
        ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
 
@@ -210,9 +210,10 @@ static void __exit cpufreq_gov_userspace_exit(void)
 }
 
 
-MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>");
-MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
+               "Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
+MODULE_LICENSE("GPL");
 
 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
 fs_initcall(cpufreq_gov_userspace_init);
index 9071d80fbba2427d6b29c911832e169bf201466a..a9bd3a05a684548cc7f36aa34fe8a1057d2bfbb3 100644 (file)
@@ -28,7 +28,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
        unsigned int max_freq = 0;
        unsigned int i;
 
-       for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                unsigned int freq = table[i].frequency;
                if (freq == CPUFREQ_ENTRY_INVALID) {
                        dprintk("table entry %u is invalid, skipping\n", i);
@@ -70,7 +70,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
        cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
                                     policy->cpuinfo.max_freq);
 
-       for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                unsigned int freq = table[i].frequency;
                if (freq == CPUFREQ_ENTRY_INVALID)
                        continue;
@@ -125,13 +125,13 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
        if (!cpu_online(policy->cpu))
                return -EINVAL;
 
-       for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                unsigned int freq = table[i].frequency;
                if (freq == CPUFREQ_ENTRY_INVALID)
                        continue;
                if ((freq < policy->min) || (freq > policy->max))
                        continue;
-               switch(relation) {
+               switch (relation) {
                case CPUFREQ_RELATION_H:
                        if (freq <= target_freq) {
                                if (freq >= optimal.frequency) {
@@ -178,7 +178,7 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table);
 /**
  * show_available_freqs - show available frequencies for the specified CPU
  */
-static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
 {
        unsigned int i = 0;
        unsigned int cpu = policy->cpu;
@@ -190,7 +190,7 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
 
        table = per_cpu(show_table, cpu);
 
-       for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
                count += sprintf(&buf[count], "%d ", table[i].frequency);
@@ -234,6 +234,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
 
-MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("CPUfreq frequency table helpers");
+MODULE_LICENSE("GPL");
index e522144cba3af9bc9d9e5e9bbc1e5dcb05e693c0..01afd758072f8242f550fc70b30b9c124aa8fa2b 100644 (file)
@@ -86,7 +86,7 @@ config ZCRYPT_MONOLITHIC
 config CRYPTO_SHA1_S390
        tristate "SHA1 digest algorithm"
        depends on S390
-       select CRYPTO_ALGAPI
+       select CRYPTO_HASH
        help
          This is the s390 hardware accelerated implementation of the
          SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
@@ -94,7 +94,7 @@ config CRYPTO_SHA1_S390
 config CRYPTO_SHA256_S390
        tristate "SHA256 digest algorithm"
        depends on S390
-       select CRYPTO_ALGAPI
+       select CRYPTO_HASH
        help
          This is the s390 hardware accelerated implementation of the
          SHA256 secure hash standard (DFIPS 180-2).
@@ -105,7 +105,7 @@ config CRYPTO_SHA256_S390
 config CRYPTO_SHA512_S390
        tristate "SHA384 and SHA512 digest algorithm"
        depends on S390
-       select CRYPTO_ALGAPI
+       select CRYPTO_HASH
        help
          This is the s390 hardware accelerated implementation of the
          SHA512 secure hash standard.
@@ -200,4 +200,13 @@ config CRYPTO_DEV_IXP4XX
        help
          Driver for the IXP4xx NPE crypto engine.
 
+config CRYPTO_DEV_PPC4XX
+       tristate "Driver AMCC PPC4xx crypto accelerator"
+       depends on PPC && 4xx
+       select CRYPTO_HASH
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       help
+         This option allows you to have support for AMCC crypto acceleration.
+
 endif # CRYPTO_HW
index 73557b2968d33710ae4c0a5745d6ac4bce0dedef..9bf4a2bc88461efdcbaca356a39728d84a9ca420 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
+obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
diff --git a/drivers/crypto/amcc/Makefile b/drivers/crypto/amcc/Makefile
new file mode 100644 (file)
index 0000000..aa376e8
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
+crypto4xx-objs :=  crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
new file mode 100644 (file)
index 0000000..61b6e1b
--- /dev/null
@@ -0,0 +1,293 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * This file implements the Linux crypto algorithms.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock_types.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <linux/hash.h>
+#include <crypto/internal/hash.h>
+#include <linux/dma-mapping.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include "crypto4xx_reg_def.h"
+#include "crypto4xx_sa.h"
+#include "crypto4xx_core.h"
+
+void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
+                             u32 save_iv, u32 ld_h, u32 ld_iv, u32 hdr_proc,
+                             u32 h, u32 c, u32 pad_type, u32 op_grp, u32 op,
+                             u32 dir)
+{
+       sa->sa_command_0.w = 0;
+       sa->sa_command_0.bf.save_hash_state = save_h;
+       sa->sa_command_0.bf.save_iv = save_iv;
+       sa->sa_command_0.bf.load_hash_state = ld_h;
+       sa->sa_command_0.bf.load_iv = ld_iv;
+       sa->sa_command_0.bf.hdr_proc = hdr_proc;
+       sa->sa_command_0.bf.hash_alg = h;
+       sa->sa_command_0.bf.cipher_alg = c;
+       sa->sa_command_0.bf.pad_type = pad_type & 3;
+       sa->sa_command_0.bf.extend_pad = pad_type >> 2;
+       sa->sa_command_0.bf.op_group = op_grp;
+       sa->sa_command_0.bf.opcode = op;
+       sa->sa_command_0.bf.dir = dir;
+}
+
+void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, u32 hmac_mc,
+                             u32 cfb, u32 esn, u32 sn_mask, u32 mute,
+                             u32 cp_pad, u32 cp_pay, u32 cp_hdr)
+{
+       sa->sa_command_1.w = 0;
+       sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2;
+       sa->sa_command_1.bf.crypto_mode9_8 = cm & 3;
+       sa->sa_command_1.bf.feedback_mode = cfb,
+       sa->sa_command_1.bf.sa_rev = 1;
+       sa->sa_command_1.bf.extended_seq_num = esn;
+       sa->sa_command_1.bf.seq_num_mask = sn_mask;
+       sa->sa_command_1.bf.mutable_bit_proc = mute;
+       sa->sa_command_1.bf.copy_pad = cp_pad;
+       sa->sa_command_1.bf.copy_payload = cp_pay;
+       sa->sa_command_1.bf.copy_hdr = cp_hdr;
+}
+
+int crypto4xx_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+       ctx->direction = DIR_OUTBOUND;
+       ctx->hash_final = 0;
+       ctx->is_hash = 0;
+       ctx->pd_ctl = 0x1;
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+                                 req->nbytes, req->info,
+                                 get_dynamic_sa_iv_size(ctx));
+}
+
+int crypto4xx_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+       ctx->direction = DIR_INBOUND;
+       ctx->hash_final = 0;
+       ctx->is_hash = 0;
+       ctx->pd_ctl = 1;
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+                                 req->nbytes, req->info,
+                                 get_dynamic_sa_iv_size(ctx));
+}
+
+/**
+ * AES Functions
+ */
+static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher,
+                               const u8 *key,
+                               unsigned int keylen,
+                               unsigned char cm,
+                               u8 fb)
+{
+       struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct dynamic_sa_ctl *sa;
+       int    rc;
+
+       if (keylen != AES_KEYSIZE_256 &&
+               keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_128) {
+               crypto_ablkcipher_set_flags(cipher,
+                               CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+
+       /* Create SA */
+       if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+               crypto4xx_free_sa(ctx);
+
+       rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4);
+       if (rc)
+               return rc;
+
+       if (ctx->state_record_dma_addr == 0) {
+               rc = crypto4xx_alloc_state_record(ctx);
+               if (rc) {
+                       crypto4xx_free_sa(ctx);
+                       return rc;
+               }
+       }
+       /* Setup SA */
+       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+       ctx->hash_final = 0;
+
+       set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
+                                SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
+                                SA_NO_HEADER_PROC, SA_HASH_ALG_NULL,
+                                SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO,
+                                SA_OP_GROUP_BASIC, SA_OPCODE_DECRYPT,
+                                DIR_INBOUND);
+
+       set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH,
+                                fb, SA_EXTENDED_SN_OFF,
+                                SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+                                SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+                                SA_NOT_COPY_HDR);
+       crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
+                           key, keylen);
+       sa->sa_contents = SA_AES_CONTENTS | (keylen << 2);
+       sa->sa_command_1.bf.key_len = keylen >> 3;
+       ctx->is_hash = 0;
+       ctx->direction = DIR_INBOUND;
+       memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
+                       (void *)&ctx->state_record_dma_addr, 4);
+       ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx);
+
+       memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
+       sa = (struct dynamic_sa_ctl *) ctx->sa_out;
+       sa->sa_command_0.bf.dir = DIR_OUTBOUND;
+
+       return 0;
+}
+
+int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC,
+                                   CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
+/**
+ * HASH SHA1 Functions
+ */
+static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
+                                  unsigned int sa_len,
+                                  unsigned char ha,
+                                  unsigned char hm)
+{
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg);
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct dynamic_sa_ctl *sa;
+       struct dynamic_sa_hash160 *sa_in;
+       int rc;
+
+       ctx->dev   = my_alg->dev;
+       ctx->is_hash = 1;
+       ctx->hash_final = 0;
+
+       /* Create SA */
+       if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+               crypto4xx_free_sa(ctx);
+
+       rc = crypto4xx_alloc_sa(ctx, sa_len);
+       if (rc)
+               return rc;
+
+       if (ctx->state_record_dma_addr == 0) {
+               crypto4xx_alloc_state_record(ctx);
+               if (!ctx->state_record_dma_addr) {
+                       crypto4xx_free_sa(ctx);
+                       return -ENOMEM;
+               }
+       }
+
+       tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
+       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+       set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+                                SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+                                SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
+                                SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+                                SA_OPCODE_HASH, DIR_INBOUND);
+       set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH,
+                                CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+                                SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+                                SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+                                SA_NOT_COPY_HDR);
+       ctx->direction = DIR_INBOUND;
+       sa->sa_contents = SA_HASH160_CONTENTS;
+       sa_in = (struct dynamic_sa_hash160 *) ctx->sa_in;
+       /* Need to zero hash digest in SA */
+       memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest));
+       memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest));
+       sa_in->state_ptr = ctx->state_record_dma_addr;
+       ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx);
+
+       return 0;
+}
+
+int crypto4xx_hash_init(struct ahash_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       int ds;
+       struct dynamic_sa_ctl *sa;
+
+       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+       ds = crypto_ahash_digestsize(
+                       __crypto_ahash_cast(req->base.tfm));
+       sa->sa_command_0.bf.digest_len = ds >> 2;
+       sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
+       ctx->is_hash = 1;
+       ctx->direction = DIR_INBOUND;
+
+       return 0;
+}
+
+int crypto4xx_hash_update(struct ahash_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+       ctx->is_hash = 1;
+       ctx->hash_final = 0;
+       ctx->pd_ctl = 0x11;
+       ctx->direction = DIR_INBOUND;
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src,
+                                 (struct scatterlist *) req->result,
+                                 req->nbytes, NULL, 0);
+}
+
+int crypto4xx_hash_final(struct ahash_request *req)
+{
+       return 0;
+}
+
+int crypto4xx_hash_digest(struct ahash_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+       ctx->hash_final = 1;
+       ctx->pd_ctl = 0x11;
+       ctx->direction = DIR_INBOUND;
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src,
+                                 (struct scatterlist *) req->result,
+                                 req->nbytes, NULL, 0);
+}
+
+/**
+ * SHA1 Algorithm
+ */
+int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
+{
+       return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
+                                      SA_HASH_MODE_HASH);
+}
+
+
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
new file mode 100644 (file)
index 0000000..4c0dfb2
--- /dev/null
@@ -0,0 +1,1310 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * This file implements AMCC crypto offload Linux device driver for use with
+ * Linux CryptoAPI.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock_types.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include <asm/cacheflush.h>
+#include <crypto/internal/hash.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include "crypto4xx_reg_def.h"
+#include "crypto4xx_core.h"
+#include "crypto4xx_sa.h"
+
+#define PPC4XX_SEC_VERSION_STR                 "0.5"
+
+/**
+ * PPC4xx Crypto Engine Initialization Routine
+ */
+static void crypto4xx_hw_init(struct crypto4xx_device *dev)
+{
+       union ce_ring_size ring_size;
+       union ce_ring_contol ring_ctrl;
+       union ce_part_ring_size part_ring_size;
+       union ce_io_threshold io_threshold;
+       u32 rand_num;
+       union ce_pe_dma_cfg pe_dma_cfg;
+
+       writel(PPC4XX_BYTE_ORDER, dev->ce_base + CRYPTO4XX_BYTE_ORDER_CFG);
+       /* setup pe dma, include reset sg, pdr and pe, then release reset */
+       pe_dma_cfg.w = 0;
+       pe_dma_cfg.bf.bo_sgpd_en = 1;
+       pe_dma_cfg.bf.bo_data_en = 0;
+       pe_dma_cfg.bf.bo_sa_en = 1;
+       pe_dma_cfg.bf.bo_pd_en = 1;
+       pe_dma_cfg.bf.dynamic_sa_en = 1;
+       pe_dma_cfg.bf.reset_sg = 1;
+       pe_dma_cfg.bf.reset_pdr = 1;
+       pe_dma_cfg.bf.reset_pe = 1;
+       writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);
+       /* un reset pe,sg and pdr */
+       pe_dma_cfg.bf.pe_mode = 0;
+       pe_dma_cfg.bf.reset_sg = 0;
+       pe_dma_cfg.bf.reset_pdr = 0;
+       pe_dma_cfg.bf.reset_pe = 0;
+       pe_dma_cfg.bf.bo_td_en = 0;
+       writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);
+       writel(dev->pdr_pa, dev->ce_base + CRYPTO4XX_PDR_BASE);
+       writel(dev->pdr_pa, dev->ce_base + CRYPTO4XX_RDR_BASE);
+       writel(PPC4XX_PRNG_CTRL_AUTO_EN, dev->ce_base + CRYPTO4XX_PRNG_CTRL);
+       get_random_bytes(&rand_num, sizeof(rand_num));
+       writel(rand_num, dev->ce_base + CRYPTO4XX_PRNG_SEED_L);
+       get_random_bytes(&rand_num, sizeof(rand_num));
+       writel(rand_num, dev->ce_base + CRYPTO4XX_PRNG_SEED_H);
+       ring_size.w = 0;
+       ring_size.bf.ring_offset = PPC4XX_PD_SIZE;
+       ring_size.bf.ring_size   = PPC4XX_NUM_PD;
+       writel(ring_size.w, dev->ce_base + CRYPTO4XX_RING_SIZE);
+       ring_ctrl.w = 0;
+       writel(ring_ctrl.w, dev->ce_base + CRYPTO4XX_RING_CTRL);
+       writel(PPC4XX_DC_3DES_EN, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+       writel(dev->gdr_pa, dev->ce_base + CRYPTO4XX_GATH_RING_BASE);
+       writel(dev->sdr_pa, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE);
+       part_ring_size.w = 0;
+       part_ring_size.bf.sdr_size = PPC4XX_SDR_SIZE;
+       part_ring_size.bf.gdr_size = PPC4XX_GDR_SIZE;
+       writel(part_ring_size.w, dev->ce_base + CRYPTO4XX_PART_RING_SIZE);
+       writel(PPC4XX_SD_BUFFER_SIZE, dev->ce_base + CRYPTO4XX_PART_RING_CFG);
+       io_threshold.w = 0;
+       io_threshold.bf.output_threshold = PPC4XX_OUTPUT_THRESHOLD;
+       io_threshold.bf.input_threshold  = PPC4XX_INPUT_THRESHOLD;
+       writel(io_threshold.w, dev->ce_base + CRYPTO4XX_IO_THRESHOLD);
+       writel(0, dev->ce_base + CRYPTO4XX_PDR_BASE_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_RDR_BASE_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_PKT_SRC_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_PKT_DEST_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_SA_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_GATH_RING_BASE_UADDR);
+       writel(0, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE_UADDR);
+       /* un reset pe,sg and pdr */
+       pe_dma_cfg.bf.pe_mode = 1;
+       pe_dma_cfg.bf.reset_sg = 0;
+       pe_dma_cfg.bf.reset_pdr = 0;
+       pe_dma_cfg.bf.reset_pe = 0;
+       pe_dma_cfg.bf.bo_td_en = 0;
+       writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);
+       /*clear all pending interrupt*/
+       writel(PPC4XX_INTERRUPT_CLR, dev->ce_base + CRYPTO4XX_INT_CLR);
+       writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT);
+       writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT);
+       writel(PPC4XX_INT_CFG, dev->ce_base + CRYPTO4XX_INT_CFG);
+       writel(PPC4XX_PD_DONE_INT, dev->ce_base + CRYPTO4XX_INT_EN);
+}
+
+int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size)
+{
+       ctx->sa_in = dma_alloc_coherent(ctx->dev->core_dev->device, size * 4,
+                                       &ctx->sa_in_dma_addr, GFP_ATOMIC);
+       if (ctx->sa_in == NULL)
+               return -ENOMEM;
+
+       ctx->sa_out = dma_alloc_coherent(ctx->dev->core_dev->device, size * 4,
+                                        &ctx->sa_out_dma_addr, GFP_ATOMIC);
+       if (ctx->sa_out == NULL) {
+               dma_free_coherent(ctx->dev->core_dev->device,
+                                 ctx->sa_len * 4,
+                                 ctx->sa_in, ctx->sa_in_dma_addr);
+               return -ENOMEM;
+       }
+
+       memset(ctx->sa_in, 0, size * 4);
+       memset(ctx->sa_out, 0, size * 4);
+       ctx->sa_len = size;
+
+       return 0;
+}
+
+void crypto4xx_free_sa(struct crypto4xx_ctx *ctx)
+{
+       if (ctx->sa_in != NULL)
+               dma_free_coherent(ctx->dev->core_dev->device, ctx->sa_len * 4,
+                                 ctx->sa_in, ctx->sa_in_dma_addr);
+       if (ctx->sa_out != NULL)
+               dma_free_coherent(ctx->dev->core_dev->device, ctx->sa_len * 4,
+                                 ctx->sa_out, ctx->sa_out_dma_addr);
+
+       ctx->sa_in_dma_addr = 0;
+       ctx->sa_out_dma_addr = 0;
+       ctx->sa_len = 0;
+}
+
+u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx)
+{
+       ctx->state_record = dma_alloc_coherent(ctx->dev->core_dev->device,
+                               sizeof(struct sa_state_record),
+                               &ctx->state_record_dma_addr, GFP_ATOMIC);
+       if (!ctx->state_record_dma_addr)
+               return -ENOMEM;
+       memset(ctx->state_record, 0, sizeof(struct sa_state_record));
+
+       return 0;
+}
+
+void crypto4xx_free_state_record(struct crypto4xx_ctx *ctx)
+{
+       if (ctx->state_record != NULL)
+               dma_free_coherent(ctx->dev->core_dev->device,
+                                 sizeof(struct sa_state_record),
+                                 ctx->state_record,
+                                 ctx->state_record_dma_addr);
+       ctx->state_record_dma_addr = 0;
+}
+
+/**
+ * alloc memory for the gather ring
+ * no need to alloc buf for the ring
+ * gdr_tail, gdr_head and gdr_count are initialized by this function
+ */
+static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)
+{
+       int i;
+       struct pd_uinfo *pd_uinfo;
+       dev->pdr = dma_alloc_coherent(dev->core_dev->device,
+                                     sizeof(struct ce_pd) * PPC4XX_NUM_PD,
+                                     &dev->pdr_pa, GFP_ATOMIC);
+       if (!dev->pdr)
+               return -ENOMEM;
+
+       dev->pdr_uinfo = kzalloc(sizeof(struct pd_uinfo) * PPC4XX_NUM_PD,
+                               GFP_KERNEL);
+       if (!dev->pdr_uinfo) {
+               dma_free_coherent(dev->core_dev->device,
+                                 sizeof(struct ce_pd) * PPC4XX_NUM_PD,
+                                 dev->pdr,
+                                 dev->pdr_pa);
+               return -ENOMEM;
+       }
+       memset(dev->pdr, 0,  sizeof(struct ce_pd) * PPC4XX_NUM_PD);
+       dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device,
+                                  256 * PPC4XX_NUM_PD,
+                                  &dev->shadow_sa_pool_pa,
+                                  GFP_ATOMIC);
+       if (!dev->shadow_sa_pool)
+               return -ENOMEM;
+
+       dev->shadow_sr_pool = dma_alloc_coherent(dev->core_dev->device,
+                        sizeof(struct sa_state_record) * PPC4XX_NUM_PD,
+                        &dev->shadow_sr_pool_pa, GFP_ATOMIC);
+       if (!dev->shadow_sr_pool)
+               return -ENOMEM;
+       for (i = 0; i < PPC4XX_NUM_PD; i++) {
+               pd_uinfo = (struct pd_uinfo *) (dev->pdr_uinfo +
+                                               sizeof(struct pd_uinfo) * i);
+
+               /* alloc 256 bytes which is enough for any kind of dynamic sa */
+               pd_uinfo->sa_va = dev->shadow_sa_pool + 256 * i;
+               pd_uinfo->sa_pa = dev->shadow_sa_pool_pa + 256 * i;
+
+               /* alloc state record */
+               pd_uinfo->sr_va = dev->shadow_sr_pool +
+                   sizeof(struct sa_state_record) * i;
+               pd_uinfo->sr_pa = dev->shadow_sr_pool_pa +
+                   sizeof(struct sa_state_record) * i;
+       }
+
+       return 0;
+}
+
+static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev)
+{
+       if (dev->pdr != NULL)
+               dma_free_coherent(dev->core_dev->device,
+                                 sizeof(struct ce_pd) * PPC4XX_NUM_PD,
+                                 dev->pdr, dev->pdr_pa);
+       if (dev->shadow_sa_pool)
+               dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD,
+                                 dev->shadow_sa_pool, dev->shadow_sa_pool_pa);
+       if (dev->shadow_sr_pool)
+               dma_free_coherent(dev->core_dev->device,
+                       sizeof(struct sa_state_record) * PPC4XX_NUM_PD,
+                       dev->shadow_sr_pool, dev->shadow_sr_pool_pa);
+
+       kfree(dev->pdr_uinfo);
+}
+
+static u32 crypto4xx_get_pd_from_pdr_nolock(struct crypto4xx_device *dev)
+{
+       u32 retval;
+       u32 tmp;
+
+       retval = dev->pdr_head;
+       tmp = (dev->pdr_head + 1) % PPC4XX_NUM_PD;
+
+       if (tmp == dev->pdr_tail)
+               return ERING_WAS_FULL;
+
+       dev->pdr_head = tmp;
+
+       return retval;
+}
+
+static u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx)
+{
+       struct pd_uinfo *pd_uinfo;
+       unsigned long flags;
+
+       pd_uinfo = (struct pd_uinfo *)(dev->pdr_uinfo +
+                                      sizeof(struct pd_uinfo) * idx);
+       spin_lock_irqsave(&dev->core_dev->lock, flags);
+       if (dev->pdr_tail != PPC4XX_LAST_PD)
+               dev->pdr_tail++;
+       else
+               dev->pdr_tail = 0;
+       pd_uinfo->state = PD_ENTRY_FREE;
+       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+
+       return 0;
+}
+
+static struct ce_pd *crypto4xx_get_pdp(struct crypto4xx_device *dev,
+                                      dma_addr_t *pd_dma, u32 idx)
+{
+       *pd_dma = dev->pdr_pa + sizeof(struct ce_pd) * idx;
+
+       return dev->pdr + sizeof(struct ce_pd) * idx;
+}
+
+/**
+ * alloc memory for the gather ring
+ * no need to alloc buf for the ring
+ * gdr_tail, gdr_head and gdr_count are initialized by this function
+ */
+static u32 crypto4xx_build_gdr(struct crypto4xx_device *dev)
+{
+       dev->gdr = dma_alloc_coherent(dev->core_dev->device,
+                                     sizeof(struct ce_gd) * PPC4XX_NUM_GD,
+                                     &dev->gdr_pa, GFP_ATOMIC);
+       if (!dev->gdr)
+               return -ENOMEM;
+
+       memset(dev->gdr, 0, sizeof(struct ce_gd) * PPC4XX_NUM_GD);
+
+       return 0;
+}
+
+static inline void crypto4xx_destroy_gdr(struct crypto4xx_device *dev)
+{
+       dma_free_coherent(dev->core_dev->device,
+                         sizeof(struct ce_gd) * PPC4XX_NUM_GD,
+                         dev->gdr, dev->gdr_pa);
+}
+
+/*
+ * when this function is called.
+ * preemption or interrupt must be disabled
+ */
+u32 crypto4xx_get_n_gd(struct crypto4xx_device *dev, int n)
+{
+       u32 retval;
+       u32 tmp;
+       if (n >= PPC4XX_NUM_GD)
+               return ERING_WAS_FULL;
+
+       retval = dev->gdr_head;
+       tmp = (dev->gdr_head + n) % PPC4XX_NUM_GD;
+       if (dev->gdr_head > dev->gdr_tail) {
+               if (tmp < dev->gdr_head && tmp >= dev->gdr_tail)
+                       return ERING_WAS_FULL;
+       } else if (dev->gdr_head < dev->gdr_tail) {
+               if (tmp < dev->gdr_head || tmp >= dev->gdr_tail)
+                       return ERING_WAS_FULL;
+       }
+       dev->gdr_head = tmp;
+
+       return retval;
+}
+
+static u32 crypto4xx_put_gd_to_gdr(struct crypto4xx_device *dev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->core_dev->lock, flags);
+       if (dev->gdr_tail == dev->gdr_head) {
+               spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+               return 0;
+       }
+
+       if (dev->gdr_tail != PPC4XX_LAST_GD)
+               dev->gdr_tail++;
+       else
+               dev->gdr_tail = 0;
+
+       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+
+       return 0;
+}
+
+static inline struct ce_gd *crypto4xx_get_gdp(struct crypto4xx_device *dev,
+                                             dma_addr_t *gd_dma, u32 idx)
+{
+       *gd_dma = dev->gdr_pa + sizeof(struct ce_gd) * idx;
+
+       return (struct ce_gd *) (dev->gdr + sizeof(struct ce_gd) * idx);
+}
+
+/**
+ * alloc memory for the scatter ring
+ * need to alloc buf for the ring
+ * sdr_tail, sdr_head and sdr_count are initialized by this function
+ */
+static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev)
+{
+       int i;
+       struct ce_sd *sd_array;
+
+       /* alloc memory for scatter descriptor ring */
+       dev->sdr = dma_alloc_coherent(dev->core_dev->device,
+                                     sizeof(struct ce_sd) * PPC4XX_NUM_SD,
+                                     &dev->sdr_pa, GFP_ATOMIC);
+       if (!dev->sdr)
+               return -ENOMEM;
+
+       dev->scatter_buffer_size = PPC4XX_SD_BUFFER_SIZE;
+       dev->scatter_buffer_va =
+               dma_alloc_coherent(dev->core_dev->device,
+                       dev->scatter_buffer_size * PPC4XX_NUM_SD,
+                       &dev->scatter_buffer_pa, GFP_ATOMIC);
+       if (!dev->scatter_buffer_va) {
+               dma_free_coherent(dev->core_dev->device,
+                                 sizeof(struct ce_sd) * PPC4XX_NUM_SD,
+                                 dev->sdr, dev->sdr_pa);
+               return -ENOMEM;
+       }
+
+       sd_array = dev->sdr;
+
+       for (i = 0; i < PPC4XX_NUM_SD; i++) {
+               sd_array[i].ptr = dev->scatter_buffer_pa +
+                                 dev->scatter_buffer_size * i;
+       }
+
+       return 0;
+}
+
+static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev)
+{
+       if (dev->sdr != NULL)
+               dma_free_coherent(dev->core_dev->device,
+                                 sizeof(struct ce_sd) * PPC4XX_NUM_SD,
+                                 dev->sdr, dev->sdr_pa);
+
+       if (dev->scatter_buffer_va != NULL)
+               dma_free_coherent(dev->core_dev->device,
+                                 dev->scatter_buffer_size * PPC4XX_NUM_SD,
+                                 dev->scatter_buffer_va,
+                                 dev->scatter_buffer_pa);
+}
+
+/*
+ * when this function is called.
+ * preemption or interrupt must be disabled
+ */
+static u32 crypto4xx_get_n_sd(struct crypto4xx_device *dev, int n)
+{
+       u32 retval;
+       u32 tmp;
+
+       if (n >= PPC4XX_NUM_SD)
+               return ERING_WAS_FULL;
+
+       retval = dev->sdr_head;
+       tmp = (dev->sdr_head + n) % PPC4XX_NUM_SD;
+       if (dev->sdr_head > dev->gdr_tail) {
+               if (tmp < dev->sdr_head && tmp >= dev->sdr_tail)
+                       return ERING_WAS_FULL;
+       } else if (dev->sdr_head < dev->sdr_tail) {
+               if (tmp < dev->sdr_head || tmp >= dev->sdr_tail)
+                       return ERING_WAS_FULL;
+       } /* the head = tail, or empty case is already take cared */
+       dev->sdr_head = tmp;
+
+       return retval;
+}
+
+static u32 crypto4xx_put_sd_to_sdr(struct crypto4xx_device *dev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->core_dev->lock, flags);
+       if (dev->sdr_tail == dev->sdr_head) {
+               spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+               return 0;
+       }
+       if (dev->sdr_tail != PPC4XX_LAST_SD)
+               dev->sdr_tail++;
+       else
+               dev->sdr_tail = 0;
+       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+
+       return 0;
+}
+
+static inline struct ce_sd *crypto4xx_get_sdp(struct crypto4xx_device *dev,
+                                             dma_addr_t *sd_dma, u32 idx)
+{
+       *sd_dma = dev->sdr_pa + sizeof(struct ce_sd) * idx;
+
+       return  (struct ce_sd *)(dev->sdr + sizeof(struct ce_sd) * idx);
+}
+
+static u32 crypto4xx_fill_one_page(struct crypto4xx_device *dev,
+                                  dma_addr_t *addr, u32 *length,
+                                  u32 *idx, u32 *offset, u32 *nbytes)
+{
+       u32 len;
+
+       if (*length > dev->scatter_buffer_size) {
+               memcpy(phys_to_virt(*addr),
+                       dev->scatter_buffer_va +
+                       *idx * dev->scatter_buffer_size + *offset,
+                       dev->scatter_buffer_size);
+               *offset = 0;
+               *length -= dev->scatter_buffer_size;
+               *nbytes -= dev->scatter_buffer_size;
+               if (*idx == PPC4XX_LAST_SD)
+                       *idx = 0;
+               else
+                       (*idx)++;
+               *addr = *addr +  dev->scatter_buffer_size;
+               return 1;
+       } else if (*length < dev->scatter_buffer_size) {
+               memcpy(phys_to_virt(*addr),
+                       dev->scatter_buffer_va +
+                       *idx * dev->scatter_buffer_size + *offset, *length);
+               if ((*offset + *length) == dev->scatter_buffer_size) {
+                       if (*idx == PPC4XX_LAST_SD)
+                               *idx = 0;
+                       else
+                               (*idx)++;
+                       *nbytes -= *length;
+                       *offset = 0;
+               } else {
+                       *nbytes -= *length;
+                       *offset += *length;
+               }
+
+               return 0;
+       } else {
+               len = (*nbytes <= dev->scatter_buffer_size) ?
+                               (*nbytes) : dev->scatter_buffer_size;
+               memcpy(phys_to_virt(*addr),
+                       dev->scatter_buffer_va +
+                       *idx * dev->scatter_buffer_size + *offset,
+                       len);
+               *offset = 0;
+               *nbytes -= len;
+
+               if (*idx == PPC4XX_LAST_SD)
+                       *idx = 0;
+               else
+                       (*idx)++;
+
+               return 0;
+    }
+}
+
+static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
+                                     struct ce_pd *pd,
+                                     struct pd_uinfo *pd_uinfo,
+                                     u32 nbytes,
+                                     struct scatterlist *dst)
+{
+       dma_addr_t addr;
+       u32 this_sd;
+       u32 offset;
+       u32 len;
+       u32 i;
+       u32 sg_len;
+       struct scatterlist *sg;
+
+       this_sd = pd_uinfo->first_sd;
+       offset = 0;
+       i = 0;
+
+       while (nbytes) {
+               sg = &dst[i];
+               sg_len = sg->length;
+               addr = dma_map_page(dev->core_dev->device, sg_page(sg),
+                               sg->offset, sg->length, DMA_TO_DEVICE);
+
+               if (offset == 0) {
+                       len = (nbytes <= sg->length) ? nbytes : sg->length;
+                       while (crypto4xx_fill_one_page(dev, &addr, &len,
+                               &this_sd, &offset, &nbytes))
+                               ;
+                       if (!nbytes)
+                               return;
+                       i++;
+               } else {
+                       len = (nbytes <= (dev->scatter_buffer_size - offset)) ?
+                               nbytes : (dev->scatter_buffer_size - offset);
+                       len = (sg->length < len) ? sg->length : len;
+                       while (crypto4xx_fill_one_page(dev, &addr, &len,
+                                              &this_sd, &offset, &nbytes))
+                               ;
+                       if (!nbytes)
+                               return;
+                       sg_len -= len;
+                       if (sg_len) {
+                               addr += len;
+                               while (crypto4xx_fill_one_page(dev, &addr,
+                                       &sg_len, &this_sd, &offset, &nbytes))
+                                       ;
+                       }
+                       i++;
+               }
+       }
+}
+
+static u32 crypto4xx_copy_digest_to_dst(struct pd_uinfo *pd_uinfo,
+                                       struct crypto4xx_ctx *ctx)
+{
+       struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+       struct sa_state_record *state_record =
+                               (struct sa_state_record *) pd_uinfo->sr_va;
+
+       if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
+               memcpy((void *) pd_uinfo->dest_va, state_record->save_digest,
+                      SA_HASH_ALG_SHA1_DIGEST_SIZE);
+       }
+
+       return 0;
+}
+
+static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
+                                 struct pd_uinfo *pd_uinfo)
+{
+       int i;
+       if (pd_uinfo->num_gd) {
+               for (i = 0; i < pd_uinfo->num_gd; i++)
+                       crypto4xx_put_gd_to_gdr(dev);
+               pd_uinfo->first_gd = 0xffffffff;
+               pd_uinfo->num_gd = 0;
+       }
+       if (pd_uinfo->num_sd) {
+               for (i = 0; i < pd_uinfo->num_sd; i++)
+                       crypto4xx_put_sd_to_sdr(dev);
+
+               pd_uinfo->first_sd = 0xffffffff;
+               pd_uinfo->num_sd = 0;
+       }
+}
+
+static u32 crypto4xx_ablkcipher_done(struct crypto4xx_device *dev,
+                                    struct pd_uinfo *pd_uinfo,
+                                    struct ce_pd *pd)
+{
+       struct crypto4xx_ctx *ctx;
+       struct ablkcipher_request *ablk_req;
+       struct scatterlist *dst;
+       dma_addr_t addr;
+
+       ablk_req = ablkcipher_request_cast(pd_uinfo->async_req);
+       ctx  = crypto_tfm_ctx(ablk_req->base.tfm);
+
+       if (pd_uinfo->using_sd) {
+               crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo, ablk_req->nbytes,
+                                         ablk_req->dst);
+       } else {
+               dst = pd_uinfo->dest_va;
+               addr = dma_map_page(dev->core_dev->device, sg_page(dst),
+                                   dst->offset, dst->length, DMA_FROM_DEVICE);
+       }
+       crypto4xx_ret_sg_desc(dev, pd_uinfo);
+       if (ablk_req->base.complete != NULL)
+               ablk_req->base.complete(&ablk_req->base, 0);
+
+       return 0;
+}
+
+static u32 crypto4xx_ahash_done(struct crypto4xx_device *dev,
+                               struct pd_uinfo *pd_uinfo)
+{
+       struct crypto4xx_ctx *ctx;
+       struct ahash_request *ahash_req;
+
+       ahash_req = ahash_request_cast(pd_uinfo->async_req);
+       ctx  = crypto_tfm_ctx(ahash_req->base.tfm);
+
+       crypto4xx_copy_digest_to_dst(pd_uinfo,
+                                    crypto_tfm_ctx(ahash_req->base.tfm));
+       crypto4xx_ret_sg_desc(dev, pd_uinfo);
+       /* call user provided callback function x */
+       if (ahash_req->base.complete != NULL)
+               ahash_req->base.complete(&ahash_req->base, 0);
+
+       return 0;
+}
+
+static u32 crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+{
+       struct ce_pd *pd;
+       struct pd_uinfo *pd_uinfo;
+
+       pd =  dev->pdr + sizeof(struct ce_pd)*idx;
+       pd_uinfo = dev->pdr_uinfo + sizeof(struct pd_uinfo)*idx;
+       if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) ==
+                       CRYPTO_ALG_TYPE_ABLKCIPHER)
+               return crypto4xx_ablkcipher_done(dev, pd_uinfo, pd);
+       else
+               return crypto4xx_ahash_done(dev, pd_uinfo);
+}
+
+/**
+ * Note: Only use this function to copy items that is word aligned.
+ */
+void crypto4xx_memcpy_le(unsigned int *dst,
+                        const unsigned char *buf,
+                        int len)
+{
+       u8 *tmp;
+       for (; len >= 4; buf += 4, len -= 4)
+               *dst++ = cpu_to_le32(*(unsigned int *) buf);
+
+       tmp = (u8 *)dst;
+       switch (len) {
+       case 3:
+               *tmp++ = 0;
+               *tmp++ = *(buf+2);
+               *tmp++ = *(buf+1);
+               *tmp++ = *buf;
+               break;
+       case 2:
+               *tmp++ = 0;
+               *tmp++ = 0;
+               *tmp++ = *(buf+1);
+               *tmp++ = *buf;
+               break;
+       case 1:
+               *tmp++ = 0;
+               *tmp++ = 0;
+               *tmp++ = 0;
+               *tmp++ = *buf;
+               break;
+       default:
+               break;
+       }
+}
+
+static void crypto4xx_stop_all(struct crypto4xx_core_device *core_dev)
+{
+       crypto4xx_destroy_pdr(core_dev->dev);
+       crypto4xx_destroy_gdr(core_dev->dev);
+       crypto4xx_destroy_sdr(core_dev->dev);
+       dev_set_drvdata(core_dev->device, NULL);
+       iounmap(core_dev->dev->ce_base);
+       kfree(core_dev->dev);
+       kfree(core_dev);
+}
+
+void crypto4xx_return_pd(struct crypto4xx_device *dev,
+                        u32 pd_entry, struct ce_pd *pd,
+                        struct pd_uinfo *pd_uinfo)
+{
+       /* irq should be already disabled */
+       dev->pdr_head = pd_entry;
+       pd->pd_ctl.w = 0;
+       pd->pd_ctl_len.w = 0;
+       pd_uinfo->state = PD_ENTRY_FREE;
+}
+
+/*
+ * derive number of elements in scatterlist
+ * Shamlessly copy from talitos.c
+ */
+static int get_sg_count(struct scatterlist *sg_list, int nbytes)
+{
+       struct scatterlist *sg = sg_list;
+       int sg_nents = 0;
+
+       while (nbytes) {
+               sg_nents++;
+               if (sg->length > nbytes)
+                       break;
+               nbytes -= sg->length;
+               sg = sg_next(sg);
+       }
+
+       return sg_nents;
+}
+
+static u32 get_next_gd(u32 current)
+{
+       if (current != PPC4XX_LAST_GD)
+               return current + 1;
+       else
+               return 0;
+}
+
+static u32 get_next_sd(u32 current)
+{
+       if (current != PPC4XX_LAST_SD)
+               return current + 1;
+       else
+               return 0;
+}
+
+u32 crypto4xx_build_pd(struct crypto_async_request *req,
+                      struct crypto4xx_ctx *ctx,
+                      struct scatterlist *src,
+                      struct scatterlist *dst,
+                      unsigned int datalen,
+                      void *iv, u32 iv_len)
+{
+       struct crypto4xx_device *dev = ctx->dev;
+       dma_addr_t addr, pd_dma, sd_dma, gd_dma;
+       struct dynamic_sa_ctl *sa;
+       struct scatterlist *sg;
+       struct ce_gd *gd;
+       struct ce_pd *pd;
+       u32 num_gd, num_sd;
+       u32 fst_gd = 0xffffffff;
+       u32 fst_sd = 0xffffffff;
+       u32 pd_entry;
+       unsigned long flags;
+       struct pd_uinfo *pd_uinfo = NULL;
+       unsigned int nbytes = datalen, idx;
+       unsigned int ivlen = 0;
+       u32 gd_idx = 0;
+
+       /* figure how many gd is needed */
+       num_gd = get_sg_count(src, datalen);
+       if (num_gd == 1)
+               num_gd = 0;
+
+       /* figure how many sd is needed */
+       if (sg_is_last(dst) || ctx->is_hash) {
+               num_sd = 0;
+       } else {
+               if (datalen > PPC4XX_SD_BUFFER_SIZE) {
+                       num_sd = datalen / PPC4XX_SD_BUFFER_SIZE;
+                       if (datalen % PPC4XX_SD_BUFFER_SIZE)
+                               num_sd++;
+               } else {
+                       num_sd = 1;
+               }
+       }
+
+       /*
+        * The follow section of code needs to be protected
+        * The gather ring and scatter ring needs to be consecutive
+        * In case of run out of any kind of descriptor, the descriptor
+        * already got must be return the original place.
+        */
+       spin_lock_irqsave(&dev->core_dev->lock, flags);
+       if (num_gd) {
+               fst_gd = crypto4xx_get_n_gd(dev, num_gd);
+               if (fst_gd == ERING_WAS_FULL) {
+                       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+                       return -EAGAIN;
+               }
+       }
+       if (num_sd) {
+               fst_sd = crypto4xx_get_n_sd(dev, num_sd);
+               if (fst_sd == ERING_WAS_FULL) {
+                       if (num_gd)
+                               dev->gdr_head = fst_gd;
+                       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+                       return -EAGAIN;
+               }
+       }
+       pd_entry = crypto4xx_get_pd_from_pdr_nolock(dev);
+       if (pd_entry == ERING_WAS_FULL) {
+               if (num_gd)
+                       dev->gdr_head = fst_gd;
+               if (num_sd)
+                       dev->sdr_head = fst_sd;
+               spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+               return -EAGAIN;
+       }
+       spin_unlock_irqrestore(&dev->core_dev->lock, flags);
+
+       pd_uinfo = (struct pd_uinfo *)(dev->pdr_uinfo +
+                                      sizeof(struct pd_uinfo) * pd_entry);
+       pd = crypto4xx_get_pdp(dev, &pd_dma, pd_entry);
+       pd_uinfo->async_req = req;
+       pd_uinfo->num_gd = num_gd;
+       pd_uinfo->num_sd = num_sd;
+
+       if (iv_len || ctx->is_hash) {
+               ivlen = iv_len;
+               pd->sa = pd_uinfo->sa_pa;
+               sa = (struct dynamic_sa_ctl *) pd_uinfo->sa_va;
+               if (ctx->direction == DIR_INBOUND)
+                       memcpy(sa, ctx->sa_in, ctx->sa_len * 4);
+               else
+                       memcpy(sa, ctx->sa_out, ctx->sa_len * 4);
+
+               memcpy((void *) sa + ctx->offset_to_sr_ptr,
+                       &pd_uinfo->sr_pa, 4);
+
+               if (iv_len)
+                       crypto4xx_memcpy_le(pd_uinfo->sr_va, iv, iv_len);
+       } else {
+               if (ctx->direction == DIR_INBOUND) {
+                       pd->sa = ctx->sa_in_dma_addr;
+                       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+               } else {
+                       pd->sa = ctx->sa_out_dma_addr;
+                       sa = (struct dynamic_sa_ctl *) ctx->sa_out;
+               }
+       }
+       pd->sa_len = ctx->sa_len;
+       if (num_gd) {
+               /* get first gd we are going to use */
+               gd_idx = fst_gd;
+               pd_uinfo->first_gd = fst_gd;
+               pd_uinfo->num_gd = num_gd;
+               gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
+               pd->src = gd_dma;
+               /* enable gather */
+               sa->sa_command_0.bf.gather = 1;
+               idx = 0;
+               src = &src[0];
+               /* walk the sg, and setup gather array */
+               while (nbytes) {
+                       sg = &src[idx];
+                       addr = dma_map_page(dev->core_dev->device, sg_page(sg),
+                                   sg->offset, sg->length, DMA_TO_DEVICE);
+                       gd->ptr = addr;
+                       gd->ctl_len.len = sg->length;
+                       gd->ctl_len.done = 0;
+                       gd->ctl_len.ready = 1;
+                       if (sg->length >= nbytes)
+                               break;
+                       nbytes -= sg->length;
+                       gd_idx = get_next_gd(gd_idx);
+                       gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);
+                       idx++;
+               }
+       } else {
+               pd->src = (u32)dma_map_page(dev->core_dev->device, sg_page(src),
+                               src->offset, src->length, DMA_TO_DEVICE);
+               /*
+                * Disable gather in sa command
+                */
+               sa->sa_command_0.bf.gather = 0;
+               /*
+                * Indicate gather array is not used
+                */
+               pd_uinfo->first_gd = 0xffffffff;
+               pd_uinfo->num_gd = 0;
+       }
+       if (ctx->is_hash || sg_is_last(dst)) {
+               /*
+                * we know application give us dst a whole piece of memory
+                * no need to use scatter ring.
+                * In case of is_hash, the icv is always at end of src data.
+                */
+               pd_uinfo->using_sd = 0;
+               pd_uinfo->first_sd = 0xffffffff;
+               pd_uinfo->num_sd = 0;
+               pd_uinfo->dest_va = dst;
+               sa->sa_command_0.bf.scatter = 0;
+               if (ctx->is_hash)
+                       pd->dest = virt_to_phys((void *)dst);
+               else
+                       pd->dest = (u32)dma_map_page(dev->core_dev->device,
+                                       sg_page(dst), dst->offset,
+                                       dst->length, DMA_TO_DEVICE);
+       } else {
+               struct ce_sd *sd = NULL;
+               u32 sd_idx = fst_sd;
+               nbytes = datalen;
+               sa->sa_command_0.bf.scatter = 1;
+               pd_uinfo->using_sd = 1;
+               pd_uinfo->dest_va = dst;
+               pd_uinfo->first_sd = fst_sd;
+               pd_uinfo->num_sd = num_sd;
+               sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);
+               pd->dest = sd_dma;
+               /* setup scatter descriptor */
+               sd->ctl.done = 0;
+               sd->ctl.rdy = 1;
+               /* sd->ptr should be setup by sd_init routine*/
+               idx = 0;
+               if (nbytes >= PPC4XX_SD_BUFFER_SIZE)
+                       nbytes -= PPC4XX_SD_BUFFER_SIZE;
+               else
+                       nbytes = 0;
+               while (nbytes) {
+                       sd_idx = get_next_sd(sd_idx);
+                       sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);
+                       /* setup scatter descriptor */
+                       sd->ctl.done = 0;
+                       sd->ctl.rdy = 1;
+                       if (nbytes >= PPC4XX_SD_BUFFER_SIZE)
+                               nbytes -= PPC4XX_SD_BUFFER_SIZE;
+                       else
+                               /*
+                                * SD entry can hold PPC4XX_SD_BUFFER_SIZE,
+                                * which is more than nbytes, so done.
+                                */
+                               nbytes = 0;
+               }
+       }
+
+       sa->sa_command_1.bf.hash_crypto_offset = 0;
+       pd->pd_ctl.w = ctx->pd_ctl;
+       pd->pd_ctl_len.w = 0x00400000 | (ctx->bypass << 24) | datalen;
+       pd_uinfo->state = PD_ENTRY_INUSE;
+       wmb();
+       /* write any value to push engine to read a pd */
+       writel(1, dev->ce_base + CRYPTO4XX_INT_DESCR_RD);
+       return -EINPROGRESS;
+}
+
+/**
+ * Algorithm Registration Functions
+ */
+static int crypto4xx_alg_init(struct crypto_tfm *tfm)
+{
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct crypto4xx_alg *amcc_alg = crypto_alg_to_crypto4xx_alg(alg);
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->dev = amcc_alg->dev;
+       ctx->sa_in = NULL;
+       ctx->sa_out = NULL;
+       ctx->sa_in_dma_addr = 0;
+       ctx->sa_out_dma_addr = 0;
+       ctx->sa_len = 0;
+
+       if (alg->cra_type == &crypto_ablkcipher_type)
+               tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx);
+       else if (alg->cra_type == &crypto_ahash_type)
+               tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
+
+       return 0;
+}
+
+static void crypto4xx_alg_exit(struct crypto_tfm *tfm)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto4xx_free_sa(ctx);
+       crypto4xx_free_state_record(ctx);
+}
+
+int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+                          struct crypto_alg *crypto_alg, int array_size)
+{
+       struct crypto4xx_alg *alg;
+       int i;
+       int rc = 0;
+
+       for (i = 0; i < array_size; i++) {
+               alg = kzalloc(sizeof(struct crypto4xx_alg), GFP_KERNEL);
+               if (!alg)
+                       return -ENOMEM;
+
+               alg->alg = crypto_alg[i];
+               INIT_LIST_HEAD(&alg->alg.cra_list);
+               if (alg->alg.cra_init == NULL)
+                       alg->alg.cra_init = crypto4xx_alg_init;
+               if (alg->alg.cra_exit == NULL)
+                       alg->alg.cra_exit = crypto4xx_alg_exit;
+               alg->dev = sec_dev;
+               rc = crypto_register_alg(&alg->alg);
+               if (rc) {
+                       list_del(&alg->entry);
+                       kfree(alg);
+               } else {
+                       list_add_tail(&alg->entry, &sec_dev->alg_list);
+               }
+       }
+
+       return 0;
+}
+
+static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+{
+       struct crypto4xx_alg *alg, *tmp;
+
+       list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
+               list_del(&alg->entry);
+               crypto_unregister_alg(&alg->alg);
+               kfree(alg);
+       }
+}
+
+static void crypto4xx_bh_tasklet_cb(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
+       struct pd_uinfo *pd_uinfo;
+       struct ce_pd *pd;
+       u32 tail;
+
+       while (core_dev->dev->pdr_head != core_dev->dev->pdr_tail) {
+               tail = core_dev->dev->pdr_tail;
+               pd_uinfo = core_dev->dev->pdr_uinfo +
+                       sizeof(struct pd_uinfo)*tail;
+               pd =  core_dev->dev->pdr + sizeof(struct ce_pd) * tail;
+               if ((pd_uinfo->state == PD_ENTRY_INUSE) &&
+                                  pd->pd_ctl.bf.pe_done &&
+                                  !pd->pd_ctl.bf.host_ready) {
+                       pd->pd_ctl.bf.pe_done = 0;
+                       crypto4xx_pd_done(core_dev->dev, tail);
+                       crypto4xx_put_pd_to_pdr(core_dev->dev, tail);
+                       pd_uinfo->state = PD_ENTRY_FREE;
+               } else {
+                       /* if tail not done, break */
+                       break;
+               }
+       }
+}
+
+/**
+ * Top Half of isr.
+ */
+static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data)
+{
+       struct device *dev = (struct device *)data;
+       struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
+
+       if (core_dev->dev->ce_base == 0)
+               return 0;
+
+       writel(PPC4XX_INTERRUPT_CLR,
+              core_dev->dev->ce_base + CRYPTO4XX_INT_CLR);
+       tasklet_schedule(&core_dev->tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * Supported Crypto Algorithms
+ */
+struct crypto_alg crypto4xx_alg[] = {
+       /* Crypto AES modes */
+       {
+               .cra_name       = "cbc(aes)",
+               .cra_driver_name = "cbc-aes-ppc4xx",
+               .cra_priority   = CRYPTO4XX_CRYPTO_PRIORITY,
+               .cra_flags      = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_ctxsize    = sizeof(struct crypto4xx_ctx),
+               .cra_alignmask  = 0,
+               .cra_type       = &crypto_ablkcipher_type,
+               .cra_module     = THIS_MODULE,
+               .cra_u          = {
+                       .ablkcipher = {
+                               .min_keysize    = AES_MIN_KEY_SIZE,
+                               .max_keysize    = AES_MAX_KEY_SIZE,
+                               .ivsize         = AES_IV_SIZE,
+                               .setkey         = crypto4xx_setkey_aes_cbc,
+                               .encrypt        = crypto4xx_encrypt,
+                               .decrypt        = crypto4xx_decrypt,
+                       }
+               }
+       },
+       /* Hash SHA1 */
+       {
+               .cra_name       = "sha1",
+               .cra_driver_name = "sha1-ppc4xx",
+               .cra_priority   = CRYPTO4XX_CRYPTO_PRIORITY,
+               .cra_flags      = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+               .cra_blocksize  = SHA1_BLOCK_SIZE,
+               .cra_ctxsize    = sizeof(struct crypto4xx_ctx),
+               .cra_alignmask  = 0,
+               .cra_type       = &crypto_ahash_type,
+               .cra_init       = crypto4xx_sha1_alg_init,
+               .cra_module     = THIS_MODULE,
+               .cra_u          = {
+                       .ahash = {
+                               .digestsize     = SHA1_DIGEST_SIZE,
+                               .init           = crypto4xx_hash_init,
+                               .update         = crypto4xx_hash_update,
+                               .final          = crypto4xx_hash_final,
+                               .digest         = crypto4xx_hash_digest,
+                       }
+               }
+       },
+};
+
+/**
+ * Module Initialization Routine
+ */
+static int __init crypto4xx_probe(struct of_device *ofdev,
+                                 const struct of_device_id *match)
+{
+       int rc;
+       struct resource res;
+       struct device *dev = &ofdev->dev;
+       struct crypto4xx_core_device *core_dev;
+
+       rc = of_address_to_resource(ofdev->node, 0, &res);
+       if (rc)
+               return -ENODEV;
+
+       if (of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-crypto")) {
+               mtdcri(SDR0, PPC460EX_SDR0_SRST,
+                      mfdcri(SDR0, PPC460EX_SDR0_SRST) | PPC460EX_CE_RESET);
+               mtdcri(SDR0, PPC460EX_SDR0_SRST,
+                      mfdcri(SDR0, PPC460EX_SDR0_SRST) & ~PPC460EX_CE_RESET);
+       } else if (of_find_compatible_node(NULL, NULL,
+                       "amcc,ppc405ex-crypto")) {
+               mtdcri(SDR0, PPC405EX_SDR0_SRST,
+                      mfdcri(SDR0, PPC405EX_SDR0_SRST) | PPC405EX_CE_RESET);
+               mtdcri(SDR0, PPC405EX_SDR0_SRST,
+                      mfdcri(SDR0, PPC405EX_SDR0_SRST) & ~PPC405EX_CE_RESET);
+       } else if (of_find_compatible_node(NULL, NULL,
+                       "amcc,ppc460sx-crypto")) {
+               mtdcri(SDR0, PPC460SX_SDR0_SRST,
+                      mfdcri(SDR0, PPC460SX_SDR0_SRST) | PPC460SX_CE_RESET);
+               mtdcri(SDR0, PPC460SX_SDR0_SRST,
+                      mfdcri(SDR0, PPC460SX_SDR0_SRST) & ~PPC460SX_CE_RESET);
+       } else {
+               printk(KERN_ERR "Crypto Function Not supported!\n");
+               return -EINVAL;
+       }
+
+       core_dev = kzalloc(sizeof(struct crypto4xx_core_device), GFP_KERNEL);
+       if (!core_dev)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, core_dev);
+       core_dev->ofdev = ofdev;
+       core_dev->dev = kzalloc(sizeof(struct crypto4xx_device), GFP_KERNEL);
+       if (!core_dev->dev)
+               goto err_alloc_dev;
+
+       core_dev->dev->core_dev = core_dev;
+       core_dev->device = dev;
+       spin_lock_init(&core_dev->lock);
+       INIT_LIST_HEAD(&core_dev->dev->alg_list);
+       rc = crypto4xx_build_pdr(core_dev->dev);
+       if (rc)
+               goto err_build_pdr;
+
+       rc = crypto4xx_build_gdr(core_dev->dev);
+       if (rc)
+               goto err_build_gdr;
+
+       rc = crypto4xx_build_sdr(core_dev->dev);
+       if (rc)
+               goto err_build_sdr;
+
+       /* Init tasklet for bottom half processing */
+       tasklet_init(&core_dev->tasklet, crypto4xx_bh_tasklet_cb,
+                    (unsigned long) dev);
+
+       /* Register for Crypto isr, Crypto Engine IRQ */
+       core_dev->irq = irq_of_parse_and_map(ofdev->node, 0);
+       rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0,
+                        core_dev->dev->name, dev);
+       if (rc)
+               goto err_request_irq;
+
+       core_dev->dev->ce_base = of_iomap(ofdev->node, 0);
+       if (!core_dev->dev->ce_base) {
+               dev_err(dev, "failed to of_iomap\n");
+               goto err_iomap;
+       }
+
+       /* need to setup pdr, rdr, gdr and sdr before this */
+       crypto4xx_hw_init(core_dev->dev);
+
+       /* Register security algorithms with Linux CryptoAPI */
+       rc = crypto4xx_register_alg(core_dev->dev, crypto4xx_alg,
+                              ARRAY_SIZE(crypto4xx_alg));
+       if (rc)
+               goto err_start_dev;
+
+       return 0;
+
+err_start_dev:
+       iounmap(core_dev->dev->ce_base);
+err_iomap:
+       free_irq(core_dev->irq, dev);
+       irq_dispose_mapping(core_dev->irq);
+       tasklet_kill(&core_dev->tasklet);
+err_request_irq:
+       crypto4xx_destroy_sdr(core_dev->dev);
+err_build_sdr:
+       crypto4xx_destroy_gdr(core_dev->dev);
+err_build_gdr:
+       crypto4xx_destroy_pdr(core_dev->dev);
+err_build_pdr:
+       kfree(core_dev->dev);
+err_alloc_dev:
+       kfree(core_dev);
+
+       return rc;
+}
+
+static int __exit crypto4xx_remove(struct of_device *ofdev)
+{
+       struct device *dev = &ofdev->dev;
+       struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
+
+       free_irq(core_dev->irq, dev);
+       irq_dispose_mapping(core_dev->irq);
+
+       tasklet_kill(&core_dev->tasklet);
+       /* Un-register with Linux CryptoAPI */
+       crypto4xx_unregister_alg(core_dev->dev);
+       /* Free all allocated memory */
+       crypto4xx_stop_all(core_dev);
+
+       return 0;
+}
+
+static struct of_device_id crypto4xx_match[] = {
+       { .compatible      = "amcc,ppc4xx-crypto",},
+       { },
+};
+
+static struct of_platform_driver crypto4xx_driver = {
+       .name           = "crypto4xx",
+       .match_table    = crypto4xx_match,
+       .probe          = crypto4xx_probe,
+       .remove         = crypto4xx_remove,
+};
+
+static int __init crypto4xx_init(void)
+{
+       return of_register_platform_driver(&crypto4xx_driver);
+}
+
+static void __exit crypto4xx_exit(void)
+{
+       of_unregister_platform_driver(&crypto4xx_driver);
+}
+
+module_init(crypto4xx_init);
+module_exit(crypto4xx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
+MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
+
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
new file mode 100644 (file)
index 0000000..1ef1034
--- /dev/null
@@ -0,0 +1,177 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * This is the header file for AMCC Crypto offload Linux device driver for
+ * use with Linux CryptoAPI.
+
+ */
+
+#ifndef __CRYPTO4XX_CORE_H__
+#define __CRYPTO4XX_CORE_H__
+
+#define PPC460SX_SDR0_SRST                      0x201
+#define PPC405EX_SDR0_SRST                      0x200
+#define PPC460EX_SDR0_SRST                      0x201
+#define PPC460EX_CE_RESET                       0x08000000
+#define PPC460SX_CE_RESET                       0x20000000
+#define PPC405EX_CE_RESET                       0x00000008
+
+#define CRYPTO4XX_CRYPTO_PRIORITY              300
+#define PPC4XX_LAST_PD                         63
+#define PPC4XX_NUM_PD                          64
+#define PPC4XX_LAST_GD                         1023
+#define PPC4XX_NUM_GD                          1024
+#define PPC4XX_LAST_SD                         63
+#define PPC4XX_NUM_SD                          64
+#define PPC4XX_SD_BUFFER_SIZE                  2048
+
+#define PD_ENTRY_INUSE                         1
+#define PD_ENTRY_FREE                          0
+#define ERING_WAS_FULL                         0xffffffff
+
+struct crypto4xx_device;
+
+struct pd_uinfo {
+       struct crypto4xx_device *dev;
+       u32   state;
+       u32 using_sd;
+       u32 first_gd;           /* first gather discriptor
+                               used by this packet */
+       u32 num_gd;             /* number of gather discriptor
+                               used by this packet */
+       u32 first_sd;           /* first scatter discriptor
+                               used by this packet */
+       u32 num_sd;             /* number of scatter discriptors
+                               used by this packet */
+       void *sa_va;            /* shadow sa, when using cp from ctx->sa */
+       u32 sa_pa;
+       void *sr_va;            /* state record for shadow sa */
+       u32 sr_pa;
+       struct scatterlist *dest_va;
+       struct crypto_async_request *async_req;         /* base crypto request
+                                                       for this packet */
+};
+
+struct crypto4xx_device {
+       struct crypto4xx_core_device *core_dev;
+       char *name;
+       u64  ce_phy_address;
+       void __iomem *ce_base;
+
+       void *pdr;                      /* base address of packet
+                                       descriptor ring */
+       dma_addr_t pdr_pa;              /* physical address used to
+                                       program ce pdr_base_register */
+       void *gdr;                      /* gather descriptor ring */
+       dma_addr_t gdr_pa;              /* physical address used to
+                                       program ce gdr_base_register */
+       void *sdr;                      /* scatter descriptor ring */
+       dma_addr_t sdr_pa;              /* physical address used to
+                                       program ce sdr_base_register */
+       void *scatter_buffer_va;
+       dma_addr_t scatter_buffer_pa;
+       u32 scatter_buffer_size;
+
+       void *shadow_sa_pool;           /* pool of memory for sa in pd_uinfo */
+       dma_addr_t shadow_sa_pool_pa;
+       void *shadow_sr_pool;           /* pool of memory for sr in pd_uinfo */
+       dma_addr_t shadow_sr_pool_pa;
+       u32 pdr_tail;
+       u32 pdr_head;
+       u32 gdr_tail;
+       u32 gdr_head;
+       u32 sdr_tail;
+       u32 sdr_head;
+       void *pdr_uinfo;
+       struct list_head alg_list;      /* List of algorithm supported
+                                       by this device */
+};
+
+struct crypto4xx_core_device {
+       struct device *device;
+       struct of_device *ofdev;
+       struct crypto4xx_device *dev;
+       u32 int_status;
+       u32 irq;
+       struct tasklet_struct tasklet;
+       spinlock_t lock;
+};
+
+struct crypto4xx_ctx {
+       struct crypto4xx_device *dev;
+       void *sa_in;
+       dma_addr_t sa_in_dma_addr;
+       void *sa_out;
+       dma_addr_t sa_out_dma_addr;
+       void *state_record;
+       dma_addr_t state_record_dma_addr;
+       u32 sa_len;
+       u32 offset_to_sr_ptr;           /* offset to state ptr, in dynamic sa */
+       u32 direction;
+       u32 next_hdr;
+       u32 save_iv;
+       u32 pd_ctl_len;
+       u32 pd_ctl;
+       u32 bypass;
+       u32 is_hash;
+       u32 hash_final;
+};
+
+struct crypto4xx_req_ctx {
+       struct crypto4xx_device *dev;   /* Device in which
+                                       operation to send to */
+       void *sa;
+       u32 sa_dma_addr;
+       u16 sa_len;
+};
+
+struct crypto4xx_alg {
+       struct list_head  entry;
+       struct crypto_alg alg;
+       struct crypto4xx_device *dev;
+};
+
+#define crypto_alg_to_crypto4xx_alg(x) \
+               container_of(x, struct crypto4xx_alg, alg)
+
+extern int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size);
+extern void crypto4xx_free_sa(struct crypto4xx_ctx *ctx);
+extern u32 crypto4xx_alloc_sa_rctx(struct crypto4xx_ctx *ctx,
+                                  struct crypto4xx_ctx *rctx);
+extern void crypto4xx_free_sa_rctx(struct crypto4xx_ctx *rctx);
+extern void crypto4xx_free_ctx(struct crypto4xx_ctx *ctx);
+extern u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx);
+extern u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx);
+extern u32 get_dynamic_sa_offset_key_field(struct crypto4xx_ctx *ctx);
+extern u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx);
+extern void crypto4xx_memcpy_le(unsigned int *dst,
+                               const unsigned char *buf, int len);
+extern u32 crypto4xx_build_pd(struct crypto_async_request *req,
+                             struct crypto4xx_ctx *ctx,
+                             struct scatterlist *src,
+                             struct scatterlist *dst,
+                             unsigned int datalen,
+                             void *iv, u32 iv_len);
+extern int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
+                                   const u8 *key, unsigned int keylen);
+extern int crypto4xx_encrypt(struct ablkcipher_request *req);
+extern int crypto4xx_decrypt(struct ablkcipher_request *req);
+extern int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+extern int crypto4xx_hash_digest(struct ahash_request *req);
+extern int crypto4xx_hash_final(struct ahash_request *req);
+extern int crypto4xx_hash_update(struct ahash_request *req);
+extern int crypto4xx_hash_init(struct ahash_request *req);
+#endif
diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
new file mode 100644 (file)
index 0000000..7d4edb0
--- /dev/null
@@ -0,0 +1,284 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * This filr defines the register set for Security Subsystem
+ */
+
+#ifndef __CRYPTO4XX_REG_DEF_H__
+#define __CRYPTO4XX_REG_DEF_H__
+
+/* CRYPTO4XX Register offset */
+#define CRYPTO4XX_DESCRIPTOR                   0x00000000
+#define CRYPTO4XX_CTRL_STAT                    0x00000000
+#define CRYPTO4XX_SOURCE                       0x00000004
+#define CRYPTO4XX_DEST                         0x00000008
+#define CRYPTO4XX_SA                           0x0000000C
+#define CRYPTO4XX_SA_LENGTH                    0x00000010
+#define CRYPTO4XX_LENGTH                       0x00000014
+
+#define CRYPTO4XX_PE_DMA_CFG                   0x00000040
+#define CRYPTO4XX_PE_DMA_STAT                  0x00000044
+#define CRYPTO4XX_PDR_BASE                     0x00000048
+#define CRYPTO4XX_RDR_BASE                     0x0000004c
+#define CRYPTO4XX_RING_SIZE                    0x00000050
+#define CRYPTO4XX_RING_CTRL                    0x00000054
+#define CRYPTO4XX_INT_RING_STAT                        0x00000058
+#define CRYPTO4XX_EXT_RING_STAT                        0x0000005c
+#define CRYPTO4XX_IO_THRESHOLD                 0x00000060
+#define CRYPTO4XX_GATH_RING_BASE               0x00000064
+#define CRYPTO4XX_SCAT_RING_BASE               0x00000068
+#define CRYPTO4XX_PART_RING_SIZE               0x0000006c
+#define CRYPTO4XX_PART_RING_CFG                        0x00000070
+
+#define CRYPTO4XX_PDR_BASE_UADDR               0x00000080
+#define CRYPTO4XX_RDR_BASE_UADDR               0x00000084
+#define CRYPTO4XX_PKT_SRC_UADDR                        0x00000088
+#define CRYPTO4XX_PKT_DEST_UADDR               0x0000008c
+#define CRYPTO4XX_SA_UADDR                     0x00000090
+#define CRYPTO4XX_GATH_RING_BASE_UADDR         0x000000A0
+#define CRYPTO4XX_SCAT_RING_BASE_UADDR         0x000000A4
+
+#define CRYPTO4XX_SEQ_RD                       0x00000408
+#define CRYPTO4XX_SEQ_MASK_RD                  0x0000040C
+
+#define CRYPTO4XX_SA_CMD_0                     0x00010600
+#define CRYPTO4XX_SA_CMD_1                     0x00010604
+
+#define CRYPTO4XX_STATE_PTR                    0x000106dc
+#define CRYPTO4XX_STATE_IV                     0x00010700
+#define CRYPTO4XX_STATE_HASH_BYTE_CNT_0                0x00010710
+#define CRYPTO4XX_STATE_HASH_BYTE_CNT_1                0x00010714
+
+#define CRYPTO4XX_STATE_IDIGEST_0              0x00010718
+#define CRYPTO4XX_STATE_IDIGEST_1              0x0001071c
+
+#define CRYPTO4XX_DATA_IN                      0x00018000
+#define CRYPTO4XX_DATA_OUT                     0x0001c000
+
+#define CRYPTO4XX_INT_UNMASK_STAT              0x000500a0
+#define CRYPTO4XX_INT_MASK_STAT                        0x000500a4
+#define CRYPTO4XX_INT_CLR                      0x000500a4
+#define CRYPTO4XX_INT_EN                       0x000500a8
+
+#define CRYPTO4XX_INT_PKA                      0x00000002
+#define CRYPTO4XX_INT_PDR_DONE                 0x00008000
+#define CRYPTO4XX_INT_MA_WR_ERR                        0x00020000
+#define CRYPTO4XX_INT_MA_RD_ERR                        0x00010000
+#define CRYPTO4XX_INT_PE_ERR                   0x00000200
+#define CRYPTO4XX_INT_USER_DMA_ERR             0x00000040
+#define CRYPTO4XX_INT_SLAVE_ERR                        0x00000010
+#define CRYPTO4XX_INT_MASTER_ERR               0x00000008
+#define CRYPTO4XX_INT_ERROR                    0x00030258
+
+#define CRYPTO4XX_INT_CFG                      0x000500ac
+#define CRYPTO4XX_INT_DESCR_RD                 0x000500b0
+#define CRYPTO4XX_INT_DESCR_CNT                        0x000500b4
+#define CRYPTO4XX_INT_TIMEOUT_CNT              0x000500b8
+
+#define CRYPTO4XX_DEVICE_CTRL                  0x00060080
+#define CRYPTO4XX_DEVICE_ID                    0x00060084
+#define CRYPTO4XX_DEVICE_INFO                  0x00060088
+#define CRYPTO4XX_DMA_USER_SRC                 0x00060094
+#define CRYPTO4XX_DMA_USER_DEST                        0x00060098
+#define CRYPTO4XX_DMA_USER_CMD                 0x0006009C
+
+#define CRYPTO4XX_DMA_CFG                      0x000600d4
+#define CRYPTO4XX_BYTE_ORDER_CFG               0x000600d8
+#define CRYPTO4XX_ENDIAN_CFG                   0x000600d8
+
+#define CRYPTO4XX_PRNG_STAT                    0x00070000
+#define CRYPTO4XX_PRNG_CTRL                    0x00070004
+#define CRYPTO4XX_PRNG_SEED_L                  0x00070008
+#define CRYPTO4XX_PRNG_SEED_H                  0x0007000c
+
+#define CRYPTO4XX_PRNG_RES_0                   0x00070020
+#define CRYPTO4XX_PRNG_RES_1                   0x00070024
+#define CRYPTO4XX_PRNG_RES_2                   0x00070028
+#define CRYPTO4XX_PRNG_RES_3                   0x0007002C
+
+#define CRYPTO4XX_PRNG_LFSR_L                  0x00070030
+#define CRYPTO4XX_PRNG_LFSR_H                  0x00070034
+
+/**
+ * Initilize CRYPTO ENGINE registers, and memory bases.
+ */
+#define PPC4XX_PDR_POLL                                0x3ff
+#define PPC4XX_OUTPUT_THRESHOLD                        2
+#define PPC4XX_INPUT_THRESHOLD                 2
+#define PPC4XX_PD_SIZE                         6
+#define PPC4XX_CTX_DONE_INT                    0x2000
+#define PPC4XX_PD_DONE_INT                     0x8000
+#define PPC4XX_BYTE_ORDER                      0x22222
+#define PPC4XX_INTERRUPT_CLR                   0x3ffff
+#define PPC4XX_PRNG_CTRL_AUTO_EN               0x3
+#define PPC4XX_DC_3DES_EN                      1
+#define PPC4XX_INT_DESCR_CNT                   4
+#define PPC4XX_INT_TIMEOUT_CNT                 0
+#define PPC4XX_INT_CFG                         1
+/**
+ * all follow define are ad hoc
+ */
+#define PPC4XX_RING_RETRY                      100
+#define PPC4XX_RING_POLL                       100
+#define PPC4XX_SDR_SIZE                                PPC4XX_NUM_SD
+#define PPC4XX_GDR_SIZE                                PPC4XX_NUM_GD
+
+/**
+  * Generic Security Association (SA) with all possible fields. These will
+ * never likely used except for reference purpose. These structure format
+ * can be not changed as the hardware expects them to be layout as defined.
+ * Field can be removed or reduced but ordering can not be changed.
+ */
+#define CRYPTO4XX_DMA_CFG_OFFSET               0x40
+union ce_pe_dma_cfg {
+       struct {
+               u32 rsv:7;
+               u32 dir_host:1;
+               u32 rsv1:2;
+               u32 bo_td_en:1;
+               u32 dis_pdr_upd:1;
+               u32 bo_sgpd_en:1;
+               u32 bo_data_en:1;
+               u32 bo_sa_en:1;
+               u32 bo_pd_en:1;
+               u32 rsv2:4;
+               u32 dynamic_sa_en:1;
+               u32 pdr_mode:2;
+               u32 pe_mode:1;
+               u32 rsv3:5;
+               u32 reset_sg:1;
+               u32 reset_pdr:1;
+               u32 reset_pe:1;
+       } bf;
+    u32 w;
+} __attribute__((packed));
+
+#define CRYPTO4XX_PDR_BASE_OFFSET              0x48
+#define CRYPTO4XX_RDR_BASE_OFFSET              0x4c
+#define CRYPTO4XX_RING_SIZE_OFFSET             0x50
+union ce_ring_size {
+       struct {
+               u32 ring_offset:16;
+               u32 rsv:6;
+               u32 ring_size:10;
+       } bf;
+    u32 w;
+} __attribute__((packed));
+
+#define CRYPTO4XX_RING_CONTROL_OFFSET          0x54
+union ce_ring_contol {
+       struct {
+               u32 continuous:1;
+               u32 rsv:5;
+               u32 ring_retry_divisor:10;
+               u32 rsv1:4;
+               u32 ring_poll_divisor:10;
+       } bf;
+    u32 w;
+} __attribute__((packed));
+
+#define CRYPTO4XX_IO_THRESHOLD_OFFSET          0x60
+union ce_io_threshold {
+       struct {
+               u32 rsv:6;
+               u32 output_threshold:10;
+               u32 rsv1:6;
+               u32 input_threshold:10;
+       } bf;
+    u32 w;
+} __attribute__((packed));
+
+#define CRYPTO4XX_GATHER_RING_BASE_OFFSET      0x64
+#define CRYPTO4XX_SCATTER_RING_BASE_OFFSET     0x68
+
+union ce_part_ring_size  {
+       struct {
+               u32 sdr_size:16;
+               u32 gdr_size:16;
+       } bf;
+    u32 w;
+} __attribute__((packed));
+
+#define MAX_BURST_SIZE_32                      0
+#define MAX_BURST_SIZE_64                      1
+#define MAX_BURST_SIZE_128                     2
+#define MAX_BURST_SIZE_256                     3
+
+/* gather descriptor control length */
+struct gd_ctl_len {
+       u32 len:16;
+       u32 rsv:14;
+       u32 done:1;
+       u32 ready:1;
+} __attribute__((packed));
+
+struct ce_gd {
+       u32 ptr;
+       struct gd_ctl_len ctl_len;
+} __attribute__((packed));
+
+struct sd_ctl {
+       u32 ctl:30;
+       u32 done:1;
+       u32 rdy:1;
+} __attribute__((packed));
+
+struct ce_sd {
+    u32 ptr;
+       struct sd_ctl ctl;
+} __attribute__((packed));
+
+#define PD_PAD_CTL_32  0x10
+#define PD_PAD_CTL_64  0x20
+#define PD_PAD_CTL_128 0x40
+#define PD_PAD_CTL_256 0x80
+union ce_pd_ctl {
+       struct {
+               u32 pd_pad_ctl:8;
+               u32 status:8;
+               u32 next_hdr:8;
+               u32 rsv:2;
+               u32 cached_sa:1;
+               u32 hash_final:1;
+               u32 init_arc4:1;
+               u32 rsv1:1;
+               u32 pe_done:1;
+               u32 host_ready:1;
+       } bf;
+       u32 w;
+} __attribute__((packed));
+
+union ce_pd_ctl_len {
+       struct {
+               u32 bypass:8;
+               u32 pe_done:1;
+               u32 host_ready:1;
+               u32 rsv:2;
+               u32 pkt_len:20;
+       } bf;
+       u32 w;
+} __attribute__((packed));
+
+struct ce_pd {
+       union ce_pd_ctl   pd_ctl;
+       u32 src;
+       u32 dest;
+       u32 sa;                 /* get from ctx->sa_dma_addr */
+       u32 sa_len;             /* only if dynamic sa is used */
+       union ce_pd_ctl_len pd_ctl_len;
+
+} __attribute__((packed));
+#endif
diff --git a/drivers/crypto/amcc/crypto4xx_sa.c b/drivers/crypto/amcc/crypto4xx_sa.c
new file mode 100644 (file)
index 0000000..466fd94
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * @file crypto4xx_sa.c
+ *
+ * This file implements the security context
+ * assoicate format.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock_types.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+#include "crypto4xx_reg_def.h"
+#include "crypto4xx_sa.h"
+#include "crypto4xx_core.h"
+
+u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx *ctx)
+{
+       u32 offset;
+       union dynamic_sa_contents cts;
+
+       if (ctx->direction == DIR_INBOUND)
+               cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
+       else
+               cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
+       offset = cts.bf.key_size
+               + cts.bf.inner_size
+               + cts.bf.outer_size
+               + cts.bf.spi
+               + cts.bf.seq_num0
+               + cts.bf.seq_num1
+               + cts.bf.seq_num_mask0
+               + cts.bf.seq_num_mask1
+               + cts.bf.seq_num_mask2
+               + cts.bf.seq_num_mask3;
+
+       return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx)
+{
+       u32 offset;
+       union dynamic_sa_contents cts;
+
+       if (ctx->direction == DIR_INBOUND)
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
+       else
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
+       offset = cts.bf.key_size
+               + cts.bf.inner_size
+               + cts.bf.outer_size
+               + cts.bf.spi
+               + cts.bf.seq_num0
+               + cts.bf.seq_num1
+               + cts.bf.seq_num_mask0
+               + cts.bf.seq_num_mask1
+               + cts.bf.seq_num_mask2
+               + cts.bf.seq_num_mask3
+               + cts.bf.iv0
+               + cts.bf.iv1
+               + cts.bf.iv2
+               + cts.bf.iv3;
+
+       return sizeof(struct dynamic_sa_ctl) + offset * 4;
+}
+
+u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx *ctx)
+{
+       union dynamic_sa_contents cts;
+
+       if (ctx->direction == DIR_INBOUND)
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
+       else
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
+       return (cts.bf.iv0 + cts.bf.iv1 + cts.bf.iv2 + cts.bf.iv3) * 4;
+}
+
+u32 get_dynamic_sa_offset_key_field(struct crypto4xx_ctx *ctx)
+{
+       union dynamic_sa_contents cts;
+
+       if (ctx->direction == DIR_INBOUND)
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
+       else
+               cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
+
+       return sizeof(struct dynamic_sa_ctl);
+}
diff --git a/drivers/crypto/amcc/crypto4xx_sa.h b/drivers/crypto/amcc/crypto4xx_sa.h
new file mode 100644 (file)
index 0000000..4b83ed7
--- /dev/null
@@ -0,0 +1,243 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
+ *
+ * This file defines the security context
+ * assoicate format.
+ */
+
+#ifndef __CRYPTO4XX_SA_H__
+#define __CRYPTO4XX_SA_H__
+
+#define AES_IV_SIZE                            16
+
+/**
+ * Contents of Dynamic Security Association (SA) with all possible fields
+ */
+union dynamic_sa_contents {
+       struct {
+               u32 arc4_state_ptr:1;
+               u32 arc4_ij_ptr:1;
+               u32 state_ptr:1;
+               u32 iv3:1;
+               u32 iv2:1;
+               u32 iv1:1;
+               u32 iv0:1;
+               u32 seq_num_mask3:1;
+               u32 seq_num_mask2:1;
+               u32 seq_num_mask1:1;
+               u32 seq_num_mask0:1;
+               u32 seq_num1:1;
+               u32 seq_num0:1;
+               u32 spi:1;
+               u32 outer_size:5;
+               u32 inner_size:5;
+               u32 key_size:4;
+               u32 cmd_size:4;
+       } bf;
+       u32 w;
+} __attribute__((packed));
+
+#define DIR_OUTBOUND                           0
+#define DIR_INBOUND                            1
+#define SA_OP_GROUP_BASIC                      0
+#define SA_OPCODE_ENCRYPT                      0
+#define SA_OPCODE_DECRYPT                      0
+#define SA_OPCODE_HASH                         3
+#define SA_CIPHER_ALG_DES                      0
+#define SA_CIPHER_ALG_3DES                     1
+#define SA_CIPHER_ALG_ARC4                     2
+#define SA_CIPHER_ALG_AES                      3
+#define SA_CIPHER_ALG_KASUMI                   4
+#define SA_CIPHER_ALG_NULL                     15
+
+#define SA_HASH_ALG_MD5                                0
+#define SA_HASH_ALG_SHA1                       1
+#define SA_HASH_ALG_NULL                       15
+#define SA_HASH_ALG_SHA1_DIGEST_SIZE           20
+
+#define SA_LOAD_HASH_FROM_SA                   0
+#define SA_LOAD_HASH_FROM_STATE                        2
+#define SA_NOT_LOAD_HASH                       3
+#define SA_LOAD_IV_FROM_SA                     0
+#define SA_LOAD_IV_FROM_INPUT                  1
+#define SA_LOAD_IV_FROM_STATE                  2
+#define SA_LOAD_IV_GEN_IV                      3
+
+#define SA_PAD_TYPE_CONSTANT                   2
+#define SA_PAD_TYPE_ZERO                       3
+#define SA_PAD_TYPE_TLS                                5
+#define SA_PAD_TYPE_DTLS                       5
+#define SA_NOT_SAVE_HASH                       0
+#define SA_SAVE_HASH                           1
+#define SA_NOT_SAVE_IV                         0
+#define SA_SAVE_IV                             1
+#define SA_HEADER_PROC                         1
+#define SA_NO_HEADER_PROC                      0
+
+union sa_command_0 {
+       struct {
+               u32 scatter:1;
+               u32 gather:1;
+               u32 save_hash_state:1;
+               u32 save_iv:1;
+               u32 load_hash_state:2;
+               u32 load_iv:2;
+               u32 digest_len:4;
+               u32 hdr_proc:1;
+               u32 extend_pad:1;
+               u32 stream_cipher_pad:1;
+               u32 rsv:1;
+               u32 hash_alg:4;
+               u32 cipher_alg:4;
+               u32 pad_type:2;
+               u32 op_group:2;
+               u32 dir:1;
+               u32 opcode:3;
+       } bf;
+       u32 w;
+} __attribute__((packed));
+
+#define CRYPTO_MODE_ECB                                0
+#define CRYPTO_MODE_CBC                                1
+
+#define CRYPTO_FEEDBACK_MODE_NO_FB             0
+#define CRYPTO_FEEDBACK_MODE_64BIT_OFB         0
+#define CRYPTO_FEEDBACK_MODE_8BIT_CFB          1
+#define CRYPTO_FEEDBACK_MODE_1BIT_CFB          2
+#define CRYPTO_FEEDBACK_MODE_128BIT_CFB                3
+
+#define SA_AES_KEY_LEN_128                     2
+#define SA_AES_KEY_LEN_192                     3
+#define SA_AES_KEY_LEN_256                     4
+
+#define SA_REV2                                        1
+/**
+ * The follow defines bits sa_command_1
+ * In Basic hash mode  this bit define simple hash or hmac.
+ * In IPsec mode, this bit define muting control.
+ */
+#define SA_HASH_MODE_HASH                      0
+#define SA_HASH_MODE_HMAC                      1
+#define SA_MC_ENABLE                           0
+#define SA_MC_DISABLE                          1
+#define SA_NOT_COPY_HDR                                0
+#define SA_COPY_HDR                            1
+#define SA_NOT_COPY_PAD                                0
+#define SA_COPY_PAD                            1
+#define SA_NOT_COPY_PAYLOAD                    0
+#define SA_COPY_PAYLOAD                                1
+#define SA_EXTENDED_SN_OFF                     0
+#define SA_EXTENDED_SN_ON                      1
+#define SA_SEQ_MASK_OFF                                0
+#define SA_SEQ_MASK_ON                         1
+
+union sa_command_1 {
+       struct {
+               u32 crypto_mode31:1;
+               u32 save_arc4_state:1;
+               u32 arc4_stateful:1;
+               u32 key_len:5;
+               u32 hash_crypto_offset:8;
+               u32 sa_rev:2;
+               u32 byte_offset:1;
+               u32 hmac_muting:1;
+               u32 feedback_mode:2;
+               u32 crypto_mode9_8:2;
+               u32 extended_seq_num:1;
+               u32 seq_num_mask:1;
+               u32 mutable_bit_proc:1;
+               u32 ip_version:1;
+               u32 copy_pad:1;
+               u32 copy_payload:1;
+               u32 copy_hdr:1;
+               u32 rsv1:1;
+       } bf;
+       u32 w;
+} __attribute__((packed));
+
+struct dynamic_sa_ctl {
+       u32 sa_contents;
+       union sa_command_0 sa_command_0;
+       union sa_command_1 sa_command_1;
+} __attribute__((packed));
+
+/**
+ * State Record for Security Association (SA)
+ */
+struct  sa_state_record {
+       u32 save_iv[4];
+       u32 save_hash_byte_cnt[2];
+       u32 save_digest[16];
+} __attribute__((packed));
+
+/**
+ * Security Association (SA) for AES128
+ *
+ */
+struct dynamic_sa_aes128 {
+       struct dynamic_sa_ctl   ctrl;
+       u32 key[4];
+       u32 iv[4]; /* for CBC, OFC, and CFB mode */
+       u32 state_ptr;
+       u32 reserved;
+} __attribute__((packed));
+
+#define SA_AES128_LEN          (sizeof(struct dynamic_sa_aes128)/4)
+#define SA_AES128_CONTENTS     0x3e000042
+
+/*
+ * Security Association (SA) for AES192
+ */
+struct dynamic_sa_aes192 {
+       struct dynamic_sa_ctl ctrl;
+       u32 key[6];
+       u32 iv[4]; /* for CBC, OFC, and CFB mode */
+       u32 state_ptr;
+       u32 reserved;
+} __attribute__((packed));
+
+#define SA_AES192_LEN          (sizeof(struct dynamic_sa_aes192)/4)
+#define SA_AES192_CONTENTS     0x3e000062
+
+/**
+ * Security Association (SA) for AES256
+ */
+struct dynamic_sa_aes256 {
+       struct dynamic_sa_ctl ctrl;
+       u32 key[8];
+       u32 iv[4]; /* for CBC, OFC, and CFB mode */
+       u32 state_ptr;
+       u32 reserved;
+} __attribute__((packed));
+
+#define SA_AES256_LEN          (sizeof(struct dynamic_sa_aes256)/4)
+#define SA_AES256_CONTENTS     0x3e000082
+#define SA_AES_CONTENTS                0x3e000002
+
+/**
+ * Security Association (SA) for HASH160: HMAC-SHA1
+ */
+struct dynamic_sa_hash160 {
+       struct dynamic_sa_ctl ctrl;
+       u32 inner_digest[5];
+       u32 outer_digest[5];
+       u32 state_ptr;
+       u32 reserved;
+} __attribute__((packed));
+#define SA_HASH160_LEN         (sizeof(struct dynamic_sa_hash160)/4)
+#define SA_HASH160_CONTENTS     0x2000a502
+
+#endif
index 10c3c498358c0d27b0bbfa3c979f77f4841758be..55dd88d82d6d541bfe463b12927406ec0a57cb41 100644 (file)
@@ -182,7 +182,7 @@ static int __init dio_init(void)
 
        /* Initialize the DIO bus */ 
        INIT_LIST_HEAD(&dio_bus.devices);
-       strcpy(dio_bus.dev.bus_id, "dio");
+       dev_set_name(&dio_bus.dev, "dio");
        error = device_register(&dio_bus.dev);
        if (error) {
                pr_err("DIO: Error registering dio_bus\n");
@@ -237,7 +237,7 @@ static int __init dio_init(void)
                dev->scode = scode;
                dev->resource.start = pa;
                dev->resource.end = pa + DIO_SIZE(scode, va);
-               sprintf(dev->dev.bus_id,"%02x", scode);
+               dev_set_name(&dev->dev, "%02x", scode);
 
                 /* read the ID byte(s) and encode if necessary. */
                prid = DIO_ID(va);
index a97c07eef7ec92468c24150669e690033f310a4f..20ad3d26bec2d5330ac40bd8b437475009e0d8f0 100644 (file)
@@ -1011,7 +1011,7 @@ static int __init dw_probe(struct platform_device *pdev)
        dma_writel(dw, CFG, DW_CFG_DMA_EN);
 
        printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n",
-                       pdev->dev.bus_id, dw->dma.chancnt);
+                       dev_name(&pdev->dev), dw->dma.chancnt);
 
        dma_async_device_register(&dw->dma);
 
index 24f3ca85152351ac8d5234f05fc3c6f81d9354dc..cb0f639f049d4d8cb3e69d052d5dbd78b8c1b317 100644 (file)
@@ -198,7 +198,7 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
        mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        mci->mod_name = "cell_edac";
        mci->ctl_name = "MIC";
-       mci->dev_name = pdev->dev.bus_id;
+       mci->dev_name = dev_name(&pdev->dev);
        mci->edac_check = cell_edac_check;
        cell_edac_init_csrows(mci);
 
index 853ef37ec00662a894a7d6caa6c889823b8a0ce8..4637a4a757df65f29144d13b60d82f4dea3671c8 100644 (file)
@@ -218,7 +218,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
        pci->dev = &op->dev;
        pci->mod_name = EDAC_MOD_STR;
        pci->ctl_name = pdata->name;
-       pci->dev_name = op->dev.bus_id;
+       pci->dev_name = dev_name(&op->dev);
 
        if (edac_op_state == EDAC_OPSTATE_POLL)
                pci->edac_check = mpc85xx_pci_check;
index 083ce8d0c63d78c009c45588e55ac9c85ac665c4..5131aaae8e03787d0c3e237f3cbac85b77453880 100644 (file)
@@ -121,7 +121,7 @@ static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
        pdata->irq = NO_IRQ;
        platform_set_drvdata(pdev, pci);
        pci->dev = &pdev->dev;
-       pci->dev_name = pdev->dev.bus_id;
+       pci->dev_name = dev_name(&pdev->dev);
        pci->mod_name = EDAC_MOD_STR;
        pci->ctl_name = pdata->name;
 
@@ -294,7 +294,7 @@ static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
        pdata->irq = NO_IRQ;
        edac_dev->dev = &pdev->dev;
        platform_set_drvdata(pdev, edac_dev);
-       edac_dev->dev_name = pdev->dev.bus_id;
+       edac_dev->dev_name = dev_name(&pdev->dev);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -462,7 +462,7 @@ static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
        pdata->irq = NO_IRQ;
        edac_dev->dev = &pdev->dev;
        platform_set_drvdata(pdev, edac_dev);
-       edac_dev->dev_name = pdev->dev.bus_id;
+       edac_dev->dev_name = dev_name(&pdev->dev);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -713,7 +713,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, mci);
        pdata->name = "mv64x60_mc_err";
        pdata->irq = NO_IRQ;
-       mci->dev_name = pdev->dev.bus_id;
+       mci->dev_name = dev_name(&pdev->dev);
        pdata->edac_idx = edac_mc_idx++;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index c950bf8606d967b07639ed14e0bfd643136df57d..66958b3f10b426c3fcee2135a61087c4b50241bd 100644 (file)
@@ -200,7 +200,7 @@ static int __init eisa_init_device (struct eisa_root_device *root,
        edev->dev.bus = &eisa_bus_type;
        edev->dev.dma_mask = &edev->dma_mask;
        edev->dev.coherent_dma_mask = edev->dma_mask;
-       sprintf (edev->dev.bus_id, "%02X:%02X", root->bus_nr, slot);
+       dev_set_name(&edev->dev, "%02X:%02X", root->bus_nr, slot);
 
        for (i = 0; i < EISA_MAX_RESOURCES; i++) {
 #ifdef CONFIG_EISA_NAMES
@@ -301,7 +301,7 @@ static int __init eisa_probe (struct eisa_root_device *root)
        struct eisa_device *edev;
 
         printk (KERN_INFO "EISA: Probing bus %d at %s\n",
-               root->bus_nr, root->dev->bus_id);
+               root->bus_nr, dev_name(root->dev));
 
        /* First try to get hold of slot 0. If there is no device
         * here, simply fail, unless root->force_probe is set. */
index 7a1168249dd56b761b15e70c81745a750fe4507c..984b587f0f96eb796c6b8971d1e5564973a6ae05 100644 (file)
@@ -160,7 +160,7 @@ static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
 {
        struct gpio_chip *c = &bg->gpio;
 
-       c->label = bg->pdev->dev.bus_id;
+       c->label = dev_name(&bg->pdev->dev);
        c->owner = THIS_MODULE;
        c->direction_input = bt8xxgpio_gpio_direction_input;
        c->get = bt8xxgpio_gpio_get;
index 5aa6780652aa8d920d3591e8f99370a2d677c770..186d08159d4871560291e8cf8eccfffd6ebcfa0e 100644 (file)
@@ -359,8 +359,8 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
        DRM_DEBUG("adding \"%s\" to sysfs\n",
                  drm_get_connector_name(connector));
 
-       snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s",
-                dev->primary->index, drm_get_connector_name(connector));
+       dev_set_name(&connector->kdev, "card%d-%s",
+                    dev->primary->index, drm_get_connector_name(connector));
        ret = device_register(&connector->kdev);
 
        if (ret) {
index e7d984866de0465f5846225c6b59a0072fec7fd1..fbb9030b68a5465bca036e1d441f2ef0fd97e090 100644 (file)
@@ -841,7 +841,7 @@ int i2c_attach_client(struct i2c_client *client)
 
        if (client->driver && !is_newstyle_driver(client->driver)) {
                client->dev.release = i2c_client_release;
-               client->dev.uevent_suppress = 1;
+               dev_set_uevent_suppress(&client->dev, 1);
        } else
                client->dev.release = i2c_client_dev_release;
 
index 5ea3bfad172a02a1c27100920fec28c5d60b1e4f..640c9920724287a42a5e9bbbd03a63a9aaa57cb3 100644 (file)
@@ -56,8 +56,12 @@ if IDE
 
 comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
 
+config IDE_XFER_MODE
+       bool
+
 config IDE_TIMINGS
        bool
+       select IDE_XFER_MODE
 
 config IDE_ATAPI
        bool
@@ -698,6 +702,7 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST
 config BLK_DEV_IDE_AU1XXX
        bool "IDE for AMD Alchemy Au1200"
        depends on SOC_AU1200
+       select IDE_XFER_MODE
 choice
        prompt "IDE Mode for AMD Alchemy Au1200"
        default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
@@ -871,6 +876,7 @@ config BLK_DEV_ALI14XX
 
 config BLK_DEV_DTC2278
        tristate "DTC-2278 support"
+       select IDE_XFER_MODE
        select IDE_LEGACY
        help
          This driver is enabled at runtime using the "dtc2278.probe" kernel
@@ -902,6 +908,7 @@ config BLK_DEV_QD65XX
 
 config BLK_DEV_UMC8672
        tristate "UMC-8672 support"
+       select IDE_XFER_MODE
        select IDE_LEGACY
        help
          This driver is enabled at runtime using the "umc8672.probe" kernel
@@ -915,5 +922,6 @@ endif
 config BLK_DEV_IDEDMA
        def_bool BLK_DEV_IDEDMA_SFF || \
                 BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+       select IDE_XFER_MODE
 
 endif # IDE
index 1c326d94aa6d932021476f041801ddf4f57e9e8c..9b4bbe1cdc1ad9eeb511fe607853d8a6ba985ba1 100644 (file)
@@ -5,9 +5,11 @@
 EXTRA_CFLAGS                           += -Idrivers/ide
 
 ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
-             ide-taskfile.o ide-pm.o ide-park.o ide-pio-blacklist.o ide-sysfs.o
+             ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
+             ide-io-std.o ide-eh.o
 
 # core IDE code
+ide-core-$(CONFIG_IDE_XFER_MODE)       += ide-pio-blacklist.o ide-xfer-mode.o
 ide-core-$(CONFIG_IDE_TIMINGS)         += ide-timings.o
 ide-core-$(CONFIG_IDE_ATAPI)           += ide-atapi.o
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)      += setup-pci.o
index 4485b9c6f0e68bc8c5b28f26652d133f54b7b1df..878f8ec6dbe1147b182fdedca240b86041f37710 100644 (file)
@@ -139,7 +139,7 @@ static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
        drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
 }
 
-static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
+static int init_chipset_aec62xx(struct pci_dev *dev)
 {
        /* These are necessary to get AEC6280 Macintosh cards to work */
        if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
@@ -156,7 +156,7 @@ static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
        }
 
-       return dev->irq;
+       return 0;
 }
 
 static u8 atp86x_cable_detect(ide_hwif_t *hwif)
index 66f43083408b4762c940525b2348bde4a67c4fd3..d3513b6b8530aaa0b82497e0c4ec485c809853e8 100644 (file)
@@ -212,7 +212,7 @@ static int ali15x3_dma_setup(ide_drive_t *drive)
  *     appropriate also sets up the 1533 southbridge.
  */
 
-static unsigned int init_chipset_ali15x3(struct pci_dev *dev)
+static int init_chipset_ali15x3(struct pci_dev *dev)
 {
        unsigned long flags;
        u8 tmpbyte;
index 77267c85996578a47adb19d7104db6992e128e38..628cd2e5fed83de28aab0b423f02adc15944e90d 100644 (file)
@@ -140,7 +140,7 @@ static void amd7411_cable_detect(struct pci_dev *dev)
  * The initialization callback.  Initialize drive independent registers.
  */
 
-static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
+static int init_chipset_amd74xx(struct pci_dev *dev)
 {
        u8 t = 0, offset = amd_offset(dev);
 
@@ -172,7 +172,7 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
                t |= 0xf0;
        pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
 
-       return dev->irq;
+       return 0;
 }
 
 static u8 amd_cable_detect(ide_hwif_t *hwif)
@@ -183,14 +183,6 @@ static u8 amd_cable_detect(ide_hwif_t *hwif)
                return ATA_CBL_PATA40;
 }
 
-static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       if (hwif->irq == 0) /* 0 is bogus but will do for now */
-               hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
-}
-
 static const struct ide_port_ops amd_port_ops = {
        .set_pio_mode           = amd_set_pio_mode,
        .set_dma_mode           = amd_set_drive,
@@ -207,7 +199,6 @@ static const struct ide_port_ops amd_port_ops = {
        {                                                               \
                .name           = DRV_NAME,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
-               .init_hwif      = init_hwif_amd74xx,                    \
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
                .port_ops       = &amd_port_ops,                        \
                .host_flags     = IDE_HFLAGS_AMD,                       \
@@ -221,7 +212,6 @@ static const struct ide_port_ops amd_port_ops = {
        {                                                               \
                .name           = DRV_NAME,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
-               .init_hwif      = init_hwif_amd74xx,                    \
                .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
                .port_ops       = &amd_port_ops,                        \
                .host_flags     = IDE_HFLAGS_AMD,                       \
index ecd1e62ca91a86b0373bf7156e8326e67ffbfa25..923cbfe259d31969f603788dd9c80086b9d62940 100644 (file)
@@ -142,7 +142,6 @@ static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
                .name           = DRV_NAME,
                .enablebits     = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
                .port_ops       = &atiixp_port_ops,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -151,7 +150,7 @@ static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
                .name           = DRV_NAME,
                .enablebits     = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
                .port_ops       = &atiixp_port_ops,
-               .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS,
+               .host_flags     = IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
index 79a2dfed8eb7b600603f68b8468c4ca2e7393a43..154ec2cf734f302a4a154ba948b663e3c8b283b9 100644 (file)
@@ -536,9 +536,8 @@ static const struct ide_port_info au1xxx_port_info = {
 #endif
 };
 
-static int au_ide_probe(struct device *dev)
+static int au_ide_probe(struct platform_device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
        _auide_hwif *ahwif = &auide_hwif;
        struct resource *res;
        struct ide_host *host;
@@ -552,23 +551,23 @@ static int au_ide_probe(struct device *dev)
 #endif
 
        memset(&auide_hwif, 0, sizeof(_auide_hwif));
-       ahwif->irq = platform_get_irq(pdev, 0);
+       ahwif->irq = platform_get_irq(dev, 0);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 
        if (res == NULL) {
-               pr_debug("%s %d: no base address\n", DRV_NAME, pdev->id);
+               pr_debug("%s %d: no base address\n", DRV_NAME, dev->id);
                ret = -ENODEV;
                goto out;
        }
        if (ahwif->irq < 0) {
-               pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+               pr_debug("%s %d: no IRQ\n", DRV_NAME, dev->id);
                ret = -ENODEV;
                goto out;
        }
 
        if (!request_mem_region(res->start, res->end - res->start + 1,
-                               pdev->name)) {
+                               dev->name)) {
                pr_debug("%s: request_mem_region failed\n", DRV_NAME);
                ret =  -EBUSY;
                goto out;
@@ -583,7 +582,7 @@ static int au_ide_probe(struct device *dev)
        memset(&hw, 0, sizeof(hw));
        auide_setup_ports(&hw, ahwif);
        hw.irq = ahwif->irq;
-       hw.dev = dev;
+       hw.dev = &dev->dev;
        hw.chipset = ide_au1xxx;
 
        ret = ide_host_add(&au1xxx_port_info, hws, &host);
@@ -592,7 +591,7 @@ static int au_ide_probe(struct device *dev)
 
        auide_hwif.hwif = host->ports[0];
 
-       dev_set_drvdata(dev, host);
+       platform_set_drvdata(dev, host);
 
        printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
 
@@ -600,38 +599,39 @@ static int au_ide_probe(struct device *dev)
        return ret;
 }
 
-static int au_ide_remove(struct device *dev)
+static int au_ide_remove(struct platform_device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
        struct resource *res;
-       struct ide_host *host = dev_get_drvdata(dev);
+       struct ide_host *host = platform_get_drvdata(dev);
        _auide_hwif *ahwif = &auide_hwif;
 
        ide_host_remove(host);
 
        iounmap((void *)ahwif->regbase);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, res->end - res->start + 1);
 
        return 0;
 }
 
-static struct device_driver au1200_ide_driver = {
-       .name           = "au1200-ide",
-       .bus            = &platform_bus_type,
+static struct platform_driver au1200_ide_driver = {
+       .driver = {
+               .name           = "au1200-ide",
+               .owner          = THIS_MODULE,
+       },
        .probe          = au_ide_probe,
        .remove         = au_ide_remove,
 };
 
 static int __init au_ide_init(void)
 {
-       return driver_register(&au1200_ide_driver);
+       return platform_driver_register(&au1200_ide_driver);
 }
 
 static void __exit au_ide_exit(void)
 {
-       driver_unregister(&au1200_ide_driver);
+       platform_driver_unregister(&au1200_ide_driver);
 }
 
 MODULE_LICENSE("GPL");
index 2f9688d87ecdc5eb192c67588bbcd51ea8094a41..aeee036b15035594432ff8de3bc5e0c5c9ab4946 100644 (file)
@@ -333,7 +333,7 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        return (dma_stat & 7) != 4;
 }
 
-static unsigned int init_chipset_cmd64x(struct pci_dev *dev)
+static int init_chipset_cmd64x(struct pci_dev *dev)
 {
        u8 mrdmode = 0;
 
index d003bec56ff9f51c7c5839e83e79e317b9608eac..58fb90e5b7635c08ae16545b876776c46af095d0 100644 (file)
@@ -133,7 +133,8 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
         *      do all the device setup for us
         */
 
-       ide_pci_setup_ports(dev, d, 14, &hw[0], &hws[0]);
+       ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
+       hw[0].irq = 14;
 
        return ide_host_add(d, hws, NULL);
 }
index d8ede85fe17f4428be6713394e678af59c1457b2..8e8b35a899012961aa6967cb5e8dd7115cf0afb4 100644 (file)
@@ -135,7 +135,7 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
  *     Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
 
-static unsigned int init_chipset_cs5530(struct pci_dev *dev)
+static int init_chipset_cs5530(struct pci_dev *dev)
 {
        struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 
index 8f1b2d9f05138631c541d71c2cb195987de726a5..bacb1194c9c9e5eb9ed4290fd625a457b60c903f 100644 (file)
@@ -46,7 +46,7 @@ static const struct ide_port_ops delkin_cb_port_ops = {
        .quirkproc              = ide_undecoded_slave,
 };
 
-static unsigned int delkin_cb_init_chipset(struct pci_dev *dev)
+static int delkin_cb_init_chipset(struct pci_dev *dev)
 {
        unsigned long base = pci_resource_start(dev, 0);
        int i;
index 3eb9b5c63a0f4a3a4c67facb6e7687a465f69936..d3b3e824f445e53bae0270152b6bb185d5fb889e 100644 (file)
@@ -995,7 +995,7 @@ static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
                pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
 }
 
-static unsigned int init_chipset_hpt366(struct pci_dev *dev)
+static int init_chipset_hpt366(struct pci_dev *dev)
 {
        unsigned long io_base   = pci_resource_start(dev, 4);
        struct hpt_info *info   = hpt3xx_get_info(&dev->dev);
@@ -1237,7 +1237,7 @@ static unsigned int init_chipset_hpt366(struct pci_dev *dev)
        hpt3xx_disable_fast_irq(dev, 0x50);
        hpt3xx_disable_fast_irq(dev, 0x54);
 
-       return dev->irq;
+       return 0;
 }
 
 static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
index ec7d07fa570a8ab706f06b1ed6c6d506ed86b011..5b704f1ea90c901f446897ca21715b8f558bbd64 100644 (file)
@@ -20,9 +20,6 @@
 #include <acpi/acpi_bus.h>
 
 #define REGS_PER_GTF           7
-struct taskfile_array {
-       u8      tfa[REGS_PER_GTF];      /* regs. 0x1f1 - 0x1f7 */
-};
 
 struct GTM_buffer {
        u32     PIO_speed0;
@@ -89,12 +86,8 @@ static const struct dmi_system_id ide_acpi_dmi_table[] = {
        { }     /* terminate list */
 };
 
-static int ide_acpi_blacklist(void)
+int ide_acpi_init(void)
 {
-       static int done;
-       if (done)
-               return 0;
-       done = 1;
        dmi_check_system(ide_acpi_dmi_table);
        return 0;
 }
@@ -201,40 +194,6 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
        return chan_handle;
 }
 
-/**
- * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
- * @drive: device to locate
- *
- * Retrieves the object handle of a given drive. According to the ACPI
- * spec the drive is a child of the hwif.
- *
- * Returns handle on success, 0 on error.
- */
-static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
-{
-       ide_hwif_t      *hwif = drive->hwif;
-       int              port;
-       acpi_handle      drive_handle;
-
-       if (!hwif->acpidata)
-               return NULL;
-
-       if (!hwif->acpidata->obj_handle)
-               return NULL;
-
-       port = hwif->channel ? drive->dn - 2: drive->dn;
-
-       DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
-                drive->name, hwif->channel, port);
-
-
-       /* TBD: could also check ACPI object VALID bits */
-       drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
-       DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
-
-       return drive_handle;
-}
-
 /**
  * do_drive_get_GTF - get the drive bootup default taskfile settings
  * @drive: the drive for which the taskfile settings should be retrieved
@@ -257,47 +216,15 @@ static int do_drive_get_GTF(ide_drive_t *drive,
        acpi_status                     status;
        struct acpi_buffer              output;
        union acpi_object               *out_obj;
-       ide_hwif_t                      *hwif = drive->hwif;
-       struct device                   *dev = hwif->gendev.parent;
        int                             err = -ENODEV;
-       int                             port;
 
        *gtf_length = 0;
        *gtf_address = 0UL;
        *obj_loc = 0UL;
 
-       if (ide_noacpi)
-               return 0;
-
-       if (!dev) {
-               DEBPRINT("no PCI device for %s\n", hwif->name);
-               goto out;
-       }
-
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               goto out;
-       }
-
-       port = hwif->channel ? drive->dn - 2: drive->dn;
-
-       DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
-                hwif->name, dev_name(dev), port, hwif->channel);
-
-       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
-               DEBPRINT("%s drive %d:%d not present\n",
-                        hwif->name, hwif->channel, port);
-               goto out;
-       }
-
-       /* Get this drive's _ADR info. if not already known. */
        if (!drive->acpidata->obj_handle) {
-               drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
-               if (!drive->acpidata->obj_handle) {
-                       DEBPRINT("No ACPI object found for %s\n",
-                                drive->name);
-                       goto out;
-               }
+               DEBPRINT("No ACPI object found for %s\n", drive->name);
+               goto out;
        }
 
        /* Setting up output buffer */
@@ -354,43 +281,6 @@ out:
        return err;
 }
 
-/**
- * taskfile_load_raw - send taskfile registers to drive
- * @drive: drive to which output is sent
- * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
- *
- * Outputs IDE taskfile to the drive.
- */
-static int taskfile_load_raw(ide_drive_t *drive,
-                             const struct taskfile_array *gtf)
-{
-       ide_task_t args;
-       int err = 0;
-
-       DEBPRINT("(0x1f1-1f7): hex: "
-              "%02x %02x %02x %02x %02x %02x %02x\n",
-              gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
-              gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
-
-       memset(&args, 0, sizeof(ide_task_t));
-
-       /* convert gtf to IDE Taskfile */
-       memcpy(&args.tf_array[7], &gtf->tfa, 7);
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-
-       if (!ide_acpigtf) {
-               DEBPRINT("_GTF execution disabled\n");
-               return err;
-       }
-
-       err = ide_no_data_taskfile(drive, &args);
-       if (err)
-               printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
-                      __func__, err);
-
-       return err;
-}
-
 /**
  * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
  * @drive: the drive to which the taskfile command should be sent
@@ -404,43 +294,41 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
                                  unsigned int gtf_length,
                                  unsigned long gtf_address)
 {
-       int                     rc = -ENODEV, err;
+       int                     rc = 0, err;
        int                     gtf_count = gtf_length / REGS_PER_GTF;
        int                     ix;
-       struct taskfile_array   *gtf;
-
-       if (ide_noacpi)
-               return 0;
-
-       DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
-
-       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               goto out;
-
-       if (!gtf_count)         /* shouldn't be here */
-               goto out;
 
        DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
                 gtf_length, gtf_length, gtf_count, gtf_address);
 
-       if (gtf_length % REGS_PER_GTF) {
-               printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
-                      __func__, gtf_length);
-               goto out;
-       }
-
-       rc = 0;
+       /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
        for (ix = 0; ix < gtf_count; ix++) {
-               gtf = (struct taskfile_array *)
-                       (gtf_address + ix * REGS_PER_GTF);
+               u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
+               ide_task_t task;
 
-               /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
-               err = taskfile_load_raw(drive, gtf);
-               if (err)
+               DEBPRINT("(0x1f1-1f7): "
+                        "hex: %02x %02x %02x %02x %02x %02x %02x\n",
+                        gtf[0], gtf[1], gtf[2],
+                        gtf[3], gtf[4], gtf[5], gtf[6]);
+
+               if (!ide_acpigtf) {
+                       DEBPRINT("_GTF execution disabled\n");
+                       continue;
+               }
+
+               /* convert GTF to taskfile */
+               memset(&task, 0, sizeof(ide_task_t));
+               memcpy(&task.tf_array[7], gtf, REGS_PER_GTF);
+               task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+               err = ide_no_data_taskfile(drive, &task);
+               if (err) {
+                       printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
+                                       __func__, err);
                        rc = err;
+               }
        }
 
-out:
        return rc;
 }
 
@@ -647,26 +535,23 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
                DEBPRINT("no ACPI data for %s\n", hwif->name);
                return;
        }
+
        /* channel first and then drives for power on and verse versa for power off */
        if (on)
                acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (!drive->acpidata->obj_handle)
-                       drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
-
-               if (drive->acpidata->obj_handle &&
-                   (drive->dev_flags & IDE_DFLAG_PRESENT)) {
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               if (drive->acpidata->obj_handle)
                        acpi_bus_set_power(drive->acpidata->obj_handle,
-                               on? ACPI_STATE_D0: ACPI_STATE_D3);
-               }
+                                          on ? ACPI_STATE_D0 : ACPI_STATE_D3);
        }
+
        if (!on)
                acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
 }
 
 /**
- * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * ide_acpi_init_port - initialize the ACPI link for an IDE interface
  * @hwif: target IDE interface (channel)
  *
  * The ACPI spec is not quite clear when the drive identify buffer
@@ -676,10 +561,8 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
  * So we get the information during startup; but this means that
  * any changes during run-time will be lost after resume.
  */
-void ide_acpi_init(ide_hwif_t *hwif)
+void ide_acpi_init_port(ide_hwif_t *hwif)
 {
-       ide_acpi_blacklist();
-
        hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
        if (!hwif->acpidata)
                return;
@@ -708,15 +591,24 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
        hwif->devices[0]->acpidata = &hwif->acpidata->master;
        hwif->devices[1]->acpidata = &hwif->acpidata->slave;
 
-       /*
-        * Send IDENTIFY for each drive
-        */
-       ide_port_for_each_dev(i, drive, hwif) {
-               memset(drive->acpidata, 0, sizeof(*drive->acpidata));
+       /* get _ADR info for each device */
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               acpi_handle dev_handle;
 
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       continue;
+               DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+                        drive->name, hwif->channel, drive->dn & 1);
+
+               /* TBD: could also check ACPI object VALID bits */
+               dev_handle = acpi_get_child(hwif->acpidata->obj_handle,
+                                           drive->dn & 1);
+
+               DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle);
+
+               drive->acpidata->obj_handle = dev_handle;
+       }
 
+       /* send IDENTIFY for each device */
+       ide_port_for_each_present_dev(i, drive, hwif) {
                err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
                if (err)
                        DEBPRINT("identify device %s failed (%d)\n",
@@ -736,9 +628,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
        ide_acpi_get_timing(hwif);
        ide_acpi_push_timing(hwif);
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (drive->dev_flags & IDE_DFLAG_PRESENT)
-                       /* Execute ACPI startup code */
-                       ide_acpi_exec_tfs(drive);
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               ide_acpi_exec_tfs(drive);
        }
 }
index e9d042dba0e075572844752dc032e66e6219bcec..6adc5b4a4406808d909e3944e1f1c47f5354ef15 100644 (file)
@@ -149,7 +149,10 @@ static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
        memcpy(rq->cmd, pc->c, 12);
        if (drive->media == ide_tape)
                rq->cmd[13] = REQ_IDETAPE_PC1;
-       ide_do_drive_cmd(drive, rq);
+
+       drive->hwif->rq = NULL;
+
+       elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
 }
 
 /*
@@ -297,6 +300,21 @@ int ide_cd_get_xferlen(struct request *rq)
 }
 EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
 
+void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
+{
+       ide_task_t task;
+
+       memset(&task, 0, sizeof(task));
+       task.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
+                       IDE_TFLAG_IN_NSECT;
+
+       drive->hwif->tp_ops->tf_read(drive, &task);
+
+       *bcount = (task.tf.lbah << 8) | task.tf.lbam;
+       *ireason = task.tf.nsect & 3;
+}
+EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
+
 /*
  * This is the usual interrupt handler which will be called during a packet
  * command.  We will transfer some of the data (as requested by the drive)
@@ -456,6 +474,25 @@ next_irq:
        return ide_started;
 }
 
+static void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       ide_task_t task;
+       u8 dma = drive->dma;
+
+       memset(&task, 0, sizeof(task));
+       task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
+                       IDE_TFLAG_OUT_FEATURE | tf_flags;
+       task.tf.feature = dma;          /* Use PIO/DMA */
+       task.tf.lbam    = bcount & 0xff;
+       task.tf.lbah    = (bcount >> 8) & 0xff;
+
+       ide_tf_dump(drive->name, &task.tf);
+       hwif->tp_ops->set_irq(hwif, 1);
+       SELECT_MASK(drive, 0);
+       hwif->tp_ops->tf_load(drive, &task);
+}
+
 static u8 ide_read_ireason(ide_drive_t *drive)
 {
        ide_task_t task;
@@ -629,7 +666,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive)
                                                       : WAIT_TAPE_CMD;
        }
 
-       ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
+       ide_pktcmd_tf_load(drive, tf_flags, bcount);
 
        /* Issue the packet command */
        if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
index ddfbea41d296a738a1efb5ace07b22b9a7dff2ad..2177cd11664c216a50c927e884a0ba9fa522d8b4 100644 (file)
@@ -242,7 +242,9 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
                ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
                              failed_command->cmd[0]);
 
-       ide_do_drive_cmd(drive, rq);
+       drive->hwif->rq = NULL;
+
+       elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
 }
 
 static void cdrom_end_request(ide_drive_t *drive, int uptodate)
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
new file mode 100644 (file)
index 0000000..7c39534
--- /dev/null
@@ -0,0 +1,190 @@
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+DEFINE_MUTEX(ide_setting_mtx);
+
+ide_devset_get(io_32bit, io_32bit);
+
+static int set_io_32bit(ide_drive_t *drive, int arg)
+{
+       if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
+               return -EPERM;
+
+       if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
+               return -EINVAL;
+
+       drive->io_32bit = arg;
+
+       return 0;
+}
+
+ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
+
+static int set_ksettings(ide_drive_t *drive, int arg)
+{
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
+
+       return 0;
+}
+
+ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
+
+static int set_using_dma(ide_drive_t *drive, int arg)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+       int err = -EPERM;
+
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       if (ata_id_has_dma(drive->id) == 0)
+               goto out;
+
+       if (drive->hwif->dma_ops == NULL)
+               goto out;
+
+       err = 0;
+
+       if (arg) {
+               if (ide_set_dma(drive))
+                       err = -EIO;
+       } else
+               ide_dma_off(drive);
+
+out:
+       return err;
+#else
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       return -EPERM;
+#endif
+}
+
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+       switch (req_pio) {
+       case 202:
+       case 201:
+       case 200:
+       case 102:
+       case 101:
+       case 100:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+       case 9:
+       case 8:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+       case 7:
+       case 6:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+       default:
+               return 0;
+       }
+}
+
+static int set_pio_mode(ide_drive_t *drive, int arg)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+
+       if (arg < 0 || arg > 255)
+               return -EINVAL;
+
+       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+               return -ENOSYS;
+
+       if (set_pio_mode_abuse(drive->hwif, arg)) {
+               if (arg == 8 || arg == 9) {
+                       unsigned long flags;
+
+                       /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
+                       spin_lock_irqsave(&hwif->lock, flags);
+                       port_ops->set_pio_mode(drive, arg);
+                       spin_unlock_irqrestore(&hwif->lock, flags);
+               } else
+                       port_ops->set_pio_mode(drive, arg);
+       } else {
+               int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+
+               ide_set_pio(drive, arg);
+
+               if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+                       if (keep_dma)
+                               ide_dma_on(drive);
+               }
+       }
+
+       return 0;
+}
+
+ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
+
+static int set_unmaskirq(ide_drive_t *drive, int arg)
+{
+       if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
+               return -EPERM;
+
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_UNMASK;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+
+       return 0;
+}
+
+ide_ext_devset_rw_sync(io_32bit, io_32bit);
+ide_ext_devset_rw_sync(keepsettings, ksettings);
+ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
+ide_ext_devset_rw_sync(using_dma, using_dma);
+__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
+
+int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
+                      int arg)
+{
+       struct request_queue *q = drive->queue;
+       struct request *rq;
+       int ret = 0;
+
+       if (!(setting->flags & DS_SYNC))
+               return setting->set(drive, arg);
+
+       rq = blk_get_request(q, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->cmd_len = 5;
+       rq->cmd[0] = REQ_DEVSET_EXEC;
+       *(int *)&rq->cmd[1] = arg;
+       rq->special = setting->set;
+
+       if (blk_execute_rq(q, NULL, rq, 0))
+               ret = rq->errors;
+       blk_put_request(rq);
+
+       return ret;
+}
+
+ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
+{
+       int err, (*setfunc)(ide_drive_t *, int) = rq->special;
+
+       err = setfunc(drive, *(int *)&rq->cmd[1]);
+       if (err)
+               rq->errors = err;
+       else
+               err = 1;
+       ide_end_request(drive, err, 0);
+       return ide_stopped;
+}
index 059c90bb5ad2f4082c52ad695100ea83490c0263..a878f4734f8129139efc995bd8c65337f6dad0fc 100644 (file)
@@ -470,6 +470,63 @@ void ide_dma_timeout(ide_drive_t *drive)
 }
 EXPORT_SYMBOL_GPL(ide_dma_timeout);
 
+/*
+ * un-busy the port etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct request *rq;
+       ide_startstop_t ret = ide_stopped;
+
+       /*
+        * end current dma transaction
+        */
+
+       if (error < 0) {
+               printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
+               (void)hwif->dma_ops->dma_end(drive);
+               ret = ide_error(drive, "dma timeout error",
+                               hwif->tp_ops->read_status(hwif));
+       } else {
+               printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
+               hwif->dma_ops->dma_timeout(drive);
+       }
+
+       /*
+        * disable dma for now, but remember that we did so because of
+        * a timeout -- we'll reenable after we finish this next request
+        * (or rather the first chunk of it) in pio.
+        */
+       drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
+       drive->retry_pio++;
+       ide_dma_off_quietly(drive);
+
+       /*
+        * un-busy drive etc and make sure request is sane
+        */
+
+       rq = hwif->rq;
+       if (!rq)
+               goto out;
+
+       hwif->rq = NULL;
+
+       rq->errors = 0;
+
+       if (!rq->bio)
+               goto out;
+
+       rq->sector = rq->bio->bi_sector;
+       rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
+       rq->hard_cur_sectors = rq->current_nr_sectors;
+       rq->buffer = bio_data(rq->bio);
+out:
+       return ret;
+}
+
 void ide_release_dma_engine(ide_hwif_t *hwif)
 {
        if (hwif->dmatable_cpu) {
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
new file mode 100644 (file)
index 0000000..1231b5e
--- /dev/null
@@ -0,0 +1,428 @@
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+
+static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq,
+                                    u8 stat, u8 err)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if ((stat & ATA_BUSY) ||
+           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
+               /* other bits are useless when BUSY */
+               rq->errors |= ERROR_RESET;
+       } else if (stat & ATA_ERR) {
+               /* err has different meaning on cdrom and tape */
+               if (err == ATA_ABORTED) {
+                       if ((drive->dev_flags & IDE_DFLAG_LBA) &&
+                           /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
+                           hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
+                               return ide_stopped;
+               } else if ((err & BAD_CRC) == BAD_CRC) {
+                       /* UDMA crc error, just retry the operation */
+                       drive->crc_count++;
+               } else if (err & (ATA_BBK | ATA_UNC)) {
+                       /* retries won't help these */
+                       rq->errors = ERROR_MAX;
+               } else if (err & ATA_TRK0NF) {
+                       /* help it find track zero */
+                       rq->errors |= ERROR_RECAL;
+               }
+       }
+
+       if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
+           (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
+               int nsect = drive->mult_count ? drive->mult_count : 1;
+
+               ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
+       }
+
+       if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
+               ide_kill_rq(drive, rq);
+               return ide_stopped;
+       }
+
+       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
+               rq->errors |= ERROR_RESET;
+
+       if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+               ++rq->errors;
+               return ide_do_reset(drive);
+       }
+
+       if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+               drive->special.b.recalibrate = 1;
+
+       ++rq->errors;
+
+       return ide_stopped;
+}
+
+static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq,
+                                      u8 stat, u8 err)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if ((stat & ATA_BUSY) ||
+           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
+               /* other bits are useless when BUSY */
+               rq->errors |= ERROR_RESET;
+       } else {
+               /* add decoding error stuff */
+       }
+
+       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
+               /* force an abort */
+               hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
+
+       if (rq->errors >= ERROR_MAX) {
+               ide_kill_rq(drive, rq);
+       } else {
+               if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+                       ++rq->errors;
+                       return ide_do_reset(drive);
+               }
+               ++rq->errors;
+       }
+
+       return ide_stopped;
+}
+
+static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq,
+                                  u8 stat, u8 err)
+{
+       if (drive->media == ide_disk)
+               return ide_ata_error(drive, rq, stat, err);
+       return ide_atapi_error(drive, rq, stat, err);
+}
+
+/**
+ *     ide_error       -       handle an error on the IDE
+ *     @drive: drive the error occurred on
+ *     @msg: message to report
+ *     @stat: status bits
+ *
+ *     ide_error() takes action based on the error returned by the drive.
+ *     For normal I/O that may well include retries. We deal with
+ *     both new-style (taskfile) and old style command handling here.
+ *     In the case of taskfile command handling there is work left to
+ *     do
+ */
+
+ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
+{
+       struct request *rq;
+       u8 err;
+
+       err = ide_dump_status(drive, msg, stat);
+
+       rq = drive->hwif->rq;
+       if (rq == NULL)
+               return ide_stopped;
+
+       /* retry only "normal" I/O: */
+       if (!blk_fs_request(rq)) {
+               rq->errors = 1;
+               ide_end_drive_cmd(drive, stat, err);
+               return ide_stopped;
+       }
+
+       return __ide_error(drive, rq, stat, err);
+}
+EXPORT_SYMBOL_GPL(ide_error);
+
+static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
+{
+       struct request *rq = drive->hwif->rq;
+
+       if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
+               ide_end_request(drive, err ? err : 1, 0);
+}
+
+/* needed below */
+static ide_startstop_t do_reset1(ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion
+ * every 50ms during an atapi drive reset operation.  If the drive has not yet
+ * responded, and we have not yet hit our maximum waiting time, then the timer
+ * is restarted for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 stat;
+
+       SELECT_DRIVE(drive);
+       udelay(10);
+       stat = hwif->tp_ops->read_status(hwif);
+
+       if (OK_STAT(stat, 0, ATA_BUSY))
+               printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
+       else {
+               if (time_before(jiffies, hwif->poll_timeout)) {
+                       ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20,
+                                       NULL);
+                       /* continue polling */
+                       return ide_started;
+               }
+               /* end of polling */
+               hwif->polling = 0;
+               printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n",
+                       drive->name, stat);
+               /* do it the old fashioned way */
+               return do_reset1(drive, 1);
+       }
+       /* done polling */
+       hwif->polling = 0;
+       ide_complete_drive_reset(drive, 0);
+       return ide_stopped;
+}
+
+static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
+{
+       static const char *err_master_vals[] =
+               { NULL, "passed", "formatter device error",
+                 "sector buffer error", "ECC circuitry error",
+                 "controlling MPU error" };
+
+       u8 err_master = err & 0x7f;
+
+       printk(KERN_ERR "%s: reset: master: ", hwif->name);
+       if (err_master && err_master < 6)
+               printk(KERN_CONT "%s", err_master_vals[err_master]);
+       else
+               printk(KERN_CONT "error (0x%02x?)", err);
+       if (err & 0x80)
+               printk(KERN_CONT "; slave: failed");
+       printk(KERN_CONT "\n");
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+       u8 tmp;
+       int err = 0;
+
+       if (port_ops && port_ops->reset_poll) {
+               err = port_ops->reset_poll(drive);
+               if (err) {
+                       printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+                               hwif->name, drive->name);
+                       goto out;
+               }
+       }
+
+       tmp = hwif->tp_ops->read_status(hwif);
+
+       if (!OK_STAT(tmp, 0, ATA_BUSY)) {
+               if (time_before(jiffies, hwif->poll_timeout)) {
+                       ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+                       /* continue polling */
+                       return ide_started;
+               }
+               printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n",
+                       hwif->name, tmp);
+               drive->failures++;
+               err = -EIO;
+       } else  {
+               tmp = ide_read_error(drive);
+
+               if (tmp == 1) {
+                       printk(KERN_INFO "%s: reset: success\n", hwif->name);
+                       drive->failures = 0;
+               } else {
+                       ide_reset_report_error(hwif, tmp);
+                       drive->failures++;
+                       err = -EIO;
+               }
+       }
+out:
+       hwif->polling = 0;      /* done polling */
+       ide_complete_drive_reset(drive, err);
+       return ide_stopped;
+}
+
+static void ide_disk_pre_reset(ide_drive_t *drive)
+{
+       int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
+
+       drive->special.all = 0;
+       drive->special.b.set_geometry = legacy;
+       drive->special.b.recalibrate  = legacy;
+
+       drive->mult_count = 0;
+       drive->dev_flags &= ~IDE_DFLAG_PARKED;
+
+       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
+           (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
+               drive->mult_req = 0;
+
+       if (drive->mult_req != drive->mult_count)
+               drive->special.b.set_multmode = 1;
+}
+
+static void pre_reset(ide_drive_t *drive)
+{
+       const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+
+       if (drive->media == ide_disk)
+               ide_disk_pre_reset(drive);
+       else
+               drive->dev_flags |= IDE_DFLAG_POST_RESET;
+
+       if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
+               if (drive->crc_count)
+                       ide_check_dma_crc(drive);
+               else
+                       ide_dma_off(drive);
+       }
+
+       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
+               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
+                       drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+                       drive->io_32bit = 0;
+               }
+               return;
+       }
+
+       if (port_ops && port_ops->pre_reset)
+               port_ops->pre_reset(drive);
+
+       if (drive->current_speed != 0xff)
+               drive->desired_speed = drive->current_speed;
+       drive->current_speed = 0xff;
+}
+
+/*
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+       const struct ide_port_ops *port_ops;
+       ide_drive_t *tdrive;
+       unsigned long flags, timeout;
+       int i;
+       DEFINE_WAIT(wait);
+
+       spin_lock_irqsave(&hwif->lock, flags);
+
+       /* We must not reset with running handlers */
+       BUG_ON(hwif->handler != NULL);
+
+       /* For an ATAPI device, first try an ATAPI SRST. */
+       if (drive->media != ide_disk && !do_not_try_atapi) {
+               pre_reset(drive);
+               SELECT_DRIVE(drive);
+               udelay(20);
+               tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
+               ndelay(400);
+               hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
+               hwif->polling = 1;
+               __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+               spin_unlock_irqrestore(&hwif->lock, flags);
+               return ide_started;
+       }
+
+       /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
+       do {
+               unsigned long now;
+
+               prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
+               timeout = jiffies;
+               ide_port_for_each_present_dev(i, tdrive, hwif) {
+                       if ((tdrive->dev_flags & IDE_DFLAG_PARKED) &&
+                           time_after(tdrive->sleep, timeout))
+                               timeout = tdrive->sleep;
+               }
+
+               now = jiffies;
+               if (time_before_eq(timeout, now))
+                       break;
+
+               spin_unlock_irqrestore(&hwif->lock, flags);
+               timeout = schedule_timeout_uninterruptible(timeout - now);
+               spin_lock_irqsave(&hwif->lock, flags);
+       } while (timeout);
+       finish_wait(&ide_park_wq, &wait);
+
+       /*
+        * First, reset any device state data we were maintaining
+        * for any of the drives on this interface.
+        */
+       ide_port_for_each_dev(i, tdrive, hwif)
+               pre_reset(tdrive);
+
+       if (io_ports->ctl_addr == 0) {
+               spin_unlock_irqrestore(&hwif->lock, flags);
+               ide_complete_drive_reset(drive, -ENXIO);
+               return ide_stopped;
+       }
+
+       /*
+        * Note that we also set nIEN while resetting the device,
+        * to mask unwanted interrupts from the interface during the reset.
+        * However, due to the design of PC hardware, this will cause an
+        * immediate interrupt due to the edge transition it produces.
+        * This single interrupt gives us a "fast poll" for drives that
+        * recover from reset very quickly, saving us the first 50ms wait time.
+        *
+        * TODO: add ->softreset method and stop abusing ->set_irq
+        */
+       /* set SRST and nIEN */
+       tp_ops->set_irq(hwif, 4);
+       /* more than enough time */
+       udelay(10);
+       /* clear SRST, leave nIEN (unless device is on the quirk list) */
+       tp_ops->set_irq(hwif, drive->quirk_list == 2);
+       /* more than enough time */
+       udelay(10);
+       hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
+       hwif->polling = 1;
+       __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+
+       /*
+        * Some weird controller like resetting themselves to a strange
+        * state when the disks are reset this way. At least, the Winbond
+        * 553 documentation says that
+        */
+       port_ops = hwif->port_ops;
+       if (port_ops && port_ops->resetproc)
+               port_ops->resetproc(drive);
+
+       spin_unlock_irqrestore(&hwif->lock, flags);
+       return ide_started;
+}
+
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+
+ide_startstop_t ide_do_reset(ide_drive_t *drive)
+{
+       return do_reset1(drive, 0);
+}
+EXPORT_SYMBOL(ide_do_reset);
diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c
new file mode 100644 (file)
index 0000000..45b43dd
--- /dev/null
@@ -0,0 +1,316 @@
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+/*
+ *     Conventional PIO operations for ATA devices
+ */
+
+static u8 ide_inb(unsigned long port)
+{
+       return (u8) inb(port);
+}
+
+static void ide_outb(u8 val, unsigned long port)
+{
+       outb(val, port);
+}
+
+/*
+ *     MMIO operations, typically used for SATA controllers
+ */
+
+static u8 ide_mm_inb(unsigned long port)
+{
+       return (u8) readb((void __iomem *) port);
+}
+
+static void ide_mm_outb(u8 value, unsigned long port)
+{
+       writeb(value, (void __iomem *) port);
+}
+
+void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
+{
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
+       else
+               outb(cmd, hwif->io_ports.command_addr);
+}
+EXPORT_SYMBOL_GPL(ide_exec_command);
+
+u8 ide_read_status(ide_hwif_t *hwif)
+{
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               return readb((void __iomem *)hwif->io_ports.status_addr);
+       else
+               return inb(hwif->io_ports.status_addr);
+}
+EXPORT_SYMBOL_GPL(ide_read_status);
+
+u8 ide_read_altstatus(ide_hwif_t *hwif)
+{
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               return readb((void __iomem *)hwif->io_ports.ctl_addr);
+       else
+               return inb(hwif->io_ports.ctl_addr);
+}
+EXPORT_SYMBOL_GPL(ide_read_altstatus);
+
+void ide_set_irq(ide_hwif_t *hwif, int on)
+{
+       u8 ctl = ATA_DEVCTL_OBS;
+
+       if (on == 4) { /* hack for SRST */
+               ctl |= 4;
+               on &= ~4;
+       }
+
+       ctl |= on ? 0 : 2;
+
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
+       else
+               outb(ctl, hwif->io_ports.ctl_addr);
+}
+EXPORT_SYMBOL_GPL(ide_set_irq);
+
+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       struct ide_taskfile *tf = &task->tf;
+       void (*tf_outb)(u8 addr, unsigned long port);
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+       if (mmio)
+               tf_outb = ide_mm_outb;
+       else
+               tf_outb = ide_outb;
+
+       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+               HIHI = 0xFF;
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+               u16 data = (tf->hob_data << 8) | tf->data;
+
+               if (mmio)
+                       writew(data, (void __iomem *)io_ports->data_addr);
+               else
+                       outw(data, io_ports->data_addr);
+       }
+
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+               tf_outb(tf->hob_feature, io_ports->feature_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+               tf_outb(tf->hob_nsect, io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+               tf_outb(tf->hob_lbal, io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+               tf_outb(tf->hob_lbam, io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+               tf_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+               tf_outb(tf->feature, io_ports->feature_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+               tf_outb(tf->nsect, io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+               tf_outb(tf->lbal, io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+               tf_outb(tf->lbam, io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+               tf_outb(tf->lbah, io_ports->lbah_addr);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+               tf_outb((tf->device & HIHI) | drive->select,
+                        io_ports->device_addr);
+}
+EXPORT_SYMBOL_GPL(ide_tf_load);
+
+void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       struct ide_taskfile *tf = &task->tf;
+       void (*tf_outb)(u8 addr, unsigned long port);
+       u8 (*tf_inb)(unsigned long port);
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+       if (mmio) {
+               tf_outb = ide_mm_outb;
+               tf_inb  = ide_mm_inb;
+       } else {
+               tf_outb = ide_outb;
+               tf_inb  = ide_inb;
+       }
+
+       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+               u16 data;
+
+               if (mmio)
+                       data = readw((void __iomem *)io_ports->data_addr);
+               else
+                       data = inw(io_ports->data_addr);
+
+               tf->data = data & 0xff;
+               tf->hob_data = (data >> 8) & 0xff;
+       }
+
+       /* be sure we're looking at the low order bits */
+       tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+               tf->feature = tf_inb(io_ports->feature_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+               tf->nsect  = tf_inb(io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+               tf->lbal   = tf_inb(io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+               tf->lbam   = tf_inb(io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+               tf->lbah   = tf_inb(io_ports->lbah_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+               tf->device = tf_inb(io_ports->device_addr);
+
+       if (task->tf_flags & IDE_TFLAG_LBA48) {
+               tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+                       tf->hob_feature = tf_inb(io_ports->feature_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect   = tf_inb(io_ports->nsect_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal    = tf_inb(io_ports->lbal_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam    = tf_inb(io_ports->lbam_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah    = tf_inb(io_ports->lbah_addr);
+       }
+}
+EXPORT_SYMBOL_GPL(ide_tf_read);
+
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static void ata_vlb_sync(unsigned long port)
+{
+       (void)inb(port);
+       (void)inb(port);
+       (void)inb(port);
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd len is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
+                   unsigned int len)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       unsigned long data_addr = io_ports->data_addr;
+       u8 io_32bit = drive->io_32bit;
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+       len++;
+
+       if (io_32bit) {
+               unsigned long uninitialized_var(flags);
+
+               if ((io_32bit & 2) && !mmio) {
+                       local_irq_save(flags);
+                       ata_vlb_sync(io_ports->nsect_addr);
+               }
+
+               if (mmio)
+                       __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
+               else
+                       insl(data_addr, buf, len / 4);
+
+               if ((io_32bit & 2) && !mmio)
+                       local_irq_restore(flags);
+
+               if ((len & 3) >= 2) {
+                       if (mmio)
+                               __ide_mm_insw((void __iomem *)data_addr,
+                                               (u8 *)buf + (len & ~3), 1);
+                       else
+                               insw(data_addr, (u8 *)buf + (len & ~3), 1);
+               }
+       } else {
+               if (mmio)
+                       __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
+               else
+                       insw(data_addr, buf, len / 2);
+       }
+}
+EXPORT_SYMBOL_GPL(ide_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
+                    unsigned int len)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       unsigned long data_addr = io_ports->data_addr;
+       u8 io_32bit = drive->io_32bit;
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+       len++;
+
+       if (io_32bit) {
+               unsigned long uninitialized_var(flags);
+
+               if ((io_32bit & 2) && !mmio) {
+                       local_irq_save(flags);
+                       ata_vlb_sync(io_ports->nsect_addr);
+               }
+
+               if (mmio)
+                       __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
+               else
+                       outsl(data_addr, buf, len / 4);
+
+               if ((io_32bit & 2) && !mmio)
+                       local_irq_restore(flags);
+
+               if ((len & 3) >= 2) {
+                       if (mmio)
+                               __ide_mm_outsw((void __iomem *)data_addr,
+                                                (u8 *)buf + (len & ~3), 1);
+                       else
+                               outsw(data_addr, (u8 *)buf + (len & ~3), 1);
+               }
+       } else {
+               if (mmio)
+                       __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
+               else
+                       outsw(data_addr, buf, len / 2);
+       }
+}
+EXPORT_SYMBOL_GPL(ide_output_data);
+
+const struct ide_tp_ops default_tp_ops = {
+       .exec_command           = ide_exec_command,
+       .read_status            = ide_read_status,
+       .read_altstatus         = ide_read_altstatus,
+
+       .set_irq                = ide_set_irq,
+
+       .tf_load                = ide_tf_load,
+       .tf_read                = ide_tf_read,
+
+       .input_data             = ide_input_data,
+       .output_data            = ide_output_data,
+};
index a9a6c208288a27173970b705de620fea3e076294..2e92497b58aa02501b208562ab498d4f4d6c1e87 100644 (file)
@@ -196,7 +196,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 }
 EXPORT_SYMBOL(ide_end_drive_cmd);
 
-static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
+void ide_kill_rq(ide_drive_t *drive, struct request *rq)
 {
        if (rq->rq_disk) {
                struct ide_driver *drv;
@@ -207,133 +207,6 @@ static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
                ide_end_request(drive, 0, 0);
 }
 
-static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if ((stat & ATA_BUSY) ||
-           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
-               /* other bits are useless when BUSY */
-               rq->errors |= ERROR_RESET;
-       } else if (stat & ATA_ERR) {
-               /* err has different meaning on cdrom and tape */
-               if (err == ATA_ABORTED) {
-                       if ((drive->dev_flags & IDE_DFLAG_LBA) &&
-                           /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
-                           hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
-                               return ide_stopped;
-               } else if ((err & BAD_CRC) == BAD_CRC) {
-                       /* UDMA crc error, just retry the operation */
-                       drive->crc_count++;
-               } else if (err & (ATA_BBK | ATA_UNC)) {
-                       /* retries won't help these */
-                       rq->errors = ERROR_MAX;
-               } else if (err & ATA_TRK0NF) {
-                       /* help it find track zero */
-                       rq->errors |= ERROR_RECAL;
-               }
-       }
-
-       if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
-           (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
-               int nsect = drive->mult_count ? drive->mult_count : 1;
-
-               ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
-       }
-
-       if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
-               ide_kill_rq(drive, rq);
-               return ide_stopped;
-       }
-
-       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
-               rq->errors |= ERROR_RESET;
-
-       if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-               ++rq->errors;
-               return ide_do_reset(drive);
-       }
-
-       if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-               drive->special.b.recalibrate = 1;
-
-       ++rq->errors;
-
-       return ide_stopped;
-}
-
-static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if ((stat & ATA_BUSY) ||
-           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
-               /* other bits are useless when BUSY */
-               rq->errors |= ERROR_RESET;
-       } else {
-               /* add decoding error stuff */
-       }
-
-       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
-               /* force an abort */
-               hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
-
-       if (rq->errors >= ERROR_MAX) {
-               ide_kill_rq(drive, rq);
-       } else {
-               if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-                       ++rq->errors;
-                       return ide_do_reset(drive);
-               }
-               ++rq->errors;
-       }
-
-       return ide_stopped;
-}
-
-static ide_startstop_t
-__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
-{
-       if (drive->media == ide_disk)
-               return ide_ata_error(drive, rq, stat, err);
-       return ide_atapi_error(drive, rq, stat, err);
-}
-
-/**
- *     ide_error       -       handle an error on the IDE
- *     @drive: drive the error occurred on
- *     @msg: message to report
- *     @stat: status bits
- *
- *     ide_error() takes action based on the error returned by the drive.
- *     For normal I/O that may well include retries. We deal with
- *     both new-style (taskfile) and old style command handling here.
- *     In the case of taskfile command handling there is work left to
- *     do
- */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
-{
-       struct request *rq;
-       u8 err;
-
-       err = ide_dump_status(drive, msg, stat);
-
-       rq = drive->hwif->rq;
-       if (rq == NULL)
-               return ide_stopped;
-
-       /* retry only "normal" I/O: */
-       if (!blk_fs_request(rq)) {
-               rq->errors = 1;
-               ide_end_drive_cmd(drive, stat, err);
-               return ide_stopped;
-       }
-
-       return __ide_error(drive, rq, stat, err);
-}
-EXPORT_SYMBOL_GPL(ide_error);
-
 static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
        tf->nsect   = drive->sect;
@@ -490,71 +363,16 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
        return ide_stopped;
 }
 
-int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
-                      int arg)
-{
-       struct request_queue *q = drive->queue;
-       struct request *rq;
-       int ret = 0;
-
-       if (!(setting->flags & DS_SYNC))
-               return setting->set(drive, arg);
-
-       rq = blk_get_request(q, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd_len = 5;
-       rq->cmd[0] = REQ_DEVSET_EXEC;
-       *(int *)&rq->cmd[1] = arg;
-       rq->special = setting->set;
-
-       if (blk_execute_rq(q, NULL, rq, 0))
-               ret = rq->errors;
-       blk_put_request(rq);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ide_devset_execute);
-
 static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
 {
        u8 cmd = rq->cmd[0];
 
-       if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
-               ide_task_t task;
-               struct ide_taskfile *tf = &task.tf;
-
-               memset(&task, 0, sizeof(task));
-               if (cmd == REQ_PARK_HEADS) {
-                       drive->sleep = *(unsigned long *)rq->special;
-                       drive->dev_flags |= IDE_DFLAG_SLEEPING;
-                       tf->command = ATA_CMD_IDLEIMMEDIATE;
-                       tf->feature = 0x44;
-                       tf->lbal = 0x4c;
-                       tf->lbam = 0x4e;
-                       tf->lbah = 0x55;
-                       task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
-               } else          /* cmd == REQ_UNPARK_HEADS */
-                       tf->command = ATA_CMD_CHK_POWER;
-
-               task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-               task.rq = rq;
-               drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
-               return do_rw_taskfile(drive, &task);
-       }
-
        switch (cmd) {
+       case REQ_PARK_HEADS:
+       case REQ_UNPARK_HEADS:
+               return ide_do_park_unpark(drive, rq);
        case REQ_DEVSET_EXEC:
-       {
-               int err, (*setfunc)(ide_drive_t *, int) = rq->special;
-
-               err = setfunc(drive, *(int *)&rq->cmd[1]);
-               if (err)
-                       rq->errors = err;
-               else
-                       err = 1;
-               ide_end_request(drive, err, 0);
-               return ide_stopped;
-       }
+               return ide_do_devset(drive, rq);
        case REQ_DRIVE_RESET:
                return ide_do_reset(drive);
        default:
@@ -820,63 +638,6 @@ plug_device_2:
                blk_plug_device(q);
 }
 
-/*
- * un-busy the port etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq;
-       ide_startstop_t ret = ide_stopped;
-
-       /*
-        * end current dma transaction
-        */
-
-       if (error < 0) {
-               printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
-               (void)hwif->dma_ops->dma_end(drive);
-               ret = ide_error(drive, "dma timeout error",
-                               hwif->tp_ops->read_status(hwif));
-       } else {
-               printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
-               hwif->dma_ops->dma_timeout(drive);
-       }
-
-       /*
-        * disable dma for now, but remember that we did so because of
-        * a timeout -- we'll reenable after we finish this next request
-        * (or rather the first chunk of it) in pio.
-        */
-       drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
-       drive->retry_pio++;
-       ide_dma_off_quietly(drive);
-
-       /*
-        * un-busy drive etc and make sure request is sane
-        */
-
-       rq = hwif->rq;
-       if (!rq)
-               goto out;
-
-       hwif->rq = NULL;
-
-       rq->errors = 0;
-
-       if (!rq->bio)
-               goto out;
-
-       rq->sector = rq->bio->bi_sector;
-       rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-       rq->hard_cur_sectors = rq->current_nr_sectors;
-       rq->buffer = bio_data(rq->bio);
-out:
-       return ret;
-}
-
 static void ide_plug_device(ide_drive_t *drive)
 {
        struct request_queue *q = drive->queue;
@@ -888,6 +649,29 @@ static void ide_plug_device(ide_drive_t *drive)
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
+static int drive_is_ready(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 stat = 0;
+
+       if (drive->waiting_for_dma)
+               return hwif->dma_ops->dma_test_irq(drive);
+
+       if (hwif->io_ports.ctl_addr &&
+           (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
+               stat = hwif->tp_ops->read_altstatus(hwif);
+       else
+               /* Note: this may clear a pending IRQ!! */
+               stat = hwif->tp_ops->read_status(hwif);
+
+       if (stat & ATA_BUSY)
+               /* drive busy: definitely not interrupting */
+               return 0;
+
+       /* drive ready: *might* be interrupting */
+       return 1;
+}
+
 /**
  *     ide_timer_expiry        -       handle lack of an IDE interrupt
  *     @data: timer callback magic (hwif)
@@ -1164,54 +948,6 @@ out_early:
 }
 EXPORT_SYMBOL_GPL(ide_intr);
 
-/**
- *     ide_do_drive_cmd        -       issue IDE special command
- *     @drive: device to issue command
- *     @rq: request to issue
- *
- *     This function issues a special IDE device request
- *     onto the request queue.
- *
- *     the rq is queued at the head of the request queue, displacing
- *     the currently-being-processed request and this function
- *     returns immediately without waiting for the new rq to be
- *     completed.  This is VERY DANGEROUS, and is intended for
- *     careful use by the ATAPI tape/cdrom driver code.
- */
-
-void ide_do_drive_cmd(ide_drive_t *drive, struct request *rq)
-{
-       struct request_queue *q = drive->queue;
-       unsigned long flags;
-
-       drive->hwif->rq = NULL;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-EXPORT_SYMBOL(ide_do_drive_cmd);
-
-void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       ide_task_t task;
-
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
-                       IDE_TFLAG_OUT_FEATURE | tf_flags;
-       task.tf.feature = dma;          /* Use PIO/DMA */
-       task.tf.lbam    = bcount & 0xff;
-       task.tf.lbah    = (bcount >> 8) & 0xff;
-
-       ide_tf_dump(drive->name, &task.tf);
-       hwif->tp_ops->set_irq(hwif, 1);
-       SELECT_MASK(drive, 0);
-       hwif->tp_ops->tf_load(drive, &task);
-}
-
-EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
-
 void ide_pad_transfer(ide_drive_t *drive, int write, int len)
 {
        ide_hwif_t *hwif = drive->hwif;
index b1892bd95c6fe5e7d270e3b92e2fd825b6847cb3..317c5dadd7c0220b3021049bc2bb2415eb0e0172 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/*
- *     Conventional PIO operations for ATA devices
- */
-
-static u8 ide_inb (unsigned long port)
-{
-       return (u8) inb(port);
-}
-
-static void ide_outb (u8 val, unsigned long port)
-{
-       outb(val, port);
-}
-
-/*
- *     MMIO operations, typically used for SATA controllers
- */
-
-static u8 ide_mm_inb (unsigned long port)
-{
-       return (u8) readb((void __iomem *) port);
-}
-
-static void ide_mm_outb (u8 value, unsigned long port)
-{
-       writeb(value, (void __iomem *) port);
-}
-
-void SELECT_DRIVE (ide_drive_t *drive)
+void SELECT_DRIVE(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_port_ops *port_ops = hwif->port_ops;
@@ -78,277 +50,6 @@ void SELECT_MASK(ide_drive_t *drive, int mask)
                port_ops->maskproc(drive, mask);
 }
 
-void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
-       else
-               outb(cmd, hwif->io_ports.command_addr);
-}
-EXPORT_SYMBOL_GPL(ide_exec_command);
-
-u8 ide_read_status(ide_hwif_t *hwif)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return readb((void __iomem *)hwif->io_ports.status_addr);
-       else
-               return inb(hwif->io_ports.status_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_status);
-
-u8 ide_read_altstatus(ide_hwif_t *hwif)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return readb((void __iomem *)hwif->io_ports.ctl_addr);
-       else
-               return inb(hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_altstatus);
-
-void ide_set_irq(ide_hwif_t *hwif, int on)
-{
-       u8 ctl = ATA_DEVCTL_OBS;
-
-       if (on == 4) { /* hack for SRST */
-               ctl |= 4;
-               on &= ~4;
-       }
-
-       ctl |= on ? 0 : 2;
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
-       else
-               outb(ctl, hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_set_irq);
-
-void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       void (*tf_outb)(u8 addr, unsigned long port);
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
-
-       if (mmio)
-               tf_outb = ide_mm_outb;
-       else
-               tf_outb = ide_outb;
-
-       if (task->tf_flags & IDE_TFLAG_FLAGGED)
-               HIHI = 0xFF;
-
-       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
-               u16 data = (tf->hob_data << 8) | tf->data;
-
-               if (mmio)
-                       writew(data, (void __iomem *)io_ports->data_addr);
-               else
-                       outw(data, io_ports->data_addr);
-       }
-
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
-               tf_outb(tf->hob_feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
-               tf_outb(tf->hob_nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
-               tf_outb(tf->hob_lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
-               tf_outb(tf->hob_lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
-               tf_outb(tf->hob_lbah, io_ports->lbah_addr);
-
-       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
-               tf_outb(tf->feature, io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
-               tf_outb(tf->nsect, io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
-               tf_outb(tf->lbal, io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
-               tf_outb(tf->lbam, io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
-               tf_outb(tf->lbah, io_ports->lbah_addr);
-
-       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-               tf_outb((tf->device & HIHI) | drive->select,
-                        io_ports->device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_tf_load);
-
-void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_taskfile *tf = &task->tf;
-       void (*tf_outb)(u8 addr, unsigned long port);
-       u8 (*tf_inb)(unsigned long port);
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       if (mmio) {
-               tf_outb = ide_mm_outb;
-               tf_inb  = ide_mm_inb;
-       } else {
-               tf_outb = ide_outb;
-               tf_inb  = ide_inb;
-       }
-
-       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-               u16 data;
-
-               if (mmio)
-                       data = readw((void __iomem *)io_ports->data_addr);
-               else
-                       data = inw(io_ports->data_addr);
-
-               tf->data = data & 0xff;
-               tf->hob_data = (data >> 8) & 0xff;
-       }
-
-       /* be sure we're looking at the low order bits */
-       tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
-
-       if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
-               tf->feature = tf_inb(io_ports->feature_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
-               tf->nsect  = tf_inb(io_ports->nsect_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
-               tf->lbal   = tf_inb(io_ports->lbal_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
-               tf->lbam   = tf_inb(io_ports->lbam_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
-               tf->lbah   = tf_inb(io_ports->lbah_addr);
-       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
-               tf->device = tf_inb(io_ports->device_addr);
-
-       if (task->tf_flags & IDE_TFLAG_LBA48) {
-               tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
-
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-                       tf->hob_feature = tf_inb(io_ports->feature_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-                       tf->hob_nsect   = tf_inb(io_ports->nsect_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-                       tf->hob_lbal    = tf_inb(io_ports->lbal_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-                       tf->hob_lbam    = tf_inb(io_ports->lbam_addr);
-               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-                       tf->hob_lbah    = tf_inb(io_ports->lbah_addr);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_tf_read);
-
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static void ata_vlb_sync(unsigned long port)
-{
-       (void)inb(port);
-       (void)inb(port);
-       (void)inb(port);
-}
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd len is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
-                   unsigned int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long data_addr = io_ports->data_addr;
-       u8 io_32bit = drive->io_32bit;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       len++;
-
-       if (io_32bit) {
-               unsigned long uninitialized_var(flags);
-
-               if ((io_32bit & 2) && !mmio) {
-                       local_irq_save(flags);
-                       ata_vlb_sync(io_ports->nsect_addr);
-               }
-
-               if (mmio)
-                       __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
-               else
-                       insl(data_addr, buf, len / 4);
-
-               if ((io_32bit & 2) && !mmio)
-                       local_irq_restore(flags);
-
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_insw((void __iomem *)data_addr,
-                                               (u8 *)buf + (len & ~3), 1);
-                       else
-                               insw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       insw(data_addr, buf, len / 2);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_input_data);
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
-                    unsigned int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long data_addr = io_ports->data_addr;
-       u8 io_32bit = drive->io_32bit;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       len++;
-
-       if (io_32bit) {
-               unsigned long uninitialized_var(flags);
-
-               if ((io_32bit & 2) && !mmio) {
-                       local_irq_save(flags);
-                       ata_vlb_sync(io_ports->nsect_addr);
-               }
-
-               if (mmio)
-                       __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
-               else
-                       outsl(data_addr, buf, len / 4);
-
-               if ((io_32bit & 2) && !mmio)
-                       local_irq_restore(flags);
-
-               if ((len & 3) >= 2) {
-                       if (mmio)
-                               __ide_mm_outsw((void __iomem *)data_addr,
-                                                (u8 *)buf + (len & ~3), 1);
-                       else
-                               outsw(data_addr, (u8 *)buf + (len & ~3), 1);
-               }
-       } else {
-               if (mmio)
-                       __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
-               else
-                       outsw(data_addr, buf, len / 2);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_output_data);
-
 u8 ide_read_error(ide_drive_t *drive)
 {
        ide_task_t task;
@@ -362,35 +63,6 @@ u8 ide_read_error(ide_drive_t *drive)
 }
 EXPORT_SYMBOL_GPL(ide_read_error);
 
-void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
-{
-       ide_task_t task;
-
-       memset(&task, 0, sizeof(task));
-       task.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
-                       IDE_TFLAG_IN_NSECT;
-
-       drive->hwif->tp_ops->tf_read(drive, &task);
-
-       *bcount = (task.tf.lbah << 8) | task.tf.lbam;
-       *ireason = task.tf.nsect & 3;
-}
-EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
-
-const struct ide_tp_ops default_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-
-       .set_irq                = ide_set_irq,
-
-       .tf_load                = ide_tf_load,
-       .tf_read                = ide_tf_read,
-
-       .input_data             = ide_input_data,
-       .output_data            = ide_output_data,
-};
-
 void ide_fix_driveid(u16 *id)
 {
 #ifndef __LITTLE_ENDIAN
@@ -412,7 +84,7 @@ void ide_fix_driveid(u16 *id)
  * returned by the ATA_CMD_ID_ATA[PI] commands.
  */
 
-void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+void ide_fixstring(u8 *s, const int bytecount, const int byteswap)
 {
        u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
 
@@ -435,43 +107,8 @@ void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
        while (p != end)
                *p++ = '\0';
 }
-
 EXPORT_SYMBOL(ide_fixstring);
 
-/*
- * Needed for PCI irq sharing
- */
-int drive_is_ready (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       u8 stat                 = 0;
-
-       if (drive->waiting_for_dma)
-               return hwif->dma_ops->dma_test_irq(drive);
-
-       /*
-        * We do a passive status test under shared PCI interrupts on
-        * cards that truly share the ATA side interrupt, but may also share
-        * an interrupt with another pci card/device.  We make no assumptions
-        * about possible isa-pnp and pci-pnp issues yet.
-        */
-       if (hwif->io_ports.ctl_addr &&
-           (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
-               stat = hwif->tp_ops->read_altstatus(hwif);
-       else
-               /* Note: this may clear a pending IRQ!! */
-               stat = hwif->tp_ops->read_status(hwif);
-
-       if (stat & ATA_BUSY)
-               /* drive busy:  definitely not interrupting */
-               return 0;
-
-       /* drive ready: *might* be interrupting */
-       return 1;
-}
-
-EXPORT_SYMBOL(drive_is_ready);
-
 /*
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
@@ -483,7 +120,8 @@ EXPORT_SYMBOL(drive_is_ready);
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
+                          unsigned long timeout, u8 *rstat)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
@@ -541,7 +179,8 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
  * The caller should return the updated value of "startstop" in this case,
  * "startstop" is unchanged when the function returns 0.
  */
-int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good,
+                 u8 bad, unsigned long timeout)
 {
        int err;
        u8 stat;
@@ -561,7 +200,6 @@ int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 ba
 
        return err;
 }
-
 EXPORT_SYMBOL(ide_wait_stat);
 
 /**
@@ -582,7 +220,6 @@ int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
                        return 1;
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(ide_in_drive_list);
 
 /*
@@ -607,7 +244,7 @@ static const struct drive_list_entry ivb_list[] = {
  *  All hosts that use the 80c ribbon must use!
  *  The name is derived from upper byte of word 93 and the 80c ribbon.
  */
-u8 eighty_ninty_three (ide_drive_t *drive)
+u8 eighty_ninty_three(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        u16 *id = drive->id;
@@ -652,47 +289,19 @@ no_80w:
 
 int ide_driveid_update(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u16 *id;
-       unsigned long flags;
-       u8 stat;
-
-       /*
-        * Re-read drive->id for possible DMA mode
-        * change (copied from ide-probe.c)
-        */
-
-       SELECT_MASK(drive, 1);
-       tp_ops->set_irq(hwif, 0);
-       msleep(50);
-       tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
+       int rc;
 
-       if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
-               SELECT_MASK(drive, 0);
+       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
+       if (id == NULL)
                return 0;
-       }
-
-       msleep(50);     /* wait for IRQ and ATA_DRQ */
-       stat = tp_ops->read_status(hwif);
 
-       if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
-               SELECT_MASK(drive, 0);
-               printk("%s: CHECK for good STATUS\n", drive->name);
-               return 0;
-       }
-       local_irq_save(flags);
+       SELECT_MASK(drive, 1);
+       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id);
        SELECT_MASK(drive, 0);
-       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
-       if (!id) {
-               local_irq_restore(flags);
-               return 0;
-       }
-       tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
-       (void)tp_ops->read_status(hwif);        /* clear drive IRQ */
-       local_irq_enable();
-       local_irq_restore(flags);
-       ide_fix_driveid(id);
+
+       if (rc)
+               goto out_err;
 
        drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
        drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
@@ -705,6 +314,12 @@ int ide_driveid_update(ide_drive_t *drive)
                ide_dma_off(drive);
 
        return 1;
+out_err:
+       SELECT_MASK(drive, 0);
+       if (rc == 2)
+               printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
+       kfree(id);
+       return 0;
 }
 
 int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
@@ -731,18 +346,15 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
         * but for some reason these don't work at
         * this point (lost interrupt).
         */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-       disable_irq_nosync(hwif->irq);
-       
+
        /*
         *      FIXME: we race against the running IRQ here if
         *      this is called from non IRQ context. If we use
         *      disable_irq() we hang on the error path. Work
         *      is needed.
         */
-        
+       disable_irq_nosync(hwif->irq);
+
        udelay(1);
        SELECT_DRIVE(drive);
        SELECT_MASK(drive, 1);
@@ -812,8 +424,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
  *
  * See also ide_execute_command
  */
-static void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-                     unsigned int timeout, ide_expiry_t *expiry)
+void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
+                      unsigned int timeout, ide_expiry_t *expiry)
 {
        ide_hwif_t *hwif = drive->hwif;
 
@@ -835,9 +447,8 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
        __ide_set_handler(drive, handler, timeout, expiry);
        spin_unlock_irqrestore(&hwif->lock, flags);
 }
-
 EXPORT_SYMBOL(ide_set_handler);
+
 /**
  *     ide_execute_command     -       execute an IDE command
  *     @drive: IDE drive to issue the command against
@@ -847,7 +458,7 @@ EXPORT_SYMBOL(ide_set_handler);
  *     @expiry:  handler to run on timeout
  *
  *     Helper function to issue an IDE command. This handles the
- *     atomicity requirements, command timing and ensures that the 
+ *     atomicity requirements, command timing and ensures that the
  *     handler and IRQ setup do not race. All IDE command kick off
  *     should go via this function or do equivalent locking.
  */
@@ -884,301 +495,6 @@ void ide_execute_pkt_cmd(ide_drive_t *drive)
 }
 EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
 
-static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
-{
-       struct request *rq = drive->hwif->rq;
-
-       if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
-               ide_end_request(drive, err ? err : 1, 0);
-}
-
-/* needed below */
-static ide_startstop_t do_reset1 (ide_drive_t *, int);
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 stat;
-
-       SELECT_DRIVE(drive);
-       udelay (10);
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (OK_STAT(stat, 0, ATA_BUSY))
-               printk("%s: ATAPI reset complete\n", drive->name);
-       else {
-               if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
-                       /* continue polling */
-                       return ide_started;
-               }
-               /* end of polling */
-               hwif->polling = 0;
-               printk("%s: ATAPI reset timed-out, status=0x%02x\n",
-                               drive->name, stat);
-               /* do it the old fashioned way */
-               return do_reset1(drive, 1);
-       }
-       /* done polling */
-       hwif->polling = 0;
-       ide_complete_drive_reset(drive, 0);
-       return ide_stopped;
-}
-
-static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
-{
-       static const char *err_master_vals[] =
-               { NULL, "passed", "formatter device error",
-                 "sector buffer error", "ECC circuitry error",
-                 "controlling MPU error" };
-
-       u8 err_master = err & 0x7f;
-
-       printk(KERN_ERR "%s: reset: master: ", hwif->name);
-       if (err_master && err_master < 6)
-               printk(KERN_CONT "%s", err_master_vals[err_master]);
-       else
-               printk(KERN_CONT "error (0x%02x?)", err);
-       if (err & 0x80)
-               printk(KERN_CONT "; slave: failed");
-       printk(KERN_CONT "\n");
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       u8 tmp;
-       int err = 0;
-
-       if (port_ops && port_ops->reset_poll) {
-               err = port_ops->reset_poll(drive);
-               if (err) {
-                       printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
-                               hwif->name, drive->name);
-                       goto out;
-               }
-       }
-
-       tmp = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(tmp, 0, ATA_BUSY)) {
-               if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
-                       /* continue polling */
-                       return ide_started;
-               }
-               printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
-               drive->failures++;
-               err = -EIO;
-       } else  {
-               tmp = ide_read_error(drive);
-
-               if (tmp == 1) {
-                       printk(KERN_INFO "%s: reset: success\n", hwif->name);
-                       drive->failures = 0;
-               } else {
-                       ide_reset_report_error(hwif, tmp);
-                       drive->failures++;
-                       err = -EIO;
-               }
-       }
-out:
-       hwif->polling = 0;      /* done polling */
-       ide_complete_drive_reset(drive, err);
-       return ide_stopped;
-}
-
-static void ide_disk_pre_reset(ide_drive_t *drive)
-{
-       int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
-
-       drive->special.all = 0;
-       drive->special.b.set_geometry = legacy;
-       drive->special.b.recalibrate  = legacy;
-
-       drive->mult_count = 0;
-       drive->dev_flags &= ~IDE_DFLAG_PARKED;
-
-       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
-           (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
-               drive->mult_req = 0;
-
-       if (drive->mult_req != drive->mult_count)
-               drive->special.b.set_multmode = 1;
-}
-
-static void pre_reset(ide_drive_t *drive)
-{
-       const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-
-       if (drive->media == ide_disk)
-               ide_disk_pre_reset(drive);
-       else
-               drive->dev_flags |= IDE_DFLAG_POST_RESET;
-
-       if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
-               if (drive->crc_count)
-                       ide_check_dma_crc(drive);
-               else
-                       ide_dma_off(drive);
-       }
-
-       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
-               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
-                       drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-                       drive->io_32bit = 0;
-               }
-               return;
-       }
-
-       if (port_ops && port_ops->pre_reset)
-               port_ops->pre_reset(drive);
-
-       if (drive->current_speed != 0xff)
-               drive->desired_speed = drive->current_speed;
-       drive->current_speed = 0xff;
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       const struct ide_port_ops *port_ops;
-       ide_drive_t *tdrive;
-       unsigned long flags, timeout;
-       int i;
-       DEFINE_WAIT(wait);
-
-       spin_lock_irqsave(&hwif->lock, flags);
-
-       /* We must not reset with running handlers */
-       BUG_ON(hwif->handler != NULL);
-
-       /* For an ATAPI device, first try an ATAPI SRST. */
-       if (drive->media != ide_disk && !do_not_try_atapi) {
-               pre_reset(drive);
-               SELECT_DRIVE(drive);
-               udelay (20);
-               tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
-               ndelay(400);
-               hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
-               hwif->polling = 1;
-               __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               return ide_started;
-       }
-
-       /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
-       do {
-               unsigned long now;
-
-               prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
-               timeout = jiffies;
-               ide_port_for_each_dev(i, tdrive, hwif) {
-                       if (tdrive->dev_flags & IDE_DFLAG_PRESENT &&
-                           tdrive->dev_flags & IDE_DFLAG_PARKED &&
-                           time_after(tdrive->sleep, timeout))
-                               timeout = tdrive->sleep;
-               }
-
-               now = jiffies;
-               if (time_before_eq(timeout, now))
-                       break;
-
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               timeout = schedule_timeout_uninterruptible(timeout - now);
-               spin_lock_irqsave(&hwif->lock, flags);
-       } while (timeout);
-       finish_wait(&ide_park_wq, &wait);
-
-       /*
-        * First, reset any device state data we were maintaining
-        * for any of the drives on this interface.
-        */
-       ide_port_for_each_dev(i, tdrive, hwif)
-               pre_reset(tdrive);
-
-       if (io_ports->ctl_addr == 0) {
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               ide_complete_drive_reset(drive, -ENXIO);
-               return ide_stopped;
-       }
-
-       /*
-        * Note that we also set nIEN while resetting the device,
-        * to mask unwanted interrupts from the interface during the reset.
-        * However, due to the design of PC hardware, this will cause an
-        * immediate interrupt due to the edge transition it produces.
-        * This single interrupt gives us a "fast poll" for drives that
-        * recover from reset very quickly, saving us the first 50ms wait time.
-        *
-        * TODO: add ->softreset method and stop abusing ->set_irq
-        */
-       /* set SRST and nIEN */
-       tp_ops->set_irq(hwif, 4);
-       /* more than enough time */
-       udelay(10);
-       /* clear SRST, leave nIEN (unless device is on the quirk list) */
-       tp_ops->set_irq(hwif, drive->quirk_list == 2);
-       /* more than enough time */
-       udelay(10);
-       hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
-       hwif->polling = 1;
-       __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
-
-       /*
-        * Some weird controller like resetting themselves to a strange
-        * state when the disks are reset this way. At least, the Winbond
-        * 553 documentation says that
-        */
-       port_ops = hwif->port_ops;
-       if (port_ops && port_ops->resetproc)
-               port_ops->resetproc(drive);
-
-       spin_unlock_irqrestore(&hwif->lock, flags);
-       return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
-       return do_reset1(drive, 0);
-}
-
-EXPORT_SYMBOL(ide_do_reset);
-
 /*
  * ide_wait_not_busy() waits for the currently selected device on the hwif
  * to report a non-busy status, see comments in ide_probe_port().
@@ -1187,7 +503,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
 {
        u8 stat = 0;
 
-       while(timeout--) {
+       while (timeout--) {
                /*
                 * Turn this into a schedule() sleep once I'm sure
                 * about locking issues (2.5 work ?).
index 09526a0de734f279cb3f055460ff4a4add0baed1..f6c683dd29873bad3ef622e6defe6785ed6f1b39 100644 (file)
@@ -5,163 +5,6 @@
 #include <linux/ide.h>
 #include <linux/bitops.h>
 
-static const char *udma_str[] =
-        { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
-          "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
-static const char *mwdma_str[] =
-       { "MWDMA0", "MWDMA1", "MWDMA2" };
-static const char *swdma_str[] =
-       { "SWDMA0", "SWDMA1", "SWDMA2" };
-static const char *pio_str[] =
-       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
-
-/**
- *     ide_xfer_verbose        -       return IDE mode names
- *     @mode: transfer mode
- *
- *     Returns a constant string giving the name of the mode
- *     requested.
- */
-
-const char *ide_xfer_verbose(u8 mode)
-{
-       const char *s;
-       u8 i = mode & 0xf;
-
-       if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
-               s = udma_str[i];
-       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
-               s = mwdma_str[i];
-       else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
-               s = swdma_str[i];
-       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
-               s = pio_str[i & 0x7];
-       else if (mode == XFER_PIO_SLOW)
-               s = "PIO SLOW";
-       else
-               s = "XFER ERROR";
-
-       return s;
-}
-EXPORT_SYMBOL(ide_xfer_verbose);
-
-/**
- *     ide_rate_filter         -       filter transfer mode
- *     @drive: IDE device
- *     @speed: desired speed
- *
- *     Given the available transfer modes this function returns
- *     the best available speed at or below the speed requested.
- *
- *     TODO: check device PIO capabilities
- */
-
-static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 mode = ide_find_dma_mode(drive, speed);
-
-       if (mode == 0) {
-               if (hwif->pio_mask)
-                       mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
-               else
-                       mode = XFER_PIO_4;
-       }
-
-/*     printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
-
-       return min(speed, mode);
-}
-
-/**
- *     ide_get_best_pio_mode   -       get PIO mode from drive
- *     @drive: drive to consider
- *     @mode_wanted: preferred mode
- *     @max_mode: highest allowed mode
- *
- *     This routine returns the recommended PIO settings for a given drive,
- *     based on the drive->id information and the ide_pio_blacklist[].
- *
- *     Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
- *     This is used by most chipset support modules when "auto-tuning".
- */
-
-u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
-{
-       u16 *id = drive->id;
-       int pio_mode = -1, overridden = 0;
-
-       if (mode_wanted != 255)
-               return min_t(u8, mode_wanted, max_mode);
-
-       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
-               pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
-
-       if (pio_mode != -1) {
-               printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
-       } else {
-               pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
-               if (pio_mode > 2) {     /* 2 is maximum allowed tPIO value */
-                       pio_mode = 2;
-                       overridden = 1;
-               }
-
-               if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
-                       if (ata_id_has_iordy(id)) {
-                               if (id[ATA_ID_PIO_MODES] & 7) {
-                                       overridden = 0;
-                                       if (id[ATA_ID_PIO_MODES] & 4)
-                                               pio_mode = 5;
-                                       else if (id[ATA_ID_PIO_MODES] & 2)
-                                               pio_mode = 4;
-                                       else
-                                               pio_mode = 3;
-                               }
-                       }
-               }
-
-               if (overridden)
-                       printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
-                                        drive->name);
-       }
-
-       if (pio_mode > max_mode)
-               pio_mode = max_mode;
-
-       return pio_mode;
-}
-EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
-
-/* req_pio == "255" for auto-tune */
-void ide_set_pio(ide_drive_t *drive, u8 req_pio)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       u8 host_pio, pio;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return;
-
-       BUG_ON(hwif->pio_mask == 0x00);
-
-       host_pio = fls(hwif->pio_mask) - 1;
-
-       pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
-
-       /*
-        * TODO:
-        * - report device max PIO mode
-        * - check req_pio != 255 against device max PIO mode
-        */
-       printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
-                         drive->name, host_pio, req_pio,
-                         req_pio == 255 ? "(auto-tune)" : "", pio);
-
-       (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
-}
-EXPORT_SYMBOL_GPL(ide_set_pio);
-
 /**
  *     ide_toggle_bounce       -       handle bounce buffering
  *     @drive: drive to update
@@ -188,89 +31,6 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
                blk_queue_bounce_limit(drive->queue, addr);
 }
 
-int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
-               return 0;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL)
-               return -1;
-
-       /*
-        * TODO: temporary hack for some legacy host drivers that didn't
-        * set transfer mode on the device in ->set_pio_mode method...
-        */
-       if (port_ops->set_dma_mode == NULL) {
-               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
-               return 0;
-       }
-
-       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
-               if (ide_config_drive_speed(drive, mode))
-                       return -1;
-               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
-               return 0;
-       } else {
-               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
-               return ide_config_drive_speed(drive, mode);
-       }
-}
-
-int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
-               return 0;
-
-       if (port_ops == NULL || port_ops->set_dma_mode == NULL)
-               return -1;
-
-       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
-               if (ide_config_drive_speed(drive, mode))
-                       return -1;
-               port_ops->set_dma_mode(drive, mode);
-               return 0;
-       } else {
-               port_ops->set_dma_mode(drive, mode);
-               return ide_config_drive_speed(drive, mode);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_set_dma_mode);
-
-/**
- *     ide_set_xfer_rate       -       set transfer rate
- *     @drive: drive to set
- *     @rate: speed to attempt to set
- *
- *     General helper for setting the speed of an IDE device. This
- *     function knows about user enforced limits from the configuration
- *     which ->set_pio_mode/->set_dma_mode does not.
- */
-
-int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return -1;
-
-       rate = ide_rate_filter(drive, rate);
-
-       BUG_ON(rate < XFER_PIO_0);
-
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
-               return ide_set_pio_mode(drive, rate);
-
-       return ide_set_dma_mode(drive, rate);
-}
-
 static void ide_dump_opcode(ide_drive_t *drive)
 {
        struct request *rq = drive->hwif->rq;
index c875a957596c56f2b505cb272005028f57574922..f30e52152fcbf1e2d3609998ef282eaf6b9a5f21 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/jiffies.h>
 #include <linux/blkdev.h>
 
@@ -60,6 +61,30 @@ out:
        return;
 }
 
+ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
+{
+       ide_task_t task;
+       struct ide_taskfile *tf = &task.tf;
+
+       memset(&task, 0, sizeof(task));
+       if (rq->cmd[0] == REQ_PARK_HEADS) {
+               drive->sleep = *(unsigned long *)rq->special;
+               drive->dev_flags |= IDE_DFLAG_SLEEPING;
+               tf->command = ATA_CMD_IDLEIMMEDIATE;
+               tf->feature = 0x44;
+               tf->lbal = 0x4c;
+               tf->lbam = 0x4e;
+               tf->lbah = 0x55;
+               task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+       } else          /* cmd == REQ_UNPARK_HEADS */
+               tf->command = ATA_CMD_CHK_POWER;
+
+       task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       task.rq = rq;
+       drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
+       return do_rw_taskfile(drive, &task);
+}
+
 ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
                      char *buf)
 {
index bddae2b329a0e35930e153386eb6c2a15099d6a9..61111fd2713010c8f0948e3017ff0720ed8a47ac 100644 (file)
@@ -33,8 +33,6 @@ static int ide_generic_all;           /* Set to claim all devices */
 module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
 MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
 
-#define IDE_HFLAGS_UMC (IDE_HFLAG_NO_DMA | IDE_HFLAG_FORCE_LEGACY_IRQS)
-
 #define DECLARE_GENERIC_PCI_DEV(extra_flags) \
        { \
                .name           = DRV_NAME, \
@@ -61,7 +59,7 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = {
        /*  2: SAMURAI / HT6565 / HINT_IDE */
        DECLARE_GENERIC_PCI_DEV(0),
        /*  3: UM8673F / UM8886A / UM8886BF */
-       DECLARE_GENERIC_PCI_DEV(IDE_HFLAGS_UMC),
+       DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA),
        /*  4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */
        DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA),
 
index ee8e3e7cad51e6b66ce1737d263633e947e6e29c..974067043fba350d0e42656a8860968139791d14 100644 (file)
@@ -181,16 +181,16 @@ static void ide_classify_atapi_dev(ide_drive_t *drive)
  *     do_identify     -       identify a drive
  *     @drive: drive to identify 
  *     @cmd: command used
+ *     @id: buffer for IDENTIFY data
  *
  *     Called when we have issued a drive identify command to
  *     read and parse the results. This function is run with
  *     interrupts disabled. 
  */
 
-static void do_identify(ide_drive_t *drive, u8 cmd)
+static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
 {
        ide_hwif_t *hwif = drive->hwif;
-       u16 *id = drive->id;
        char *m = (char *)&id[ATA_ID_PROD];
        unsigned long flags;
        int bswap = 1;
@@ -233,16 +233,6 @@ static void do_identify(ide_drive_t *drive, u8 cmd)
        drive->dev_flags |= IDE_DFLAG_PRESENT;
        drive->dev_flags &= ~IDE_DFLAG_DEAD;
 
-       /*
-        * Check for an ATAPI device
-        */
-       if (cmd == ATA_CMD_ID_ATAPI)
-               ide_classify_atapi_dev(drive);
-       else
-       /*
-        * Not an ATAPI device: looks like a "regular" hard disk
-        */
-               ide_classify_ata_dev(drive);
        return;
 err_misc:
        kfree(id);
@@ -250,21 +240,19 @@ err_misc:
 }
 
 /**
- *     actual_try_to_identify  -       send ata/atapi identify
+ *     ide_dev_read_id -       send ATA/ATAPI IDENTIFY command
  *     @drive: drive to identify
  *     @cmd: command to use
+ *     @id: buffer for IDENTIFY data
  *
- *     try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
- *     and waits for a response.  It also monitors irqs while this is
- *     happening, in hope of automatically determining which one is
- *     being used by the interface.
+ *     Sends an ATA(PI) IDENTIFY request to a drive and waits for a response.
  *
  *     Returns:        0  device was identified
  *                     1  device timed-out (no response to identify request)
  *                     2  device aborted the command (refused to identify itself)
  */
 
-static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
+int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
@@ -273,6 +261,13 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        unsigned long timeout;
        u8 s = 0, a = 0;
 
+       /*
+        * Disable device IRQ.  Otherwise we'll get spurious interrupts
+        * during the identify phase that the IRQ handler isn't expecting.
+        */
+       if (io_ports->ctl_addr)
+               tp_ops->set_irq(hwif, 0);
+
        /* take a deep breath */
        msleep(50);
 
@@ -317,7 +312,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 
        if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
                /* drive returned ID */
-               do_identify(drive, cmd);
+               do_identify(drive, cmd, id);
                /* drive responded with ID */
                rc = 0;
                /* clear drive IRQ */
@@ -329,63 +324,6 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        return rc;
 }
 
-/**
- *     try_to_identify -       try to identify a drive
- *     @drive: drive to probe
- *     @cmd: command to use
- *
- *     Issue the identify command and then do IRQ probing to
- *     complete the identification when needed by finding the
- *     IRQ the drive is attached to
- */
-static int try_to_identify (ide_drive_t *drive, u8 cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       int retval;
-       int autoprobe = 0;
-       unsigned long cookie = 0;
-
-       /*
-        * Disable device irq unless we need to
-        * probe for it. Otherwise we'll get spurious
-        * interrupts during the identify-phase that
-        * the irq handler isn't expecting.
-        */
-       if (hwif->io_ports.ctl_addr) {
-               if (!hwif->irq) {
-                       autoprobe = 1;
-                       cookie = probe_irq_on();
-               }
-               tp_ops->set_irq(hwif, autoprobe);
-       }
-
-       retval = actual_try_to_identify(drive, cmd);
-
-       if (autoprobe) {
-               int irq;
-
-               tp_ops->set_irq(hwif, 0);
-               /* clear drive IRQ */
-               (void)tp_ops->read_status(hwif);
-               udelay(5);
-               irq = probe_irq_off(cookie);
-               if (!hwif->irq) {
-                       if (irq > 0) {
-                               hwif->irq = irq;
-                       } else {
-                               /* Mmmm.. multiple IRQs..
-                                * don't know which was ours
-                                */
-                               printk(KERN_ERR "%s: IRQ probe failed (0x%lx)\n",
-                                       drive->name, cookie);
-                       }
-               }
-       }
-       return retval;
-}
-
 int ide_busy_sleep(ide_hwif_t *hwif, unsigned long timeout, int altstatus)
 {
        u8 stat;
@@ -440,6 +378,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+       u16 *id = drive->id;
        int rc;
        u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
 
@@ -475,11 +414,10 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 
        if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
            present || cmd == ATA_CMD_ID_ATAPI) {
-               /* send cmd and wait */
-               if ((rc = try_to_identify(drive, cmd))) {
+               rc = ide_dev_read_id(drive, cmd, id);
+               if (rc)
                        /* failed: try again */
-                       rc = try_to_identify(drive,cmd);
-               }
+                       rc = ide_dev_read_id(drive, cmd, id);
 
                stat = tp_ops->read_status(hwif);
 
@@ -494,7 +432,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        msleep(50);
                        tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                        (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
-                       rc = try_to_identify(drive, cmd);
+                       rc = ide_dev_read_id(drive, cmd, id);
                }
 
                /* ensure drive IRQ is clear */
@@ -517,37 +455,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
        return rc;
 }
 
-/*
- *
- */
-static void enable_nest (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       u8 stat;
-
-       printk(KERN_INFO "%s: enabling %s -- ",
-               hwif->name, (char *)&drive->id[ATA_ID_PROD]);
-
-       SELECT_DRIVE(drive);
-       msleep(50);
-       tp_ops->exec_command(hwif, ATA_EXABYTE_ENABLE_NEST);
-
-       if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 0)) {
-               printk(KERN_CONT "failed (timeout)\n");
-               return;
-       }
-
-       msleep(50);
-
-       stat = tp_ops->read_status(hwif);
-
-       if (!OK_STAT(stat, 0, BAD_STAT))
-               printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
-       else
-               printk(KERN_CONT "success\n");
-}
-
 /**
  *     probe_for_drives        -       upper level drive probe
  *     @drive: drive to probe for
@@ -563,6 +470,8 @@ static void enable_nest (ide_drive_t *drive)
 static u8 probe_for_drive(ide_drive_t *drive)
 {
        char *m;
+       int rc;
+       u8 cmd;
 
        /*
         *      In order to keep things simple we have an id
@@ -586,21 +495,19 @@ static u8 probe_for_drive(ide_drive_t *drive)
 
        /* skip probing? */
        if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
-retry:
                /* if !(success||timed-out) */
-               if (do_probe(drive, ATA_CMD_ID_ATA) >= 2)
+               cmd = ATA_CMD_ID_ATA;
+               rc = do_probe(drive, cmd);
+               if (rc >= 2) {
                        /* look for ATAPI device */
-                       (void)do_probe(drive, ATA_CMD_ID_ATAPI);
+                       cmd = ATA_CMD_ID_ATAPI;
+                       rc = do_probe(drive, cmd);
+               }
 
                if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        /* drive not found */
                        return 0;
 
-               if (strstr(m, "E X A B Y T E N E S T")) {
-                       enable_nest(drive);
-                       goto retry;
-               }
-
                /* identification failed? */
                if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
                        if (drive->media == ide_disk) {
@@ -614,8 +521,12 @@ retry:
                                printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
                                drive->dev_flags &= ~IDE_DFLAG_PRESENT;
                        }
+               } else {
+                       if (cmd == ATA_CMD_ID_ATAPI)
+                               ide_classify_atapi_dev(drive);
+                       else
+                               ide_classify_ata_dev(drive);
                }
-               /* drive was found */
        }
 
        if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
@@ -779,7 +690,6 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave);
 static int ide_probe_port(ide_hwif_t *hwif)
 {
        ide_drive_t *drive;
-       unsigned long flags;
        unsigned int irqd;
        int i, rc = -ENODEV;
 
@@ -797,9 +707,6 @@ static int ide_probe_port(ide_hwif_t *hwif)
        if (irqd)
                disable_irq(hwif->irq);
 
-       local_save_flags(flags);
-       local_irq_enable_in_hardirq();
-
        if (ide_port_wait_ready(hwif) == -EBUSY)
                printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
 
@@ -813,8 +720,6 @@ static int ide_probe_port(ide_hwif_t *hwif)
                        rc = 0;
        }
 
-       local_irq_restore(flags);
-
        /*
         * Use cached IRQ number. It might be (and is...) changed by probe
         * code above
@@ -831,29 +736,18 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        ide_drive_t *drive;
        int i;
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
-                       if (port_ops && port_ops->quirkproc)
-                               port_ops->quirkproc(drive);
-               }
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               if (port_ops && port_ops->quirkproc)
+                       port_ops->quirkproc(drive);
        }
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
-                       ide_set_max_pio(drive);
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               ide_set_max_pio(drive);
 
-                       drive->dev_flags |= IDE_DFLAG_NICE1;
-
-                       if (hwif->dma_ops)
-                               ide_set_dma(drive);
-               }
-       }
+               drive->dev_flags |= IDE_DFLAG_NICE1;
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
-                       drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
-               else
-                       drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
+               if (hwif->dma_ops)
+                       ide_set_dma(drive);
        }
 }
 
@@ -924,10 +818,7 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
        int i, j = 0;
 
        mutex_lock(&ide_cfg_mtx);
-       ide_port_for_each_dev(i, drive, hwif) {
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       continue;
-
+       ide_port_for_each_present_dev(i, drive, hwif) {
                if (ide_init_queue(drive)) {
                        printk(KERN_ERR "ide: failed to init %s\n",
                                        drive->name);
@@ -953,13 +844,6 @@ static int init_irq (ide_hwif_t *hwif)
        irq_handler_t irq_handler;
        int sa = 0;
 
-       mutex_lock(&ide_cfg_mtx);
-       spin_lock_init(&hwif->lock);
-
-       init_timer(&hwif->timer);
-       hwif->timer.function = &ide_timer_expiry;
-       hwif->timer.data = (unsigned long)hwif;
-
        irq_handler = hwif->host->irq_handler;
        if (irq_handler == NULL)
                irq_handler = ide_intr;
@@ -997,10 +881,8 @@ static int init_irq (ide_hwif_t *hwif)
                printk(KERN_CONT " (serialized)");
        printk(KERN_CONT "\n");
 
-       mutex_unlock(&ide_cfg_mtx);
        return 0;
 out_up:
-       mutex_unlock(&ide_cfg_mtx);
        return 1;
 }
 
@@ -1099,14 +981,9 @@ static void drive_release_dev (struct device *dev)
 
 static int hwif_init(ide_hwif_t *hwif)
 {
-       int old_irq;
-
        if (!hwif->irq) {
-               hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
-               if (!hwif->irq) {
-                       printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
-                       return 0;
-               }
+               printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
+               return 0;
        }
 
        if (register_blkdev(hwif->major, hwif->name))
@@ -1124,29 +1001,12 @@ static int hwif_init(ide_hwif_t *hwif)
 
        sg_init_table(hwif->sg_table, hwif->sg_max_nents);
        
-       if (init_irq(hwif) == 0)
-               goto done;
-
-       old_irq = hwif->irq;
-       /*
-        *      It failed to initialise. Find the default IRQ for 
-        *      this port and try that.
-        */
-       hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
-       if (!hwif->irq) {
-               printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
-                       hwif->name, old_irq);
-               goto out;
-       }
        if (init_irq(hwif)) {
-               printk(KERN_ERR "%s: probed IRQ %d and default IRQ %d failed\n",
-                       hwif->name, old_irq, hwif->irq);
+               printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
+                       hwif->name, hwif->irq);
                goto out;
        }
-       printk(KERN_WARNING "%s: probed IRQ %d failed, using default\n",
-               hwif->name, hwif->irq);
 
-done:
        blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
                            THIS_MODULE, ata_probe, ata_lock, hwif);
        return 1;
@@ -1161,13 +1021,10 @@ static void hwif_register_devices(ide_hwif_t *hwif)
        ide_drive_t *drive;
        unsigned int i;
 
-       ide_port_for_each_dev(i, drive, hwif) {
+       ide_port_for_each_present_dev(i, drive, hwif) {
                struct device *dev = &drive->gendev;
                int ret;
 
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       continue;
-
                dev_set_name(dev, "%u.%u", hwif->index, i);
                dev->parent = &hwif->gendev;
                dev->bus = &ide_bus_type;
@@ -1192,6 +1049,8 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
 
                if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
                        drive->io_32bit = 1;
+               if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
+                       drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
                if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
                        drive->dev_flags |= IDE_DFLAG_UNMASK;
                if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
@@ -1213,10 +1072,6 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
        if (d->init_iops)
                d->init_iops(hwif);
 
-       if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
-           (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
-               hwif->irq = port ? 15 : 14;
-
        /* ->host_flags may be set by ->init_iops (or even earlier...) */
        hwif->host_flags |= d->host_flags;
        hwif->pio_mask = d->pio_mask;
@@ -1317,6 +1172,12 @@ static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
        hwif->name[2]   = 'e';
        hwif->name[3]   = '0' + index;
 
+       spin_lock_init(&hwif->lock);
+
+       init_timer(&hwif->timer);
+       hwif->timer.function = &ide_timer_expiry;
+       hwif->timer.data = (unsigned long)hwif;
+
        init_completion(&hwif->gendev_rel_comp);
 
        hwif->tp_ops = &default_tp_ops;
@@ -1567,7 +1428,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
 
                j++;
 
-               ide_acpi_init(hwif);
+               ide_acpi_init_port(hwif);
 
                if (hwif->present)
                        ide_acpi_port_init_devices(hwif);
@@ -1624,11 +1485,9 @@ static void __ide_port_unregister_devices(ide_hwif_t *hwif)
        ide_drive_t *drive;
        int i;
 
-       ide_port_for_each_dev(i, drive, hwif) {
-               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
-                       device_unregister(&drive->gendev);
-                       wait_for_completion(&drive->gendev_rel_comp);
-               }
+       ide_port_for_each_present_dev(i, drive, hwif) {
+               device_unregister(&drive->gendev);
+               wait_for_completion(&drive->gendev_rel_comp);
        }
 }
 
index a7b9287ee0d4309bc30a9fe5d97df93f6f74eb3a..417cde56eafd9766815a067a12480743cb28ea1e 100644 (file)
@@ -600,7 +600,7 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif)
        int i;
 
        ide_port_for_each_dev(i, drive, hwif) {
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0 || drive->proc)
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        continue;
 
                drive->proc = proc_mkdir(drive->name, parent);
diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c
new file mode 100644 (file)
index 0000000..6910f6a
--- /dev/null
@@ -0,0 +1,246 @@
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+
+static const char *udma_str[] =
+        { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
+          "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
+static const char *mwdma_str[] =
+       { "MWDMA0", "MWDMA1", "MWDMA2" };
+static const char *swdma_str[] =
+       { "SWDMA0", "SWDMA1", "SWDMA2" };
+static const char *pio_str[] =
+       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
+
+/**
+ *     ide_xfer_verbose        -       return IDE mode names
+ *     @mode: transfer mode
+ *
+ *     Returns a constant string giving the name of the mode
+ *     requested.
+ */
+
+const char *ide_xfer_verbose(u8 mode)
+{
+       const char *s;
+       u8 i = mode & 0xf;
+
+       if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
+               s = udma_str[i];
+       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
+               s = mwdma_str[i];
+       else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
+               s = swdma_str[i];
+       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
+               s = pio_str[i & 0x7];
+       else if (mode == XFER_PIO_SLOW)
+               s = "PIO SLOW";
+       else
+               s = "XFER ERROR";
+
+       return s;
+}
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ *     ide_get_best_pio_mode   -       get PIO mode from drive
+ *     @drive: drive to consider
+ *     @mode_wanted: preferred mode
+ *     @max_mode: highest allowed mode
+ *
+ *     This routine returns the recommended PIO settings for a given drive,
+ *     based on the drive->id information and the ide_pio_blacklist[].
+ *
+ *     Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
+ *     This is used by most chipset support modules when "auto-tuning".
+ */
+
+u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
+{
+       u16 *id = drive->id;
+       int pio_mode = -1, overridden = 0;
+
+       if (mode_wanted != 255)
+               return min_t(u8, mode_wanted, max_mode);
+
+       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
+               pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
+
+       if (pio_mode != -1) {
+               printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
+       } else {
+               pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
+               if (pio_mode > 2) {     /* 2 is maximum allowed tPIO value */
+                       pio_mode = 2;
+                       overridden = 1;
+               }
+
+               if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
+                       if (ata_id_has_iordy(id)) {
+                               if (id[ATA_ID_PIO_MODES] & 7) {
+                                       overridden = 0;
+                                       if (id[ATA_ID_PIO_MODES] & 4)
+                                               pio_mode = 5;
+                                       else if (id[ATA_ID_PIO_MODES] & 2)
+                                               pio_mode = 4;
+                                       else
+                                               pio_mode = 3;
+                               }
+                       }
+               }
+
+               if (overridden)
+                       printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+                                        drive->name);
+       }
+
+       if (pio_mode > max_mode)
+               pio_mode = max_mode;
+
+       return pio_mode;
+}
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+
+       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+               return 0;
+
+       if (port_ops == NULL || port_ops->set_pio_mode == NULL)
+               return -1;
+
+       /*
+        * TODO: temporary hack for some legacy host drivers that didn't
+        * set transfer mode on the device in ->set_pio_mode method...
+        */
+       if (port_ops->set_dma_mode == NULL) {
+               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       }
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       } else {
+               port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+
+       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+               return 0;
+
+       if (port_ops == NULL || port_ops->set_dma_mode == NULL)
+               return -1;
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               port_ops->set_dma_mode(drive, mode);
+               return 0;
+       } else {
+               port_ops->set_dma_mode(drive, mode);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
+/* req_pio == "255" for auto-tune */
+void ide_set_pio(ide_drive_t *drive, u8 req_pio)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+       u8 host_pio, pio;
+
+       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+               return;
+
+       BUG_ON(hwif->pio_mask == 0x00);
+
+       host_pio = fls(hwif->pio_mask) - 1;
+
+       pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
+
+       /*
+        * TODO:
+        * - report device max PIO mode
+        * - check req_pio != 255 against device max PIO mode
+        */
+       printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
+                         drive->name, host_pio, req_pio,
+                         req_pio == 255 ? "(auto-tune)" : "", pio);
+
+       (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
+}
+EXPORT_SYMBOL_GPL(ide_set_pio);
+
+/**
+ *     ide_rate_filter         -       filter transfer mode
+ *     @drive: IDE device
+ *     @speed: desired speed
+ *
+ *     Given the available transfer modes this function returns
+ *     the best available speed at or below the speed requested.
+ *
+ *     TODO: check device PIO capabilities
+ */
+
+static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 mode = ide_find_dma_mode(drive, speed);
+
+       if (mode == 0) {
+               if (hwif->pio_mask)
+                       mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
+               else
+                       mode = XFER_PIO_4;
+       }
+
+/*     printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
+
+       return min(speed, mode);
+}
+
+/**
+ *     ide_set_xfer_rate       -       set transfer rate
+ *     @drive: drive to set
+ *     @rate: speed to attempt to set
+ *
+ *     General helper for setting the speed of an IDE device. This
+ *     function knows about user enforced limits from the configuration
+ *     which ->set_pio_mode/->set_dma_mode does not.
+ */
+
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_port_ops *port_ops = hwif->port_ops;
+
+       if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
+           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+               return -1;
+
+       rate = ide_rate_filter(drive, rate);
+
+       BUG_ON(rate < XFER_PIO_0);
+
+       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+               return ide_set_pio_mode(drive, rate);
+
+       return ide_set_dma_mode(drive, rate);
+}
index 0920e3b0c962451d6e98cff91bf87e5e150b0afb..92c9b90931e73393f0d47b311b3fb1839483a1df 100644 (file)
 
 struct class *ide_port_class;
 
-/*
- *     Locks for IDE setting functionality
- */
-
-DEFINE_MUTEX(ide_setting_mtx);
-
-ide_devset_get(io_32bit, io_32bit);
-
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
-       if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
-               return -EPERM;
-
-       if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
-               return -EINVAL;
-
-       drive->io_32bit = arg;
-
-       return 0;
-}
-
-ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
-
-static int set_ksettings(ide_drive_t *drive, int arg)
-{
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
-
-       return 0;
-}
-
-ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
-
-static int set_using_dma(ide_drive_t *drive, int arg)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-       int err = -EPERM;
-
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (ata_id_has_dma(drive->id) == 0)
-               goto out;
-
-       if (drive->hwif->dma_ops == NULL)
-               goto out;
-
-       err = 0;
-
-       if (arg) {
-               if (ide_set_dma(drive))
-                       err = -EIO;
-       } else
-               ide_dma_off(drive);
-
-out:
-       return err;
-#else
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       return -EPERM;
-#endif
-}
-
-/*
- * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
- */
-static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
-{
-       switch (req_pio) {
-       case 202:
-       case 201:
-       case 200:
-       case 102:
-       case 101:
-       case 100:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
-       case 9:
-       case 8:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
-       case 7:
-       case 6:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
-       default:
-               return 0;
-       }
-}
-
-static int set_pio_mode(ide_drive_t *drive, int arg)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (arg < 0 || arg > 255)
-               return -EINVAL;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return -ENOSYS;
-
-       if (set_pio_mode_abuse(drive->hwif, arg)) {
-               if (arg == 8 || arg == 9) {
-                       unsigned long flags;
-
-                       /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
-                       spin_lock_irqsave(&hwif->lock, flags);
-                       port_ops->set_pio_mode(drive, arg);
-                       spin_unlock_irqrestore(&hwif->lock, flags);
-               } else
-                       port_ops->set_pio_mode(drive, arg);
-       } else {
-               int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
-               ide_set_pio(drive, arg);
-
-               if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
-                       if (keep_dma)
-                               ide_dma_on(drive);
-               }
-       }
-
-       return 0;
-}
-
-ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
-
-static int set_unmaskirq(ide_drive_t *drive, int arg)
-{
-       if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
-               return -EPERM;
-
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_UNMASK;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-
-       return 0;
-}
-
-ide_ext_devset_rw_sync(io_32bit, io_32bit);
-ide_ext_devset_rw_sync(keepsettings, ksettings);
-ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
-ide_ext_devset_rw_sync(using_dma, using_dma);
-__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
-
 /**
  * ide_device_get      -       get an additional reference to a ide_drive_t
  * @drive:     device to get a reference to
@@ -527,6 +373,8 @@ static int __init ide_init(void)
                goto out_port_class;
        }
 
+       ide_acpi_init();
+
        proc_ide_create();
 
        return 0;
index 13b8153112edf3394235f3009aaefd18e1197bc4..6b9fc950b4af7af786e36e2858a3246979ee48a4 100644 (file)
@@ -603,7 +603,7 @@ static void it8212_disable_raid(struct pci_dev *dev)
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 }
 
-static unsigned int init_chipset_it821x(struct pci_dev *dev)
+static int init_chipset_it821x(struct pci_dev *dev)
 {
        u8 conf;
        static char *mode[2] = { "pass through", "smart" };
index 83643ed9a426d1a43390987871e1839e5769d7eb..ea48a3ee8063960b3a2b204b99a8d9d639a9541f 100644 (file)
@@ -286,9 +286,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
        }
 
        if (!using_inta)
-               hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
-       else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-               hwif->irq = hwif->mate->irq;    /* share IRQ with mate */
+               hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
 
        if (!hwif->dma_base)
                return;
index f21290c4b44761855760b5dcdc17a59dad5509b7..b68906c3c17e49f4223a1c84c2b68f1a17d6f47e 100644 (file)
@@ -325,7 +325,7 @@ static void apple_kiwi_init(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static unsigned int init_chipset_pdcnew(struct pci_dev *dev)
+static int init_chipset_pdcnew(struct pci_dev *dev)
 {
        const char *name = DRV_NAME;
        unsigned long dma_base = pci_resource_start(dev, 4);
@@ -444,7 +444,7 @@ static unsigned int init_chipset_pdcnew(struct pci_dev *dev)
 #endif
 
  out:
-       return dev->irq;
+       return 0;
 }
 
 static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
index 97193323aebfb5e8cbafbf33849cc9fb066f2313..cba66ebce4e341c977baff6b8d311c56c2074382 100644 (file)
@@ -264,7 +264,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
        ide_dma_timeout(drive);
 }
 
-static unsigned int init_chipset_pdc202xx(struct pci_dev *dev)
+static int init_chipset_pdc202xx(struct pci_dev *dev)
 {
        unsigned long dmabase = pci_resource_start(dev, 4);
        u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
@@ -290,7 +290,7 @@ static unsigned int init_chipset_pdc202xx(struct pci_dev *dev)
                printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
        }
 out:
-       return dev->irq;
+       return 0;
 }
 
 static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
index f1e2e4ef0d71d7cb1e18da9da158d58d0fbae48b..2aa69993306458f0bd2d26b1eada58fdff1af01e 100644 (file)
@@ -204,7 +204,7 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
  *     out to be nice and simple.
  */
 
-static unsigned int init_chipset_ich(struct pci_dev *dev)
+static int init_chipset_ich(struct pci_dev *dev)
 {
        u32 extra = 0;
 
@@ -318,19 +318,12 @@ static const struct ide_port_ops ich_port_ops = {
        .cable_detect           = piix_cable_detect,
 };
 
-#ifndef CONFIG_IA64
- #define IDE_HFLAGS_PIIX IDE_HFLAG_LEGACY_IRQS
-#else
- #define IDE_HFLAGS_PIIX 0
-#endif
-
 #define DECLARE_PIIX_DEV(udma) \
        {                                               \
                .name           = DRV_NAME,             \
                .init_hwif      = init_hwif_piix,       \
                .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
                .port_ops       = &piix_port_ops,       \
-               .host_flags     = IDE_HFLAGS_PIIX,      \
                .pio_mask       = ATA_PIO4,             \
                .swdma_mask     = ATA_SWDMA2_ONLY,      \
                .mwdma_mask     = ATA_MWDMA12_ONLY,     \
@@ -344,7 +337,6 @@ static const struct ide_port_ops ich_port_ops = {
                .init_hwif      = init_hwif_piix, \
                .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
                .port_ops       = &ich_port_ops, \
-               .host_flags     = IDE_HFLAGS_PIIX, \
                .pio_mask       = ATA_PIO4, \
                .swdma_mask     = ATA_SWDMA2_ONLY, \
                .mwdma_mask     = ATA_MWDMA12_ONLY, \
@@ -360,8 +352,7 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = {
                 */
                .name           = DRV_NAME,
                .enablebits     = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
-               .host_flags     = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA |
-                                 IDE_HFLAGS_PIIX,
+               .host_flags     = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA,
                .pio_mask       = ATA_PIO4,
                /* This is a painful system best to let it self tune for now */
        },
index 382102ba467be96a053bfb9dd9110bb69c19a3c4..b6554ef92716003567333482982458dd32a0db9b 100644 (file)
@@ -175,7 +175,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
        pci_write_config_byte(dev, 0x54, ultra_enable);
 }
 
-static unsigned int init_chipset_svwks(struct pci_dev *dev)
+static int init_chipset_svwks(struct pci_dev *dev)
 {
        unsigned int reg;
        u8 btr;
@@ -270,7 +270,7 @@ static unsigned int init_chipset_svwks(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x5A, btr);
        }
 
-       return dev->irq;
+       return 0;
 }
 
 static u8 ata66_svwks_svwks(ide_hwif_t *hwif)
@@ -353,14 +353,11 @@ static const struct ide_port_ops svwks_port_ops = {
        .cable_detect           = svwks_cable_detect,
 };
 
-#define IDE_HFLAGS_SVWKS IDE_HFLAG_LEGACY_IRQS
-
 static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
        {       /* 0: OSB4 */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
                .port_ops       = &osb4_port_ops,
-               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = 0x00, /* UDMA is problematic on OSB4 */
@@ -369,7 +366,6 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
                .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -378,7 +374,6 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
                .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -387,7 +382,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
                .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+               .host_flags     = IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -396,7 +391,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
                .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+               .host_flags     = IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
index e85d1ed29c2ac005d37928d61e0d439534f8c9dd..24bc884826fcb1f60da0182c6a1180f80ad47c30 100644 (file)
@@ -305,7 +305,6 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
  *     @dev: PCI device holding interface
  *     @d: IDE port info
  *     @port: port number
- *     @irq: PCI IRQ
  *     @hw: hw_regs_t instance corresponding to this port
  *
  *     Perform the initial set up for the hardware interface structure. This
@@ -316,7 +315,7 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
  */
 
 static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
-                           unsigned int port, int irq, hw_regs_t *hw)
+                           unsigned int port, hw_regs_t *hw)
 {
        unsigned long ctl = 0, base = 0;
 
@@ -344,7 +343,6 @@ static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
        }
 
        memset(hw, 0, sizeof(*hw));
-       hw->irq = irq;
        hw->dev = &dev->dev;
        hw->chipset = d->chipset ? d->chipset : ide_pci;
        ide_std_init_ports(hw, base, ctl | 2);
@@ -448,7 +446,6 @@ out:
  *     ide_pci_setup_ports     -       configure ports/devices on PCI IDE
  *     @dev: PCI device
  *     @d: IDE port info
- *     @pciirq: IRQ line
  *     @hw: hw_regs_t instances corresponding to this PCI IDE device
  *     @hws: hw_regs_t pointers table to update
  *
@@ -462,7 +459,7 @@ out:
  */
 
 void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
-                        int pciirq, hw_regs_t *hw, hw_regs_t **hws)
+                        hw_regs_t *hw, hw_regs_t **hws)
 {
        int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
        u8 tmp;
@@ -481,7 +478,7 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
                        continue;       /* port not enabled */
                }
 
-               if (ide_hw_configure(dev, d, port, pciirq, hw + port))
+               if (ide_hw_configure(dev, d, port, hw + port))
                        continue;
 
                *(hws + port) = hw + port;
@@ -524,7 +521,7 @@ static int do_ide_setup_pci_device(struct pci_dev *dev,
                if (noisy)
                        printk(KERN_INFO "%s %s: not 100%% native mode: will "
                                "probe irqs later\n", d->name, pci_name(dev));
-               pciirq = ret;
+               pciirq = 0;
        } else if (!pciirq && noisy) {
                printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n",
                        d->name, pci_name(dev), pciirq);
@@ -549,7 +546,7 @@ int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
        if (ret < 0)
                goto out;
 
-       ide_pci_setup_ports(dev, d, 0, &hw[0], &hws[0]);
+       ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
 
        host = ide_host_alloc(d, hws);
        if (host == NULL) {
@@ -568,7 +565,11 @@ int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
                goto out;
 
        /* fixup IRQ */
-       hw[1].irq = hw[0].irq = ret;
+       if (ide_pci_is_in_compatibility_mode(dev)) {
+               hw[0].irq = pci_get_legacy_ide_irq(dev, 0);
+               hw[1].irq = pci_get_legacy_ide_irq(dev, 1);
+       } else
+               hw[1].irq = hw[0].irq = ret;
 
        ret = ide_host_register(host, d, hws);
        if (ret)
@@ -591,7 +592,7 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
                if (ret < 0)
                        goto out;
 
-               ide_pci_setup_ports(pdev[i], d, 0, &hw[i*2], &hws[i*2]);
+               ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
        }
 
        host = ide_host_alloc(d, hws);
@@ -619,7 +620,11 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
                        goto out;
 
                /* fixup IRQ */
-               hw[i*2 + 1].irq = hw[i*2].irq = ret;
+               if (ide_pci_is_in_compatibility_mode(pdev[i])) {
+                       hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0);
+                       hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1);
+               } else
+                       hw[i*2 + 1].irq = hw[i*2].irq = ret;
        }
 
        ret = ide_host_register(host, d, hws);
index cb2b352b876b042277e8ee7a5dcb73b1a40acb3b..1811ae9cd8430a60367a93e281f9c7d3c34157f9 100644 (file)
@@ -464,7 +464,7 @@ static void sil_sata_pre_reset(ide_drive_t *drive)
  *     to 133 MHz clocking if the system isn't already set up to do it.
  */
 
-static unsigned int init_chipset_siimage(struct pci_dev *dev)
+static int init_chipset_siimage(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        void __iomem *ioaddr = host->host_priv;
index 9ec1a4a4432cd17fd1e967f48de375066499e3ea..afca22beaadfc3c279ed53693d31e0a98c48779c 100644 (file)
@@ -447,7 +447,7 @@ static int __devinit sis_find_family(struct pci_dev *dev)
        return chipset_family;
 }
 
-static unsigned int init_chipset_sis5513(struct pci_dev *dev)
+static int init_chipset_sis5513(struct pci_dev *dev)
 {
        /* Make general config ops here
           1/ tell IDE channels to operate in Compatibility mode only
@@ -563,7 +563,7 @@ static const struct ide_port_info sis5513_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_sis5513,
        .enablebits     = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
-       .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_NO_AUTODMA,
+       .host_flags     = IDE_HFLAG_NO_AUTODMA,
        .pio_mask       = ATA_PIO4,
        .mwdma_mask     = ATA_MWDMA2,
 };
index 6297956507c00fb7e3222070989f25cce9ba2000..dba213c51baa98f293e007a6b69b3a87ccd1607a 100644 (file)
@@ -271,7 +271,7 @@ static u8 sl82c105_bridge_revision(struct pci_dev *dev)
  * channel 0 here at least, but channel 1 has to be enabled by
  * firmware or arch code. We still set both to 16 bits mode.
  */
-static unsigned int init_chipset_sl82c105(struct pci_dev *dev)
+static int init_chipset_sl82c105(struct pci_dev *dev)
 {
        u32 val;
 
@@ -281,7 +281,7 @@ static unsigned int init_chipset_sl82c105(struct pci_dev *dev)
        val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
        pci_write_config_dword(dev, 0x40, val);
 
-       return dev->irq;
+       return 0;
 }
 
 static const struct ide_port_ops sl82c105_port_ops = {
index 40b4b94a4288771396c64066018dfdd80e4527af..f55d7d6313e8be45def3103f02b86b528f41e297 100644 (file)
@@ -136,7 +136,6 @@ static const struct ide_port_info slc90e66_chipset __devinitdata = {
        .name           = DRV_NAME,
        .enablebits     = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
        .port_ops       = &slc90e66_port_ops,
-       .host_flags     = IDE_HFLAG_LEGACY_IRQS,
        .pio_mask       = ATA_PIO4,
        .swdma_mask     = ATA_SWDMA2_ONLY,
        .mwdma_mask     = ATA_MWDMA12_ONLY,
index b6a1285a40213e24ff3db78f82a5e89b98c446a4..1c09e549c423ca06765e127ff91f73cab73f4716 100644 (file)
@@ -277,9 +277,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
        if (reg & 0x10)
                /* legacy mode */
                hwif->irq = hwif->channel ? 15 : 14;
-       else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-               /* sharing IRQ with mate */
-               hwif->irq = hwif->mate->irq;
 
 #if 1
        {
index 6092fe3f409d7c82e2273d1e626fc926c86ce360..3ff7231e48582187a0d254069439a2f0737894ec 100644 (file)
@@ -267,7 +267,7 @@ static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
  *     and initialize its drive independent registers.
  */
 
-static unsigned int init_chipset_via82cxxx(struct pci_dev *dev)
+static int init_chipset_via82cxxx(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct via82cxxx_dev *vdev = host->host_priv;
@@ -443,16 +443,6 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
        if ((via_config->flags & VIA_NO_UNMASK) == 0)
                d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
 
-#ifdef CONFIG_PPC_CHRP
-       if (machine_is(chrp) && _chrp_type == _CHRP_Pegasos)
-               d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS;
-#endif
-
-#ifdef CONFIG_AMIGAONE
-       if (machine_is(amigaone))
-               d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS;
-#endif
-
        d.udma_mask = via_config->udma_mask;
 
        vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
index e50047bfe9389d6c935a47b53b88632a59ee4ae4..77cfde571bd92b52835399294c8dd6c849e11f3a 100644 (file)
@@ -3,7 +3,7 @@
  *     Based on drivers/usb/iforce.c
  *
  *     Copyright Yaegashi Takeshi, 2001
- *     Adrian McMenamin, 2008
+ *     Adrian McMenamin, 2008 - 2009
  */
 
 #include <linux/kernel.h>
@@ -29,7 +29,7 @@ static void dc_pad_callback(struct mapleq *mq)
        struct maple_device *mapledev = mq->dev;
        struct dc_pad *pad = maple_get_drvdata(mapledev);
        struct input_dev *dev = pad->dev;
-       unsigned char *res = mq->recvbuf;
+       unsigned char *res = mq->recvbuf->buf;
 
        buttons = ~le16_to_cpup((__le16 *)(res + 8));
 
index 22f17a593be78ca2f6bb6fda1a35323e8e06e006..5aa2361aef95be73080e1392185ac57a2275a220 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * SEGA Dreamcast keyboard driver
  * Based on drivers/usb/usbkbd.c
- * Copyright YAEGASHI Takeshi, 2001
- * Porting to 2.6 Copyright Adrian McMenamin, 2007, 2008
+ * Copyright (c) YAEGASHI Takeshi, 2001
+ * Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ static DEFINE_MUTEX(maple_keyb_mutex);
 
 #define NR_SCANCODES 256
 
-MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin");
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk");
 MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
 MODULE_LICENSE("GPL");
 
@@ -115,7 +115,7 @@ static void dc_scan_kbd(struct dc_kbd *kbd)
                                input_event(dev, EV_MSC, MSC_SCAN, code);
                                input_report_key(dev, keycode, 0);
                        } else
-                               printk(KERN_DEBUG "maple_keyb: "
+                               dev_dbg(&dev->dev,
                                        "Unknown key (scancode %#x) released.",
                                        code);
                }
@@ -127,7 +127,7 @@ static void dc_scan_kbd(struct dc_kbd *kbd)
                                input_event(dev, EV_MSC, MSC_SCAN, code);
                                input_report_key(dev, keycode, 1);
                        } else
-                               printk(KERN_DEBUG "maple_keyb: "
+                               dev_dbg(&dev->dev,
                                        "Unknown key (scancode %#x) pressed.",
                                        code);
                }
@@ -140,7 +140,7 @@ static void dc_kbd_callback(struct mapleq *mq)
 {
        struct maple_device *mapledev = mq->dev;
        struct dc_kbd *kbd = maple_get_drvdata(mapledev);
-       unsigned long *buf = mq->recvbuf;
+       unsigned long *buf = (unsigned long *)(mq->recvbuf->buf);
 
        /*
         * We should always get the lock because the only
@@ -159,22 +159,27 @@ static void dc_kbd_callback(struct mapleq *mq)
 
 static int probe_maple_kbd(struct device *dev)
 {
-       struct maple_device *mdev = to_maple_dev(dev);
-       struct maple_driver *mdrv = to_maple_driver(dev->driver);
+       struct maple_device *mdev;
+       struct maple_driver *mdrv;
        int i, error;
        struct dc_kbd *kbd;
        struct input_dev *idev;
 
-       if (!(mdev->function & MAPLE_FUNC_KEYBOARD))
-               return -EINVAL;
+       mdev = to_maple_dev(dev);
+       mdrv = to_maple_driver(dev->driver);
 
        kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
-       idev = input_allocate_device();
-       if (!kbd || !idev) {
+       if (!kbd) {
                error = -ENOMEM;
                goto fail;
        }
 
+       idev = input_allocate_device();
+       if (!idev) {
+               error = -ENOMEM;
+               goto fail_idev_alloc;
+       }
+
        kbd->dev = idev;
        memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode));
 
@@ -195,7 +200,7 @@ static int probe_maple_kbd(struct device *dev)
 
        error = input_register_device(idev);
        if (error)
-               goto fail;
+               goto fail_register;
 
        /* Maple polling is locked to VBLANK - which may be just 50/s */
        maple_getcond_callback(mdev, dc_kbd_callback, HZ/50,
@@ -207,10 +212,12 @@ static int probe_maple_kbd(struct device *dev)
 
        return error;
 
-fail:
+fail_register:
+       maple_set_drvdata(mdev, NULL);
        input_free_device(idev);
+fail_idev_alloc:
        kfree(kbd);
-       maple_set_drvdata(mdev, NULL);
+fail:
        return error;
 }
 
index 5c8a1bcf7ca7436376223ad6a42a469b47cbf743..e1480fb11de3cfd4c1e62744eaf4a4b2bbe2e003 100644 (file)
@@ -219,6 +219,8 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
                  pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
        iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
        iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
+
+       device_init_wakeup(&pdev->dev, 1);
        return 0;
  err5:
        free_irq(irq, pdev);
@@ -253,17 +255,33 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int sh_keysc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
+       unsigned short value;
+
+       value = ioread16(priv->iomem_base + KYCR1_OFFS);
+
+       if (device_may_wakeup(dev))
+               value |= 0x80;
+       else
+               value &= ~0x80;
 
-#define sh_keysc_suspend NULL
-#define sh_keysc_resume NULL
+       iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+       return 0;
+}
+
+static struct dev_pm_ops sh_keysc_dev_pm_ops = {
+       .suspend = sh_keysc_suspend,
+};
 
 struct platform_driver sh_keysc_device_driver = {
        .probe          = sh_keysc_probe,
        .remove         = __devexit_p(sh_keysc_remove),
-       .suspend        = sh_keysc_suspend,
-       .resume         = sh_keysc_resume,
        .driver         = {
                .name   = "sh_keysc",
+               .pm     = &sh_keysc_dev_pm_ops,
        }
 };
 
index ac245e7e96a557445212e50b0987c39c46efd960..3071a52467edc0a2e1afe66f1488cc4e77bc9d37 100644 (file)
@@ -389,8 +389,7 @@ static void gigaset_freecshw(struct cardstate *cs)
 
 static void gigaset_device_release(struct device *dev)
 {
-       struct platform_device *pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev = to_platform_device(dev);
 
        /* adapted from platform_device_release() in drivers/base/platform.c */
        //FIXME is this actually necessary?
index ef2dbfe747141ee3940fa645e700d89d7a173981..ada5ebbaa255d4078c931ec740f82cd4e8f5f405 100644 (file)
@@ -110,7 +110,7 @@ int __init mca_register_device(int bus, struct mca_device *mca_dev)
 
        mca_dev->dev.parent = &mca_bus->dev;
        mca_dev->dev.bus = &mca_bus_type;
-       sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot);
+       dev_set_name(&mca_dev->dev, "%02d:%02X", bus, mca_dev->slot);
        mca_dev->dma_mask = mca_bus->default_dma_mask;
        mca_dev->dev.dma_mask = &mca_dev->dma_mask;
        mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
@@ -151,7 +151,7 @@ struct mca_bus * __devinit mca_attach_bus(int bus)
        if (!mca_bus)
                return NULL;
 
-       sprintf(mca_bus->dev.bus_id,"mca%d",bus);
+       dev_set_name(&mca_bus->dev, "mca%d", bus);
        sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
        if (device_register(&mca_bus->dev)) {
                kfree(mca_bus);
index 4d35308fc1ff76fddf2edf41fc605e2e88ca06c7..393623818ade299a09b61c6d5d245583f06f896a 100644 (file)
@@ -298,7 +298,8 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
        strlcpy(v->card, dev->name, sizeof(v->card));
-       snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev->dev.bus_id);
+       snprintf(v->bus_info, sizeof(v->bus_info),
+                "I2C:%s", dev_name(&dev->dev));
        v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
index 66c755c116dcbc8190f7305257b8201e6bc88496..ce98d955231ae4f505b8e018836698d33a3ebde8 100644 (file)
@@ -803,9 +803,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
                return (-ENOENT);
        }
 
-       card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
-       if (!card)
-               return (-ENOMEM);
+       err = snd_card_create(index[devno], id[devno], THIS_MODULE,
+                             sizeof(snd_cx88_card_t), &card);
+       if (err < 0)
+               return err;
 
        card->private_free = snd_cx88_dev_free;
 
index 2ac738fa6a07e0cd66fac559fd3c9688060dff39..f132e31f6edd8c4bcd7e7262739255437195ec5e 100644 (file)
@@ -448,9 +448,10 @@ static int em28xx_audio_init(struct em28xx *dev)
        printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
                         "Rechberger\n");
 
-       card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
+                             &card);
+       if (err < 0)
+               return err;
 
        spin_lock_init(&adev->slock);
        err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
index c750d3dd57d20c2f8a858c342ada09b21fd1b1c1..8b0b64a89874dcbaa1e591c72af22074477a8c88 100644 (file)
@@ -990,10 +990,10 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
        if (!enable[devnum])
                return -ENODEV;
 
-       card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t));
-
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
+                             sizeof(snd_card_saa7134_t), &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "SAA7134");
 
index cf9d4c7f571a369741456a26576a5714975a1119..8a4b74f3129f7978ba6c6a7e0d1940199d3a8dae 100644 (file)
@@ -34,7 +34,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
        spin_lock_init(&v4l2_dev->lock);
        v4l2_dev->dev = dev;
        snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
-                       dev->driver->name, dev->bus_id);
+                       dev->driver->name, dev_name(dev));
        dev_set_drvdata(dev, v4l2_dev);
        return 0;
 }
index 6063dc2b52e8878d2bd60b01b7a99b632dccdb79..57271cb3b3160a190b55e5043772296575a1ea54 100644 (file)
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(mcp_host_alloc);
 
 int mcp_host_register(struct mcp *mcp)
 {
-       strcpy(mcp->attached_device.bus_id, "mcp0");
+       dev_set_name(&mcp->attached_device, "mcp0");
        return device_register(&mcp->attached_device);
 }
 EXPORT_SYMBOL(mcp_host_register);
index 6860c924f3643a6f8ab679485a8b2e322cb1ac01..fea9085fe52c67e089f38fbded9ae0fb1f83b389 100644 (file)
@@ -492,7 +492,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 
        ucb->dev.class = &ucb1x00_class;
        ucb->dev.parent = &mcp->attached_device;
-       strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id));
+       dev_set_name(&ucb->dev, "ucb1x00");
 
        spin_lock_init(&ucb->lock);
        spin_lock_init(&ucb->io_lock);
index 2b1196e6142c1b951e47655d36ea185ac9466019..e94e92001e7c08f7c02f5d031bce1d0a15120fbb 100644 (file)
@@ -1603,7 +1603,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
 
-       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
+       ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
        if (ret)
                goto err_request_irq;
 
index fb2921f8099dc82910bfb6cc992eddeeae5eda15..0c44d560bf1ab7755eda9f16e86875b545e875fd 100644 (file)
@@ -103,7 +103,7 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
                if (!gpio_is_valid(oms->gpios[i]))
                        continue;
 
-               ret = gpio_request(oms->gpios[i], dev->bus_id);
+               ret = gpio_request(oms->gpios[i], dev_name(dev));
                if (ret < 0) {
                        oms->gpios[i] = -EINVAL;
                        continue;
index 043d50fb6ef65abd085a98cc42fe8ca6942dc85c..729f899a5cd5d71725ab137715d2c5b1c8a45789 100644 (file)
@@ -551,5 +551,15 @@ config MTD_PLATRAM
 
          This selection automatically selects the map_ram driver.
 
-endmenu
+config MTD_VMU
+       tristate "Map driver for Dreamcast VMU"
+       depends on MAPLE
+       help
+         This driver enables access to the Dreamcast Visual Memory Unit (VMU).
+
+         Most Dreamcast users will want to say Y here.
 
+         To build this as a module select M here, the module will be called
+         vmu-flash.
+
+endmenu
index 6d9ba35caf11a26bbeb4caefec9eae1dddcd9940..26b28a7a90b5e19a57baf21502d2dd94fdc349a7 100644 (file)
@@ -61,3 +61,4 @@ obj-$(CONFIG_MTD_PLATRAM)     += plat-ram.o
 obj-$(CONFIG_MTD_OMAP_NOR)     += omap_nor.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
 obj-$(CONFIG_MTD_BFIN_ASYNC)   += bfin-async-flash.o
+obj-$(CONFIG_MTD_VMU)          += vmu-flash.o
index 771139c5bf87b0a644e6d86b67a2858659715b54..e9026cb1c5b2248962e2280628373f33f0f43e2b 100644 (file)
@@ -41,9 +41,8 @@ struct pxa2xx_flash_info {
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 
-static int __init pxa2xx_flash_probe(struct device *dev)
+static int __init pxa2xx_flash_probe(struct platform_device *pdev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
        struct flash_platform_data *flash = pdev->dev.platform_data;
        struct pxa2xx_flash_info *info;
        struct mtd_partition *parts;
@@ -114,15 +113,15 @@ static int __init pxa2xx_flash_probe(struct device *dev)
                add_mtd_device(info->mtd);
        }
 
-       dev_set_drvdata(dev, info);
+       platform_set_drvdata(pdev, info);
        return 0;
 }
 
-static int __exit pxa2xx_flash_remove(struct device *dev)
+static int __exit pxa2xx_flash_remove(struct platform_device *dev)
 {
-       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+       struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
-       dev_set_drvdata(dev, NULL);
+       platform_set_drvdata(dev, NULL);
 
 #ifdef CONFIG_MTD_PARTITIONS
        if (info->nr_parts)
@@ -141,9 +140,9 @@ static int __exit pxa2xx_flash_remove(struct device *dev)
 }
 
 #ifdef CONFIG_PM
-static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
+static int pxa2xx_flash_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+       struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
        int ret = 0;
 
        if (info->mtd && info->mtd->suspend)
@@ -151,17 +150,17 @@ static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
        return ret;
 }
 
-static int pxa2xx_flash_resume(struct device *dev)
+static int pxa2xx_flash_resume(struct platform_device *dev)
 {
-       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+       struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
        if (info->mtd && info->mtd->resume)
                info->mtd->resume(info->mtd);
        return 0;
 }
-static void pxa2xx_flash_shutdown(struct device *dev)
+static void pxa2xx_flash_shutdown(struct platform_device *dev)
 {
-       struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+       struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
        if (info && info->mtd->suspend(info->mtd) == 0)
                info->mtd->resume(info->mtd);
@@ -172,11 +171,13 @@ static void pxa2xx_flash_shutdown(struct device *dev)
 #define pxa2xx_flash_shutdown NULL
 #endif
 
-static struct device_driver pxa2xx_flash_driver = {
-       .name           = "pxa2xx-flash",
-       .bus            = &platform_bus_type,
+static struct platform_driver pxa2xx_flash_driver = {
+       .driver = {
+               .name           = "pxa2xx-flash",
+               .owner          = THIS_MODULE,
+       },
        .probe          = pxa2xx_flash_probe,
-       .remove         = __exit_p(pxa2xx_flash_remove),
+       .remove         = __devexit_p(pxa2xx_flash_remove),
        .suspend        = pxa2xx_flash_suspend,
        .resume         = pxa2xx_flash_resume,
        .shutdown       = pxa2xx_flash_shutdown,
@@ -184,12 +185,12 @@ static struct device_driver pxa2xx_flash_driver = {
 
 static int __init init_pxa2xx_flash(void)
 {
-       return driver_register(&pxa2xx_flash_driver);
+       return platform_driver_register(&pxa2xx_flash_driver);
 }
 
 static void __exit cleanup_pxa2xx_flash(void)
 {
-       driver_unregister(&pxa2xx_flash_driver);
+       platform_driver_unregister(&pxa2xx_flash_driver);
 }
 
 module_init(init_pxa2xx_flash);
diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c
new file mode 100644 (file)
index 0000000..1f73297
--- /dev/null
@@ -0,0 +1,832 @@
+/* vmu-flash.c
+ * Driver for SEGA Dreamcast Visual Memory Unit
+ *
+ * Copyright (c) Adrian McMenamin 2002 - 2009
+ * Copyright (c) Paul Mundt 2001
+ *
+ * Licensed under version 2 of the
+ * GNU General Public Licence
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/maple.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+struct vmu_cache {
+       unsigned char *buffer;          /* Cache */
+       unsigned int block;             /* Which block was cached */
+       unsigned long jiffies_atc;      /* When was it cached? */
+       int valid;
+};
+
+struct mdev_part {
+       struct maple_device *mdev;
+       int partition;
+};
+
+struct vmupart {
+       u16 user_blocks;
+       u16 root_block;
+       u16 numblocks;
+       char *name;
+       struct vmu_cache *pcache;
+};
+
+struct memcard {
+       u16 tempA;
+       u16 tempB;
+       u32 partitions;
+       u32 blocklen;
+       u32 writecnt;
+       u32 readcnt;
+       u32 removeable;
+       int partition;
+       int read;
+       unsigned char *blockread;
+       struct vmupart *parts;
+       struct mtd_info *mtd;
+};
+
+struct vmu_block {
+       unsigned int num; /* block number */
+       unsigned int ofs; /* block offset */
+};
+
+static struct vmu_block *ofs_to_block(unsigned long src_ofs,
+       struct mtd_info *mtd, int partition)
+{
+       struct vmu_block *vblock;
+       struct maple_device *mdev;
+       struct memcard *card;
+       struct mdev_part *mpart;
+       int num;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       card = maple_get_drvdata(mdev);
+
+       if (src_ofs >= card->parts[partition].numblocks * card->blocklen)
+               goto failed;
+
+       num = src_ofs / card->blocklen;
+       if (num > card->parts[partition].numblocks)
+               goto failed;
+
+       vblock = kmalloc(sizeof(struct vmu_block), GFP_KERNEL);
+       if (!vblock)
+               goto failed;
+
+       vblock->num = num;
+       vblock->ofs = src_ofs % card->blocklen;
+       return vblock;
+
+failed:
+       return NULL;
+}
+
+/* Maple bus callback function for reads */
+static void vmu_blockread(struct mapleq *mq)
+{
+       struct maple_device *mdev;
+       struct memcard *card;
+
+       mdev = mq->dev;
+       card = maple_get_drvdata(mdev);
+       /* copy the read in data */
+
+       if (unlikely(!card->blockread))
+               return;
+
+       memcpy(card->blockread, mq->recvbuf->buf + 12,
+               card->blocklen/card->readcnt);
+
+}
+
+/* Interface with maple bus to read blocks
+ * caching the results so that other parts
+ * of the driver can access block reads */
+static int maple_vmu_read_block(unsigned int num, unsigned char *buf,
+       struct mtd_info *mtd)
+{
+       struct memcard *card;
+       struct mdev_part *mpart;
+       struct maple_device *mdev;
+       int partition, error = 0, x, wait;
+       unsigned char *blockread = NULL;
+       struct vmu_cache *pcache;
+       __be32 sendbuf;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       partition = mpart->partition;
+       card = maple_get_drvdata(mdev);
+       pcache = card->parts[partition].pcache;
+       pcache->valid = 0;
+
+       /* prepare the cache for this block */
+       if (!pcache->buffer) {
+               pcache->buffer = kmalloc(card->blocklen, GFP_KERNEL);
+               if (!pcache->buffer) {
+                       dev_err(&mdev->dev, "VMU at (%d, %d) - read fails due"
+                               " to lack of memory\n", mdev->port,
+                               mdev->unit);
+                       error = -ENOMEM;
+                       goto outB;
+               }
+       }
+
+       /*
+       * Reads may be phased - again the hardware spec
+       * supports this - though may not be any devices in
+       * the wild that implement it, but we will here
+       */
+       for (x = 0; x < card->readcnt; x++) {
+               sendbuf = cpu_to_be32(partition << 24 | x << 16 | num);
+
+               if (atomic_read(&mdev->busy) == 1) {
+                       wait_event_interruptible_timeout(mdev->maple_wait,
+                               atomic_read(&mdev->busy) == 0, HZ);
+                       if (atomic_read(&mdev->busy) == 1) {
+                               dev_notice(&mdev->dev, "VMU at (%d, %d)"
+                                       " is busy\n", mdev->port, mdev->unit);
+                               error = -EAGAIN;
+                               goto outB;
+                       }
+               }
+
+               atomic_set(&mdev->busy, 1);
+               blockread = kmalloc(card->blocklen/card->readcnt, GFP_KERNEL);
+               if (!blockread) {
+                       error = -ENOMEM;
+                       atomic_set(&mdev->busy, 0);
+                       goto outB;
+               }
+               card->blockread = blockread;
+
+               maple_getcond_callback(mdev, vmu_blockread, 0,
+                       MAPLE_FUNC_MEMCARD);
+               error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+                               MAPLE_COMMAND_BREAD, 2, &sendbuf);
+               /* Very long timeouts seem to be needed when box is stressed */
+               wait = wait_event_interruptible_timeout(mdev->maple_wait,
+                       (atomic_read(&mdev->busy) == 0 ||
+                       atomic_read(&mdev->busy) == 2), HZ * 3);
+               /*
+               * MTD layer does not handle hotplugging well
+               * so have to return errors when VMU is unplugged
+               * in the middle of a read (busy == 2)
+               */
+               if (error || atomic_read(&mdev->busy) == 2) {
+                       if (atomic_read(&mdev->busy) == 2)
+                               error = -ENXIO;
+                       atomic_set(&mdev->busy, 0);
+                       card->blockread = NULL;
+                       goto outA;
+               }
+               if (wait == 0 || wait == -ERESTARTSYS) {
+                       card->blockread = NULL;
+                       atomic_set(&mdev->busy, 0);
+                       error = -EIO;
+                       list_del_init(&(mdev->mq->list));
+                       kfree(mdev->mq->sendbuf);
+                       mdev->mq->sendbuf = NULL;
+                       if (wait == -ERESTARTSYS) {
+                               dev_warn(&mdev->dev, "VMU read on (%d, %d)"
+                                       " interrupted on block 0x%X\n",
+                                       mdev->port, mdev->unit, num);
+                       } else
+                               dev_notice(&mdev->dev, "VMU read on (%d, %d)"
+                                       " timed out on block 0x%X\n",
+                                       mdev->port, mdev->unit, num);
+                       goto outA;
+               }
+
+               memcpy(buf + (card->blocklen/card->readcnt) * x, blockread,
+                       card->blocklen/card->readcnt);
+
+               memcpy(pcache->buffer + (card->blocklen/card->readcnt) * x,
+                       card->blockread, card->blocklen/card->readcnt);
+               card->blockread = NULL;
+               pcache->block = num;
+               pcache->jiffies_atc = jiffies;
+               pcache->valid = 1;
+               kfree(blockread);
+       }
+
+       return error;
+
+outA:
+       kfree(blockread);
+outB:
+       return error;
+}
+
+/* communicate with maple bus for phased writing */
+static int maple_vmu_write_block(unsigned int num, const unsigned char *buf,
+       struct mtd_info *mtd)
+{
+       struct memcard *card;
+       struct mdev_part *mpart;
+       struct maple_device *mdev;
+       int partition, error, locking, x, phaselen, wait;
+       __be32 *sendbuf;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       partition = mpart->partition;
+       card = maple_get_drvdata(mdev);
+
+       phaselen = card->blocklen/card->writecnt;
+
+       sendbuf = kmalloc(phaselen + 4, GFP_KERNEL);
+       if (!sendbuf) {
+               error = -ENOMEM;
+               goto fail_nosendbuf;
+       }
+       for (x = 0; x < card->writecnt; x++) {
+               sendbuf[0] = cpu_to_be32(partition << 24 | x << 16 | num);
+               memcpy(&sendbuf[1], buf + phaselen * x, phaselen);
+               /* wait until the device is not busy doing something else
+               * or 1 second - which ever is longer */
+               if (atomic_read(&mdev->busy) == 1) {
+                       wait_event_interruptible_timeout(mdev->maple_wait,
+                               atomic_read(&mdev->busy) == 0, HZ);
+                       if (atomic_read(&mdev->busy) == 1) {
+                               error = -EBUSY;
+                               dev_notice(&mdev->dev, "VMU write at (%d, %d)"
+                                       "failed - device is busy\n",
+                                       mdev->port, mdev->unit);
+                               goto fail_nolock;
+                       }
+               }
+               atomic_set(&mdev->busy, 1);
+
+               locking = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+                       MAPLE_COMMAND_BWRITE, phaselen / 4 + 2, sendbuf);
+               wait = wait_event_interruptible_timeout(mdev->maple_wait,
+                       atomic_read(&mdev->busy) == 0, HZ/10);
+               if (locking) {
+                       error = -EIO;
+                       atomic_set(&mdev->busy, 0);
+                       goto fail_nolock;
+               }
+               if (atomic_read(&mdev->busy) == 2) {
+                       atomic_set(&mdev->busy, 0);
+               } else if (wait == 0 || wait == -ERESTARTSYS) {
+                       error = -EIO;
+                       dev_warn(&mdev->dev, "Write at (%d, %d) of block"
+                               " 0x%X at phase %d failed: could not"
+                               " communicate with VMU", mdev->port,
+                               mdev->unit, num, x);
+                       atomic_set(&mdev->busy, 0);
+                       kfree(mdev->mq->sendbuf);
+                       mdev->mq->sendbuf = NULL;
+                       list_del_init(&(mdev->mq->list));
+                       goto fail_nolock;
+               }
+       }
+       kfree(sendbuf);
+
+       return card->blocklen;
+
+fail_nolock:
+       kfree(sendbuf);
+fail_nosendbuf:
+       dev_err(&mdev->dev, "VMU (%d, %d): write failed\n", mdev->port,
+               mdev->unit);
+       return error;
+}
+
+/* mtd function to simulate reading byte by byte */
+static unsigned char vmu_flash_read_char(unsigned long ofs, int *retval,
+       struct mtd_info *mtd)
+{
+       struct vmu_block *vblock;
+       struct memcard *card;
+       struct mdev_part *mpart;
+       struct maple_device *mdev;
+       unsigned char *buf, ret;
+       int partition, error;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       partition = mpart->partition;
+       card = maple_get_drvdata(mdev);
+       *retval =  0;
+
+       buf = kmalloc(card->blocklen, GFP_KERNEL);
+       if (!buf) {
+               *retval = 1;
+               ret = -ENOMEM;
+               goto finish;
+       }
+
+       vblock = ofs_to_block(ofs, mtd, partition);
+       if (!vblock) {
+               *retval = 3;
+               ret = -ENOMEM;
+               goto out_buf;
+       }
+
+       error = maple_vmu_read_block(vblock->num, buf, mtd);
+       if (error) {
+               ret = error;
+               *retval = 2;
+               goto out_vblock;
+       }
+
+       ret = buf[vblock->ofs];
+
+out_vblock:
+       kfree(vblock);
+out_buf:
+       kfree(buf);
+finish:
+       return ret;
+}
+
+/* mtd higher order function to read flash */
+static int vmu_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen,  u_char *buf)
+{
+       struct maple_device *mdev;
+       struct memcard *card;
+       struct mdev_part *mpart;
+       struct vmu_cache *pcache;
+       struct vmu_block *vblock;
+       int index = 0, retval, partition, leftover, numblocks;
+       unsigned char cx;
+
+       if (len < 1)
+               return -EIO;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       partition = mpart->partition;
+       card = maple_get_drvdata(mdev);
+
+       numblocks = card->parts[partition].numblocks;
+       if (from + len > numblocks * card->blocklen)
+               len = numblocks * card->blocklen - from;
+       if (len == 0)
+               return -EIO;
+       /* Have we cached this bit already? */
+       pcache = card->parts[partition].pcache;
+       do {
+               vblock =  ofs_to_block(from + index, mtd, partition);
+               if (!vblock)
+                       return -ENOMEM;
+               /* Have we cached this and is the cache valid and timely? */
+               if (pcache->valid &&
+                       time_before(jiffies, pcache->jiffies_atc + HZ) &&
+                       (pcache->block == vblock->num)) {
+                       /* we have cached it, so do necessary copying */
+                       leftover = card->blocklen - vblock->ofs;
+                       if (vblock->ofs + len - index < card->blocklen) {
+                               /* only a bit of this block to copy */
+                               memcpy(buf + index,
+                                       pcache->buffer + vblock->ofs,
+                                       len - index);
+                               index = len;
+                       } else {
+                               /* otherwise copy remainder of whole block */
+                               memcpy(buf + index, pcache->buffer +
+                                       vblock->ofs, leftover);
+                               index += leftover;
+                       }
+               } else {
+                       /*
+                       * Not cached so read one byte -
+                       * but cache the rest of the block
+                       */
+                       cx = vmu_flash_read_char(from + index, &retval, mtd);
+                       if (retval) {
+                               *retlen = index;
+                               kfree(vblock);
+                               return cx;
+                       }
+                       memset(buf + index, cx, 1);
+                       index++;
+               }
+               kfree(vblock);
+       } while (len > index);
+       *retlen = index;
+
+       return 0;
+}
+
+static int vmu_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       struct maple_device *mdev;
+       struct memcard *card;
+       struct mdev_part *mpart;
+       int index = 0, partition, error = 0, numblocks;
+       struct vmu_cache *pcache;
+       struct vmu_block *vblock;
+       unsigned char *buffer;
+
+       mpart = mtd->priv;
+       mdev = mpart->mdev;
+       partition = mpart->partition;
+       card = maple_get_drvdata(mdev);
+
+       /* simple sanity checks */
+       if (len < 1) {
+               error = -EIO;
+               goto failed;
+       }
+       numblocks = card->parts[partition].numblocks;
+       if (to + len > numblocks * card->blocklen)
+               len = numblocks * card->blocklen - to;
+       if (len == 0) {
+               error = -EIO;
+               goto failed;
+       }
+
+       vblock = ofs_to_block(to, mtd, partition);
+       if (!vblock) {
+               error = -ENOMEM;
+               goto failed;
+       }
+
+       buffer = kmalloc(card->blocklen, GFP_KERNEL);
+       if (!buffer) {
+               error = -ENOMEM;
+               goto fail_buffer;
+       }
+
+       do {
+               /* Read in the block we are to write to */
+               error = maple_vmu_read_block(vblock->num, buffer, mtd);
+               if (error)
+                       goto fail_io;
+
+               do {
+                       buffer[vblock->ofs] = buf[index];
+                       vblock->ofs++;
+                       index++;
+                       if (index >= len)
+                               break;
+               } while (vblock->ofs < card->blocklen);
+
+               /* write out new buffer */
+               error = maple_vmu_write_block(vblock->num, buffer, mtd);
+               /* invalidate the cache */
+               pcache = card->parts[partition].pcache;
+               pcache->valid = 0;
+
+               if (error != card->blocklen)
+                       goto fail_io;
+
+               vblock->num++;
+               vblock->ofs = 0;
+       } while (len > index);
+
+       kfree(buffer);
+       *retlen = index;
+       kfree(vblock);
+       return 0;
+
+fail_io:
+       kfree(buffer);
+fail_buffer:
+       kfree(vblock);
+failed:
+       dev_err(&mdev->dev, "VMU write failing with error %d\n", error);
+       return error;
+}
+
+static void vmu_flash_sync(struct mtd_info *mtd)
+{
+       /* Do nothing here */
+}
+
+/* Maple bus callback function to recursively query hardware details */
+static void vmu_queryblocks(struct mapleq *mq)
+{
+       struct maple_device *mdev;
+       unsigned short *res;
+       struct memcard *card;
+       __be32 partnum;
+       struct vmu_cache *pcache;
+       struct mdev_part *mpart;
+       struct mtd_info *mtd_cur;
+       struct vmupart *part_cur;
+       int error;
+
+       mdev = mq->dev;
+       card = maple_get_drvdata(mdev);
+       res = (unsigned short *) (mq->recvbuf->buf);
+       card->tempA = res[12];
+       card->tempB = res[6];
+
+       dev_info(&mdev->dev, "VMU device at partition %d has %d user "
+               "blocks with a root block at %d\n", card->partition,
+               card->tempA, card->tempB);
+
+       part_cur = &card->parts[card->partition];
+       part_cur->user_blocks = card->tempA;
+       part_cur->root_block = card->tempB;
+       part_cur->numblocks = card->tempB + 1;
+       part_cur->name = kmalloc(12, GFP_KERNEL);
+       if (!part_cur->name)
+               goto fail_name;
+
+       sprintf(part_cur->name, "vmu%d.%d.%d",
+               mdev->port, mdev->unit, card->partition);
+       mtd_cur = &card->mtd[card->partition];
+       mtd_cur->name = part_cur->name;
+       mtd_cur->type = 8;
+       mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
+       mtd_cur->size = part_cur->numblocks * card->blocklen;
+       mtd_cur->erasesize = card->blocklen;
+       mtd_cur->write = vmu_flash_write;
+       mtd_cur->read = vmu_flash_read;
+       mtd_cur->sync = vmu_flash_sync;
+       mtd_cur->writesize = card->blocklen;
+
+       mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
+       if (!mpart)
+               goto fail_mpart;
+
+       mpart->mdev = mdev;
+       mpart->partition = card->partition;
+       mtd_cur->priv = mpart;
+       mtd_cur->owner = THIS_MODULE;
+
+       pcache = kzalloc(sizeof(struct vmu_cache), GFP_KERNEL);
+       if (!pcache)
+               goto fail_cache_create;
+       part_cur->pcache = pcache;
+
+       error = add_mtd_device(mtd_cur);
+       if (error)
+               goto fail_mtd_register;
+
+       maple_getcond_callback(mdev, NULL, 0,
+               MAPLE_FUNC_MEMCARD);
+
+       /*
+       * Set up a recursive call to the (probably theoretical)
+       * second or more partition
+       */
+       if (++card->partition < card->partitions) {
+               partnum = cpu_to_be32(card->partition << 24);
+               maple_getcond_callback(mdev, vmu_queryblocks, 0,
+                       MAPLE_FUNC_MEMCARD);
+               maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+                       MAPLE_COMMAND_GETMINFO, 2, &partnum);
+       }
+       return;
+
+fail_mtd_register:
+       dev_err(&mdev->dev, "Could not register maple device at (%d, %d)"
+               "error is 0x%X\n", mdev->port, mdev->unit, error);
+       for (error = 0; error <= card->partition; error++) {
+               kfree(((card->parts)[error]).pcache);
+               ((card->parts)[error]).pcache = NULL;
+       }
+fail_cache_create:
+fail_mpart:
+       for (error = 0; error <= card->partition; error++) {
+               kfree(((card->mtd)[error]).priv);
+               ((card->mtd)[error]).priv = NULL;
+       }
+       maple_getcond_callback(mdev, NULL, 0,
+               MAPLE_FUNC_MEMCARD);
+       kfree(part_cur->name);
+fail_name:
+       return;
+}
+
+/* Handles very basic info about the flash, queries for details */
+static int __devinit vmu_connect(struct maple_device *mdev)
+{
+       unsigned long test_flash_data, basic_flash_data;
+       int c, error;
+       struct memcard *card;
+       u32 partnum = 0;
+
+       test_flash_data = be32_to_cpu(mdev->devinfo.function);
+       /* Need to count how many bits are set - to find out which
+        * function_data element has details of the memory card:
+        * using Brian Kernighan's/Peter Wegner's method */
+       for (c = 0; test_flash_data; c++)
+               test_flash_data &= test_flash_data - 1;
+
+       basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]);
+
+       card = kmalloc(sizeof(struct memcard), GFP_KERNEL);
+       if (!card) {
+               error = ENOMEM;
+               goto fail_nomem;
+       }
+
+       card->partitions = (basic_flash_data >> 24 & 0xFF) + 1;
+       card->blocklen = ((basic_flash_data >> 16 & 0xFF) + 1) << 5;
+       card->writecnt = basic_flash_data >> 12 & 0xF;
+       card->readcnt = basic_flash_data >> 8 & 0xF;
+       card->removeable = basic_flash_data >> 7 & 1;
+
+       card->partition = 0;
+
+       /*
+       * Not sure there are actually any multi-partition devices in the
+       * real world, but the hardware supports them, so, so will we
+       */
+       card->parts = kmalloc(sizeof(struct vmupart) * card->partitions,
+               GFP_KERNEL);
+       if (!card->parts) {
+               error = -ENOMEM;
+               goto fail_partitions;
+       }
+
+       card->mtd = kmalloc(sizeof(struct mtd_info) * card->partitions,
+               GFP_KERNEL);
+       if (!card->mtd) {
+               error = -ENOMEM;
+               goto fail_mtd_info;
+       }
+
+       maple_set_drvdata(mdev, card);
+
+       /*
+       * We want to trap meminfo not get cond
+       * so set interval to zero, but rely on maple bus
+       * driver to pass back the results of the meminfo
+       */
+       maple_getcond_callback(mdev, vmu_queryblocks, 0,
+               MAPLE_FUNC_MEMCARD);
+
+       /* Make sure we are clear to go */
+       if (atomic_read(&mdev->busy) == 1) {
+               wait_event_interruptible_timeout(mdev->maple_wait,
+                       atomic_read(&mdev->busy) == 0, HZ);
+               if (atomic_read(&mdev->busy) == 1) {
+                       dev_notice(&mdev->dev, "VMU at (%d, %d) is busy\n",
+                               mdev->port, mdev->unit);
+                       error = -EAGAIN;
+                       goto fail_device_busy;
+               }
+       }
+
+       atomic_set(&mdev->busy, 1);
+
+       /*
+       * Set up the minfo call: vmu_queryblocks will handle
+       * the information passed back
+       */
+       error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+               MAPLE_COMMAND_GETMINFO, 2, &partnum);
+       if (error) {
+               dev_err(&mdev->dev, "Could not lock VMU at (%d, %d)"
+                       " error is 0x%X\n", mdev->port, mdev->unit, error);
+               goto fail_mtd_info;
+       }
+       return 0;
+
+fail_device_busy:
+       kfree(card->mtd);
+fail_mtd_info:
+       kfree(card->parts);
+fail_partitions:
+       kfree(card);
+fail_nomem:
+       return error;
+}
+
+static void __devexit vmu_disconnect(struct maple_device *mdev)
+{
+       struct memcard *card;
+       struct mdev_part *mpart;
+       int x;
+
+       mdev->callback = NULL;
+       card = maple_get_drvdata(mdev);
+       for (x = 0; x < card->partitions; x++) {
+               mpart = ((card->mtd)[x]).priv;
+               mpart->mdev = NULL;
+               del_mtd_device(&((card->mtd)[x]));
+               kfree(((card->parts)[x]).name);
+       }
+       kfree(card->parts);
+       kfree(card->mtd);
+       kfree(card);
+}
+
+/* Callback to handle eccentricities of both mtd subsystem
+ * and general flakyness of Dreamcast VMUs
+ */
+static int vmu_can_unload(struct maple_device *mdev)
+{
+       struct memcard *card;
+       int x;
+       struct mtd_info *mtd;
+
+       card = maple_get_drvdata(mdev);
+       for (x = 0; x < card->partitions; x++) {
+               mtd = &((card->mtd)[x]);
+               if (mtd->usecount > 0)
+                       return 0;
+       }
+       return 1;
+}
+
+#define ERRSTR "VMU at (%d, %d) file error -"
+
+static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
+{
+       enum maple_file_errors error = ((int *)recvbuf)[1];
+
+       switch (error) {
+
+       case MAPLE_FILEERR_INVALID_PARTITION:
+               dev_notice(&mdev->dev, ERRSTR " invalid partition number\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       case MAPLE_FILEERR_PHASE_ERROR:
+               dev_notice(&mdev->dev, ERRSTR " phase error\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       case MAPLE_FILEERR_INVALID_BLOCK:
+               dev_notice(&mdev->dev, ERRSTR " invalid block number\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       case MAPLE_FILEERR_WRITE_ERROR:
+               dev_notice(&mdev->dev, ERRSTR " write error\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       case MAPLE_FILEERR_INVALID_WRITE_LENGTH:
+               dev_notice(&mdev->dev, ERRSTR " invalid write length\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       case MAPLE_FILEERR_BAD_CRC:
+               dev_notice(&mdev->dev, ERRSTR " bad CRC\n",
+                       mdev->port, mdev->unit);
+               break;
+
+       default:
+               dev_notice(&mdev->dev, ERRSTR " 0x%X\n",
+                       mdev->port, mdev->unit, error);
+       }
+}
+
+
+static int __devinit probe_maple_vmu(struct device *dev)
+{
+       int error;
+       struct maple_device *mdev = to_maple_dev(dev);
+       struct maple_driver *mdrv = to_maple_driver(dev->driver);
+
+       mdev->can_unload = vmu_can_unload;
+       mdev->fileerr_handler = vmu_file_error;
+       mdev->driver = mdrv;
+
+       error = vmu_connect(mdev);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int __devexit remove_maple_vmu(struct device *dev)
+{
+       struct maple_device *mdev = to_maple_dev(dev);
+
+       vmu_disconnect(mdev);
+       return 0;
+}
+
+static struct maple_driver vmu_flash_driver = {
+       .function =     MAPLE_FUNC_MEMCARD,
+       .drv = {
+               .name =         "Dreamcast_visual_memory",
+               .probe =        probe_maple_vmu,
+               .remove =       __devexit_p(remove_maple_vmu),
+       },
+};
+
+static int __init vmu_flash_map_init(void)
+{
+       return maple_driver_register(&vmu_flash_driver);
+}
+
+static void __exit vmu_flash_map_exit(void)
+{
+       maple_driver_unregister(&vmu_flash_driver);
+}
+
+module_init(vmu_flash_map_init);
+module_exit(vmu_flash_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Adrian McMenamin");
+MODULE_DESCRIPTION("Flash mapping for Sega Dreamcast visual memory");
index ced14b5294d51dac99826cee87899e464abf5fe5..72446fb48d4b90321be0c3611d57d8a9e02877f3 100644 (file)
@@ -128,11 +128,11 @@ static int excite_nand_devready(struct mtd_info *mtd)
  * The binding to the mtd and all allocated
  * resources are released.
  */
-static int __exit excite_nand_remove(struct device *dev)
+static int __exit excite_nand_remove(struct platform_device *dev)
 {
-       struct excite_nand_drvdata * const this = dev_get_drvdata(dev);
+       struct excite_nand_drvdata * const this = platform_get_drvdata(dev);
 
-       dev_set_drvdata(dev, NULL);
+       platform_set_drvdata(dev, NULL);
 
        if (unlikely(!this)) {
                printk(KERN_ERR "%s: called %s without private data!!",
@@ -159,9 +159,8 @@ static int __exit excite_nand_remove(struct device *dev)
  * it can allocate all necessary resources then calls the
  * nand layer to look for devices.
 */
-static int __init excite_nand_probe(struct device *dev)
+static int __init excite_nand_probe(struct platform_device *pdev)
 {
-       struct platform_device * const pdev = to_platform_device(dev);
        struct excite_nand_drvdata *drvdata;    /* private driver data */
        struct nand_chip *board_chip;   /* private flash chip data */
        struct mtd_info *board_mtd;     /* mtd info for this board */
@@ -175,7 +174,7 @@ static int __init excite_nand_probe(struct device *dev)
        }
 
        /* bind private data into driver */
-       dev_set_drvdata(dev, drvdata);
+       platform_set_drvdata(pdev, drvdata);
 
        /* allocate and map the resource */
        drvdata->regs =
@@ -219,23 +218,25 @@ static int __init excite_nand_probe(struct device *dev)
        return 0;
 }
 
-static struct device_driver excite_nand_driver = {
-       .name = "excite_nand",
-       .bus = &platform_bus_type,
+static struct platform_driver excite_nand_driver = {
+       .driver = {
+               .name = "excite_nand",
+               .owner          = THIS_MODULE,
+       },
        .probe = excite_nand_probe,
-       .remove = __exit_p(excite_nand_remove)
+       .remove = __devexit_p(excite_nand_remove)
 };
 
 static int __init excite_nand_init(void)
 {
        pr_info("Basler eXcite nand flash driver Version "
                EXCITE_NANDFLASH_VERSION "\n");
-       return driver_register(&excite_nand_driver);
+       return platform_driver_register(&excite_nand_driver);
 }
 
 static void __exit excite_nand_exit(void)
 {
-       driver_unregister(&excite_nand_driver);
+       platform_driver_unregister(&excite_nand_driver);
 }
 
 module_init(excite_nand_init);
index 582cf80f555a5ba99ac1a79abf1952b65114966d..89bf85af642cb630b641a73ff966dd73aa60811a 100644 (file)
@@ -187,7 +187,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
                return -ENODEV;
 
        ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",
-                                  ndfc->ofdev->dev.bus_id, flash_np->name);
+                       dev_name(&ndfc->ofdev->dev), flash_np->name);
        if (!ndfc->mtd.name) {
                ret = -ENOMEM;
                goto err;
index 5b69e7773c6c2a826ac8b3983913e5df749db549..3a496c33fb52405801d8add2191bd3df89ac435f 100644 (file)
@@ -36,10 +36,9 @@ struct onenand_info {
        struct onenand_chip     onenand;
 };
 
-static int __devinit generic_onenand_probe(struct device *dev)
+static int __devinit generic_onenand_probe(struct platform_device *pdev)
 {
        struct onenand_info *info;
-       struct platform_device *pdev = to_platform_device(dev);
        struct flash_platform_data *pdata = pdev->dev.platform_data;
        struct resource *res = pdev->resource;
        unsigned long size = res->end - res->start + 1;
@@ -49,7 +48,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
        if (!info)
                return -ENOMEM;
 
-       if (!request_mem_region(res->start, size, dev->driver->name)) {
+       if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
                err = -EBUSY;
                goto out_free_info;
        }
@@ -82,7 +81,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
 #endif
                err = add_mtd_device(&info->mtd);
 
-       dev_set_drvdata(&pdev->dev, info);
+       platform_set_drvdata(pdev, info);
 
        return 0;
 
@@ -96,14 +95,13 @@ out_free_info:
        return err;
 }
 
-static int __devexit generic_onenand_remove(struct device *dev)
+static int __devexit generic_onenand_remove(struct platform_device *pdev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct onenand_info *info = dev_get_drvdata(&pdev->dev);
+       struct onenand_info *info = platform_get_drvdata(pdev);
        struct resource *res = pdev->resource;
        unsigned long size = res->end - res->start + 1;
 
-       dev_set_drvdata(&pdev->dev, NULL);
+       platform_set_drvdata(pdev, NULL);
 
        if (info) {
                if (info->parts)
@@ -120,9 +118,11 @@ static int __devexit generic_onenand_remove(struct device *dev)
        return 0;
 }
 
-static struct device_driver generic_onenand_driver = {
-       .name           = DRIVER_NAME,
-       .bus            = &platform_bus_type,
+static struct platform_driver generic_onenand_driver = {
+       .driver = {
+               .name           = DRIVER_NAME,
+               .owner          = THIS_MODULE,
+       },
        .probe          = generic_onenand_probe,
        .remove         = __devexit_p(generic_onenand_remove),
 };
@@ -131,12 +131,12 @@ MODULE_ALIAS(DRIVER_NAME);
 
 static int __init generic_onenand_init(void)
 {
-       return driver_register(&generic_onenand_driver);
+       return platform_driver_register(&generic_onenand_driver);
 }
 
 static void __exit generic_onenand_exit(void)
 {
-       driver_unregister(&generic_onenand_driver);
+       platform_driver_unregister(&generic_onenand_driver);
 }
 
 module_init(generic_onenand_init);
index f3a127434897472110abaa8bd5e26b383e9a9767..35cd264abae70e6436e9e0e2a1288a7aa5484c89 100644 (file)
@@ -1059,7 +1059,7 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 {
        strlcpy(info->driver, MODULENAME, sizeof(info->driver));
        strlcpy(info->version, MODULEVERSION, sizeof(info->version));
-       strlcpy(info->bus_info, ndev->dev.parent->bus_id,
+       strlcpy(info->bus_info, dev_name(ndev->dev.parent),
                sizeof(info->bus_info));
 }
 
index 9c875bb3f76c642f93203f9096942af72a0e3e53..79aec32c6add769946058f04d932d4b6e7296ca8 100644 (file)
@@ -355,8 +355,8 @@ static int mii_probe (struct net_device *dev)
        /* now we are supposed to have a proper phydev, to attach to... */
        BUG_ON(phydev->attached_dev);
 
-       phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0,
-                       PHY_INTERFACE_MODE_MII);
+       phydev = phy_connect(dev, dev_name(&phydev->dev), &au1000_adjust_link,
+                       0, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
@@ -381,8 +381,8 @@ static int mii_probe (struct net_device *dev)
        aup->phy_dev = phydev;
 
        printk(KERN_INFO "%s: attached PHY driver [%s] "
-              "(mii_bus:phy_addr=%s, irq=%d)\n",
-              dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+              "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name,
+              phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
 
        return 0;
 }
index 78e31aa861e020e461336e2323cea4647d7cb9c8..9afe8092dfc4c9f3b8fe04d1a915d2040206d794 100644 (file)
@@ -415,11 +415,11 @@ static int mii_probe(struct net_device *dev)
        }
 
 #if defined(CONFIG_BFIN_MAC_RMII)
-       phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
-                       PHY_INTERFACE_MODE_RMII);
+       phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
+                       0, PHY_INTERFACE_MODE_RMII);
 #else
-       phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
-                       PHY_INTERFACE_MODE_MII);
+       phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
+                       0, PHY_INTERFACE_MODE_MII);
 #endif
 
        if (IS_ERR(phydev)) {
@@ -447,7 +447,7 @@ static int mii_probe(struct net_device *dev)
        printk(KERN_INFO "%s: attached PHY driver [%s] "
               "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)"
               "@sclk=%dMHz)\n",
-              DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq,
+              DRV_NAME, phydev->drv->name, dev_name(&phydev->dev), phydev->irq,
               MDC_CLK, mdc_div, sclk/1000000);
 
        return 0;
@@ -488,7 +488,7 @@ static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
        strcpy(info->driver, DRV_NAME);
        strcpy(info->version, DRV_VERSION);
        strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, dev->dev.bus_id);
+       strcpy(info->bus_info, dev_name(&dev->dev));
 }
 
 static struct ethtool_ops bfin_mac_ethtool_ops = {
index 8a546a33d58124fb39cf67ff673e305f7a7fd418..1ab58375d0617039cfdf658d7ee8c56f0f6bbf09 100644 (file)
@@ -1240,7 +1240,7 @@ static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *inf
 {
        struct bmac_data *bp = netdev_priv(dev);
        strcpy(info->driver, "bmac");
-       strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id);
+       strcpy(info->bus_info, dev_name(&bp->mdev->ofdev.dev));
 }
 
 static const struct ethtool_ops bmac_ethtool_ops = {
index f66548751c384c1bf111f69b995dd701aa60b713..79741c5f9fe72d9a81a53c6b7e9d02a14c9ca68f 100644 (file)
@@ -1161,7 +1161,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, 0xff);
        memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
 
-       priv->phy = phy_connect(dev, cpmac_mii->phy_map[phy_id]->dev.bus_id,
+       priv->phy = phy_connect(dev, dev_name(&cpmac_mii->phy_map[phy_id]->dev),
                                &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
        if (IS_ERR(priv->phy)) {
                if (netif_msg_drv(priv))
index 7ce3053530f9c62279f38dd17340e89167b6044b..861c867fca879a181095b23fef81c17056018d6c 100644 (file)
@@ -1027,7 +1027,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
                printk(version);
 
        if (bdev)
-               snprintf(name, sizeof(name), "%s", bdev->bus_id);
+               snprintf(name, sizeof(name), "%s", dev_name(bdev));
        else {
                i = 0;
                dev = root_lance_dev;
@@ -1105,10 +1105,10 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
 
                start = to_tc_dev(bdev)->resource.start;
                len = to_tc_dev(bdev)->resource.end - start + 1;
-               if (!request_mem_region(start, len, bdev->bus_id)) {
+               if (!request_mem_region(start, len, dev_name(bdev))) {
                        printk(KERN_ERR
                               "%s: Unable to reserve MMIO resource\n",
-                              bdev->bus_id);
+                              dev_name(bdev));
                        ret = -EBUSY;
                        goto err_out_dev;
                }
index e4cef491dc73fc8d6486b98976d9b937b12399ad..55625dbbae5a8f8bf96415e8466f246c471f3585 100644 (file)
@@ -606,8 +606,8 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
        if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
                return -ENXIO;
 
-       printk ("%s: %s at 0x%04lx",
-               device->bus_id, depca_signature[lp->adapter], ioaddr);
+       printk("%s: %s at 0x%04lx",
+              dev_name(device), depca_signature[lp->adapter], ioaddr);
 
        switch (lp->depca_bus) {
 #ifdef CONFIG_MCA
@@ -669,7 +669,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
 
        spin_lock_init(&lp->lock);
        sprintf(lp->adapter_name, "%s (%s)",
-               depca_signature[lp->adapter], device->bus_id);
+               depca_signature[lp->adapter], dev_name(device));
        status = -EBUSY;
 
        /* Initialisation Block */
index dfe92264e8252978d5719dc81f5b08dfff6d5f25..8e7c16535ad7089e150548afc973a95ad5863ded 100644 (file)
@@ -3040,7 +3040,7 @@ static struct device *ehea_register_port(struct ehea_port *port,
        port->ofdev.dev.parent = &port->adapter->ofdev->dev;
        port->ofdev.dev.bus = &ibmebus_bus_type;
 
-       sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++);
+       dev_set_name(&port->ofdev.dev, "port%d", port_name_cnt++);
        port->ofdev.dev.release = logical_port_release;
 
        ret = of_device_register(&port->ofdev);
index 334ff9e12cdd25c5aa131ce98e10fd485a435189..14248cfc3dfd165d74d2656d8a56431460478538 100644 (file)
@@ -131,7 +131,8 @@ static int __init sonic_probe1(struct net_device *dev)
        if (sonic_debug  &&  version_printed++ == 0)
                printk(version);
 
-       printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
+       printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ",
+              dev_name(lp->device), dev->base_addr);
 
        /*
         * Put the sonic into software reset, then
@@ -156,7 +157,8 @@ static int __init sonic_probe1(struct net_device *dev)
        if ((lp->descriptors = dma_alloc_coherent(lp->device,
                                SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
                                &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
+                      dev_name(lp->device));
                goto out;
        }
 
index f6c4936e2fa8e368ca1f2fdbdb09ad75d990562e..f4086542c3589b40f095e4e7bf4f78ead04e366d 100644 (file)
@@ -211,10 +211,10 @@ static int macb_mii_probe(struct net_device *dev)
 
        /* attach the mac to the phy */
        if (pdata && pdata->is_rmii) {
-               phydev = phy_connect(dev, phydev->dev.bus_id,
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
                        &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
        } else {
-               phydev = phy_connect(dev, phydev->dev.bus_id,
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
                        &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
        }
 
@@ -1077,7 +1077,7 @@ static void macb_get_drvinfo(struct net_device *dev,
 
        strcpy(info->driver, bp->pdev->dev.driver->name);
        strcpy(info->version, "$Revision: 1.14 $");
-       strcpy(info->bus_info, bp->pdev->dev.bus_id);
+       strcpy(info->bus_info, dev_name(&bp->pdev->dev));
 }
 
 static struct ethtool_ops macb_ethtool_ops = {
@@ -1234,8 +1234,8 @@ static int __init macb_probe(struct platform_device *pdev)
 
        phydev = bp->phy_dev;
        printk(KERN_INFO "%s: attached PHY driver [%s] "
-               "(mii_bus:phy_addr=%s, irq=%d)\n",
-               dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+               "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name,
+               phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
 
        return 0;
 
index 205bb05c25d6f41a2eec0abfdb958348179d0e93..527166e35d566b11897055e0aabb99911ab17c43 100644 (file)
@@ -176,7 +176,8 @@ static int __init macsonic_init(struct net_device *dev)
        if ((lp->descriptors = dma_alloc_coherent(lp->device,
                    SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
                    &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
+                      dev_name(lp->device));
                return -ENOMEM;
        }
 
@@ -337,7 +338,7 @@ static int __init mac_onboard_sonic_probe(struct net_device *dev)
                sonic_version_printed = 1;
        }
        printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
-              lp->device->bus_id, dev->base_addr);
+              dev_name(lp->device), dev->base_addr);
 
        /* The PowerBook's SONIC is 16 bit always. */
        if (macintosh_config->ident == MAC_MODEL_PB520) {
@@ -370,10 +371,10 @@ static int __init mac_onboard_sonic_probe(struct net_device *dev)
        }
        printk(KERN_INFO
               "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
-              lp->device->bus_id, sr, lp->dma_bitmode?32:16, lp->reg_offset);
+              dev_name(lp->device), sr, lp->dma_bitmode?32:16, lp->reg_offset);
 
 #if 0 /* This is sometimes useful to find out how MacOS configured the card. */
-       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
+       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device),
               SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
 #endif
 
@@ -525,12 +526,12 @@ static int __init mac_nubus_sonic_probe(struct net_device *dev)
                sonic_version_printed = 1;
        }
        printk(KERN_INFO "%s: %s in slot %X\n",
-              lp->device->bus_id, ndev->board->name, ndev->board->slot);
+              dev_name(lp->device), ndev->board->name, ndev->board->slot);
        printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
-              lp->device->bus_id, SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset);
+              dev_name(lp->device), SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset);
 
 #if 0 /* This is sometimes useful to find out how MacOS configured the card. */
-       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id,
+       printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device),
               SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
 #endif
 
index 4e7a5faf035103a07c3c23b800b0abcfb3bd85fe..664835b822fba31ed7d3d8cd15ce20172887dc36 100644 (file)
@@ -237,7 +237,7 @@ static void mipsnet_set_mclist(struct net_device *dev)
 {
 }
 
-static int __init mipsnet_probe(struct device *dev)
+static int __init mipsnet_probe(struct platform_device *dev)
 {
        struct net_device *netdev;
        int err;
@@ -248,7 +248,7 @@ static int __init mipsnet_probe(struct device *dev)
                goto out;
        }
 
-       dev_set_drvdata(dev, netdev);
+       platform_set_drvdata(dev, netdev);
 
        netdev->open                    = mipsnet_open;
        netdev->stop                    = mipsnet_close;
@@ -293,23 +293,25 @@ out:
        return err;
 }
 
-static int __devexit mipsnet_device_remove(struct device *device)
+static int __devexit mipsnet_device_remove(struct platform_device *device)
 {
-       struct net_device *dev = dev_get_drvdata(device);
+       struct net_device *dev = platform_get_drvdata(device);
 
        unregister_netdev(dev);
        release_region(dev->base_addr, sizeof(struct mipsnet_regs));
        free_netdev(dev);
-       dev_set_drvdata(device, NULL);
+       platform_set_drvdata(device, NULL);
 
        return 0;
 }
 
-static struct device_driver mipsnet_driver = {
-       .name   = mipsnet_string,
-       .bus    = &platform_bus_type,
-       .probe  = mipsnet_probe,
-       .remove = __devexit_p(mipsnet_device_remove),
+static struct platform_driver mipsnet_driver = {
+       .driver = {
+               .name           = mipsnet_string,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = mipsnet_probe,
+       .remove         = __devexit_p(mipsnet_device_remove),
 };
 
 static int __init mipsnet_init_module(void)
@@ -319,7 +321,7 @@ static int __init mipsnet_init_module(void)
        printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
               "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
 
-       err = driver_register(&mipsnet_driver);
+       err = platform_driver_register(&mipsnet_driver);
        if (err)
                printk(KERN_ERR "Driver registration failed\n");
 
@@ -328,7 +330,7 @@ static int __init mipsnet_init_module(void)
 
 static void __exit mipsnet_exit_module(void)
 {
-       driver_unregister(&mipsnet_driver);
+       platform_driver_unregister(&mipsnet_driver);
 }
 
 module_init(mipsnet_init_module);
index b0bc3bc18e9cdffc808a9957e964f4c81e530954..fe4e158c893dc67d40066912e94b67fb58399d04 100644 (file)
@@ -2588,7 +2588,7 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
 
        phy_reset(mp);
 
-       phy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII);
+       phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII);
 
        if (speed == 0) {
                phy->autoneg = AUTONEG_ENABLE;
index 31e38fae017f8def7273d568089914599a1b54d6..845431c186ac3475cacf44d6794544f9b2e3d5ec 100644 (file)
@@ -2478,7 +2478,7 @@ static int sbmac_mii_probe(struct net_device *dev)
                return -ENXIO;
        }
 
-       phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0,
+       phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll, 0,
                              PHY_INTERFACE_MODE_GMII);
        if (IS_ERR(phy_dev)) {
                printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
@@ -2500,7 +2500,7 @@ static int sbmac_mii_probe(struct net_device *dev)
 
        pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
                dev->name, phy_dev->drv->name,
-               phy_dev->dev.bus_id, phy_dev->irq);
+               dev_name(&phy_dev->dev), phy_dev->irq);
 
        sc->phy_dev = phy_dev;
 
@@ -2697,7 +2697,7 @@ static int __init sbmac_probe(struct platform_device *pldev)
        sbm_base = ioremap_nocache(res->start, res->end - res->start + 1);
        if (!sbm_base) {
                printk(KERN_ERR "%s: unable to map device registers\n",
-                      pldev->dev.bus_id);
+                      dev_name(&pldev->dev));
                err = -ENOMEM;
                goto out_out;
        }
@@ -2708,7 +2708,7 @@ static int __init sbmac_probe(struct platform_device *pldev)
         * If we find a zero, skip this MAC.
         */
        sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
-       pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id,
+       pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", dev_name(&pldev->dev),
                 sbmac_orig_hwaddr ? "" : "not ", (long long)res->start);
        if (sbmac_orig_hwaddr == 0) {
                err = 0;
@@ -2721,7 +2721,7 @@ static int __init sbmac_probe(struct platform_device *pldev)
        dev = alloc_etherdev(sizeof(struct sbmac_softc));
        if (!dev) {
                printk(KERN_ERR "%s: unable to allocate etherdev\n",
-                      pldev->dev.bus_id);
+                      dev_name(&pldev->dev));
                err = -ENOMEM;
                goto out_unmap;
        }
index 223cde0d43be8a6674f956cea35e3a490530cfdb..293610334a778b2ca81c4af52a2b8e391d13b204 100644 (file)
@@ -1545,7 +1545,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        strncpy(info->driver, CARDNAME, sizeof(info->driver));
        strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
+       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
 }
 
 static int smc911x_ethtool_nwayreset(struct net_device *dev)
index b215a8d85e62d5e2fc3eb54064918ae8dd90fd97..0b6da95014444eb7a31a2cfe21023cf59de6d8b3 100644 (file)
@@ -1614,7 +1614,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        strncpy(info->driver, CARDNAME, sizeof(info->driver));
        strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
+       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
 }
 
 static int smc_ethtool_nwayreset(struct net_device *dev)
index d1590ac55e4b8826a81251c3fd0b2011931be0f2..ab18ee0f60f31918270dae2422186bf4348ab2a6 100644 (file)
@@ -769,7 +769,7 @@ static int smsc911x_mii_probe(struct net_device *dev)
                return -ENODEV;
        }
 
-       phydev = phy_connect(dev, phydev->dev.bus_id,
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
                &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface);
 
        if (IS_ERR(phydev)) {
@@ -778,7 +778,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
        }
 
        pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-               dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+               dev->name, phydev->drv->name,
+               dev_name(&phydev->dev), phydev->irq);
 
        /* mask with MAC supported features */
        phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
@@ -1549,7 +1550,7 @@ static void smsc911x_ethtool_getdrvinfo(struct net_device *dev,
 {
        strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver));
        strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version));
-       strlcpy(info->bus_info, dev->dev.parent->bus_id,
+       strlcpy(info->bus_info, dev_name(dev->dev.parent),
                sizeof(info->bus_info));
 }
 
index 4e15ae068b3ffdfb64bb974d7f6e9080e13f3c97..72f1348eb809b06d6c5550a796427f847ab4f154 100644 (file)
@@ -1160,7 +1160,7 @@ static int smsc9420_mii_probe(struct net_device *dev)
        smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr,
                phydev->phy_id);
 
-       phydev = phy_connect(dev, phydev->dev.bus_id,
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
                &smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
@@ -1169,7 +1169,7 @@ static int smsc9420_mii_probe(struct net_device *dev)
        }
 
        pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-               dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+               dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
 
        /* mask with MAC supported features */
        phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
index bcd0e60cbda98984c9383f55cc4df671510d33a1..e1f8eb96a45ca3821976028bfb8c57c5a30ce0af 100644 (file)
@@ -725,7 +725,7 @@ static int tc_mii_probe(struct net_device *dev)
        }
 
        /* attach the mac to the phy */
-       phydev = phy_connect(dev, phydev->dev.bus_id,
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
                             &tc_handle_link_change, 0,
                             lp->chiptype == TC35815_TX4939 ?
                             PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
@@ -735,7 +735,7 @@ static int tc_mii_probe(struct net_device *dev)
        }
        printk(KERN_INFO "%s: attached PHY driver [%s] "
                "(mii_bus:phy_addr=%s, id=%x)\n",
-               dev->name, phydev->drv->name, phydev->dev.bus_id,
+               dev->name, phydev->drv->name, dev_name(&phydev->dev),
                phydev->phy_id);
 
        /* mask with MAC supported features */
index e80a0b65a7549d4fb2fec512a363586aac65f04b..d58b971faa648b5018dcc849372719daeb6f497d 100644 (file)
@@ -613,7 +613,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
 
        snprintf(wimax_dev->name, sizeof(wimax_dev->name),
-                "i2400m-%s:%s", dev->bus->name, dev->bus_id);
+                "i2400m-%s:%s", dev->bus->name, dev_name(dev));
 
        i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL);
        if (i2400m->bm_cmd_buf == NULL) {
index 9702c22b24974052ac7664b82475378b8cbe5bcd..0528879f6d39b66ef9239fd166c783425ebd7bdc 100644 (file)
@@ -102,7 +102,7 @@ int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
                dev_err(dev, "HW BUG? Unknown/unexpected data in notification "
                        "message (%zu bytes)\n", buf_len);
                snprintf(prefix, sizeof(prefix), "%s %s: ",
-                        dev_driver_string(dev) , dev->bus_id);
+                        dev_driver_string(dev) , dev_name(dev));
                if (buf_len > 64) {
                        print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
                                       8, 4, buf, 64, 0);
index 03a3f34e90393c43202db9731caac53cd25ed40a..a12a7211c982fc7284b8cb2a01b0c52c966a2718 100644 (file)
@@ -183,7 +183,7 @@ static int __init sonic_probe1(struct net_device *dev)
 
        if (lp->descriptors == NULL) {
                printk(KERN_ERR "%s: couldn't alloc DMA memory for "
-                               " descriptors.\n", lp->device->bus_id);
+                               " descriptors.\n", dev_name(lp->device));
                goto out;
        }
 
index a13abf55d7844adba846c7c99c2e23d376e05fec..8450f4a6568a852a288b75a62436e913b71e7ef8 100644 (file)
@@ -225,7 +225,8 @@ void cpqhp_shutdown_debugfs(void)
 
 void cpqhp_create_debugfs_files(struct controller *ctrl)
 {
-       ctrl->dentry = debugfs_create_file(ctrl->pci_dev->dev.bus_id, S_IRUGO, root, ctrl, &debug_ops);
+       ctrl->dentry = debugfs_create_file(dev_name(&ctrl->pci_dev->dev),
+                                          S_IRUGO, root, ctrl, &debug_ops);
 }
 
 void cpqhp_remove_debugfs_files(struct controller *ctrl)
index fc1de46fd20a0f5317389861380c0903858fee5a..90013341cd5f8bd90f7c34f228984a6325baa3cd 100644 (file)
@@ -468,13 +468,13 @@ out:
        return ret;
 }
 
-int au1x00_drv_pcmcia_remove(struct device *dev)
+int au1x00_drv_pcmcia_remove(struct platform_device *dev)
 {
-       struct skt_dev_info *sinfo = dev_get_drvdata(dev);
+       struct skt_dev_info *sinfo = platform_get_drvdata(dev);
        int i;
 
        mutex_lock(&pcmcia_sockets_lock);
-       dev_set_drvdata(dev, NULL);
+       platform_set_drvdata(dev, NULL);
 
        for (i = 0; i < sinfo->nskt; i++) {
                struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
@@ -498,13 +498,13 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
  * PCMCIA "Driver" API
  */
 
-static int au1x00_drv_pcmcia_probe(struct device *dev)
+static int au1x00_drv_pcmcia_probe(struct platform_device *dev)
 {
        int i, ret = -ENODEV;
 
        mutex_lock(&pcmcia_sockets_lock);
        for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
-               ret = au1x00_pcmcia_hw_init[i](dev);
+               ret = au1x00_pcmcia_hw_init[i](&dev->dev);
                if (ret == 0)
                        break;
        }
@@ -512,14 +512,26 @@ static int au1x00_drv_pcmcia_probe(struct device *dev)
        return ret;
 }
 
+static int au1x00_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int au1x00_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
 
-static struct device_driver au1x00_pcmcia_driver = {
+static struct platform_driver au1x00_pcmcia_driver = {
+       .driver = {
+               .name           = "au1x00-pcmcia",
+               .owner          = THIS_MODULE,
+       },
        .probe          = au1x00_drv_pcmcia_probe,
        .remove         = au1x00_drv_pcmcia_remove,
-       .name           = "au1x00-pcmcia",
-       .bus            = &platform_bus_type,
-       .suspend        = pcmcia_socket_dev_suspend,
-       .resume         = pcmcia_socket_dev_resume,
+       .suspend        = au1x00_drv_pcmcia_suspend,
+       .resume         = au1x00_drv_pcmcia_resume,
 };
 
 
@@ -533,8 +545,7 @@ static struct device_driver au1x00_pcmcia_driver = {
 static int __init au1x00_pcmcia_init(void)
 {
        int error = 0;
-       if ((error = driver_register(&au1x00_pcmcia_driver)))
-               return error;
+       error = platform_driver_register(&au1x00_pcmcia_driver);
        return error;
 }
 
@@ -544,7 +555,7 @@ static int __init au1x00_pcmcia_init(void)
  */
 static void __exit au1x00_pcmcia_exit(void)
 {
-       driver_unregister(&au1x00_pcmcia_driver);
+       platform_driver_unregister(&au1x00_pcmcia_driver);
 }
 
 module_init(au1x00_pcmcia_init);
index 71653ab8489015f768459866a4ea1ff3d23e84d2..40d4953e4b12ee2be19effe5e8472a16686bbc7b 100644 (file)
@@ -1238,6 +1238,16 @@ static int pcic_init(struct pcmcia_socket *s)
        return 0;
 }
 
+static int i82365_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int i82365_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
 static struct pccard_operations pcic_operations = {
        .init                   = pcic_init,
        .get_status             = pcic_get_status,
@@ -1248,11 +1258,13 @@ static struct pccard_operations pcic_operations = {
 
 /*====================================================================*/
 
-static struct device_driver i82365_driver = {
-       .name = "i82365",
-       .bus = &platform_bus_type,
-       .suspend = pcmcia_socket_dev_suspend,
-       .resume = pcmcia_socket_dev_resume,
+static struct platform_driver i82365_driver = {
+       .driver = {
+               .name = "i82365",
+               .owner          = THIS_MODULE,
+       },
+       .suspend        = i82365_drv_pcmcia_suspend,
+       .resume         = i82365_drv_pcmcia_resume,
 };
 
 static struct platform_device *i82365_device;
@@ -1261,7 +1273,7 @@ static int __init init_i82365(void)
 {
     int i, ret;
 
-    ret = driver_register(&i82365_driver);
+    ret = platform_driver_register(&i82365_driver);
     if (ret)
        goto err_out;
 
@@ -1337,7 +1349,7 @@ err_dev_unregister:
        pnp_disable_dev(i82365_pnpdev);
 #endif
 err_driver_unregister:
-    driver_unregister(&i82365_driver);
+    platform_driver_unregister(&i82365_driver);
 err_out:
     return ret;
 } /* init_i82365 */
@@ -1365,7 +1377,7 @@ static void __exit exit_i82365(void)
     if (i82365_pnpdev)
                pnp_disable_dev(i82365_pnpdev);
 #endif
-    driver_unregister(&i82365_driver);
+    platform_driver_unregister(&i82365_driver);
 } /* exit_i82365 */
 
 module_init(init_i82365);
index 2ab4f22c21de423a7fccb64cc6562b444e6c1b59..62b4ecc97c46fe513014e04c91167cb64248080c 100644 (file)
@@ -696,13 +696,25 @@ static struct pccard_operations pcc_operations = {
        .set_mem_map            = pcc_set_mem_map,
 };
 
+static int cfc_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int cfc_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
 /*====================================================================*/
 
-static struct device_driver pcc_driver = {
-       .name = "cfc",
-       .bus = &platform_bus_type,
-       .suspend = pcmcia_socket_dev_suspend,
-       .resume = pcmcia_socket_dev_resume,
+static struct platform_driver pcc_driver = {
+       .driver = {
+               .name           = "cfc",
+               .owner          = THIS_MODULE,
+       },
+       .suspend        = cfc_drv_pcmcia_suspend,
+       .resume         = cfc_drv_pcmcia_resume,
 };
 
 static struct platform_device pcc_device = {
@@ -716,13 +728,13 @@ static int __init init_m32r_pcc(void)
 {
        int i, ret;
 
-       ret = driver_register(&pcc_driver);
+       ret = platform_driver_register(&pcc_driver);
        if (ret)
                return ret;
 
        ret = platform_device_register(&pcc_device);
        if (ret){
-               driver_unregister(&pcc_driver);
+               platform_driver_unregister(&pcc_driver);
                return ret;
        }
 
@@ -754,7 +766,7 @@ static int __init init_m32r_pcc(void)
        if (pcc_sockets == 0) {
                printk("socket is not found.\n");
                platform_device_unregister(&pcc_device);
-               driver_unregister(&pcc_driver);
+               platform_driver_unregister(&pcc_driver);
                return -ENODEV;
        }
 
@@ -802,7 +814,7 @@ static void __exit exit_m32r_pcc(void)
        if (poll_interval != 0)
                del_timer_sync(&poll_timer);
 
-       driver_unregister(&pcc_driver);
+       platform_driver_unregister(&pcc_driver);
 } /* exit_m32r_pcc */
 
 module_init(init_m32r_pcc);
index 2f108c23dbd98872dc474bf4e19f901fbab63378..12034b41d196a9e4a566977877b7bc5d84f091d2 100644 (file)
@@ -672,13 +672,25 @@ static struct pccard_operations pcc_operations = {
        .set_mem_map            = pcc_set_mem_map,
 };
 
+static int pcc_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int pcc_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
 /*====================================================================*/
 
-static struct device_driver pcc_driver = {
-       .name = "pcc",
-       .bus = &platform_bus_type,
-       .suspend = pcmcia_socket_dev_suspend,
-       .resume = pcmcia_socket_dev_resume,
+static struct platform_driver pcc_driver = {
+       .driver = {
+               .name           = "pcc",
+               .owner          = THIS_MODULE,
+       },
+       .suspend        = pcc_drv_pcmcia_suspend,
+       .resume         = pcc_drv_pcmcia_resume,
 };
 
 static struct platform_device pcc_device = {
@@ -692,13 +704,13 @@ static int __init init_m32r_pcc(void)
 {
        int i, ret;
 
-       ret = driver_register(&pcc_driver);
+       ret = platform_driver_register(&pcc_driver);
        if (ret)
                return ret;
 
        ret = platform_device_register(&pcc_device);
        if (ret){
-               driver_unregister(&pcc_driver);
+               platform_driver_unregister(&pcc_driver);
                return ret;
        }
 
@@ -715,7 +727,7 @@ static int __init init_m32r_pcc(void)
        if (pcc_sockets == 0) {
                printk("socket is not found.\n");
                platform_device_unregister(&pcc_device);
-               driver_unregister(&pcc_driver);
+               platform_driver_unregister(&pcc_driver);
                return -ENODEV;
        }
 
@@ -763,7 +775,7 @@ static void __exit exit_m32r_pcc(void)
        if (poll_interval != 0)
                del_timer_sync(&poll_timer);
 
-       driver_unregister(&pcc_driver);
+       platform_driver_unregister(&pcc_driver);
 } /* exit_m32r_pcc */
 
 module_init(init_m32r_pcc);
index c0e2afc79e3e4555877562498d30035aa65815ae..e592e0e0d7ed3a88dcdb0b4379b1ad69edfd3cc3 100644 (file)
@@ -153,7 +153,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
                unsigned long align, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_IO,
-                                            s->dev.bus_id);
+                                            dev_name(&s->dev));
        struct pcmcia_align_data data;
        unsigned long min = base;
        int ret;
index c5b2a44b4c3783bc4da19bb2bd481cd2b30088ca..d8da5ac844e96b4739f130953e086216b9f2023b 100644 (file)
@@ -65,7 +65,7 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
 #endif
 };
 
-static int sa11x0_drv_pcmcia_probe(struct device *dev)
+static int sa11x0_drv_pcmcia_probe(struct platform_device *dev)
 {
        int i, ret = -ENODEV;
 
@@ -73,7 +73,7 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev)
         * Initialise any "on-board" PCMCIA sockets.
         */
        for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) {
-               ret = sa11x0_pcmcia_hw_init[i](dev);
+               ret = sa11x0_pcmcia_hw_init[i](&dev->dev);
                if (ret == 0)
                        break;
        }
@@ -81,13 +81,31 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev)
        return ret;
 }
 
-static struct device_driver sa11x0_pcmcia_driver = {
+static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
+{
+       return soc_common_drv_pcmcia_remove(&dev->dev);
+}
+
+static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int sa11x0_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
+
+static struct platform_driver sa11x0_pcmcia_driver = {
+       .driver = {
+               .name           = "sa11x0-pcmcia",
+               .owner          = THIS_MODULE,
+       },
        .probe          = sa11x0_drv_pcmcia_probe,
-       .remove         = soc_common_drv_pcmcia_remove,
-       .name           = "sa11x0-pcmcia",
-       .bus            = &platform_bus_type,
-       .suspend        = pcmcia_socket_dev_suspend,
-       .resume         = pcmcia_socket_dev_resume,
+       .remove         = sa11x0_drv_pcmcia_remove,
+       .suspend        = sa11x0_drv_pcmcia_suspend,
+       .resume         = sa11x0_drv_pcmcia_resume,
 };
 
 /* sa11x0_pcmcia_init()
@@ -100,7 +118,7 @@ static struct device_driver sa11x0_pcmcia_driver = {
  */
 static int __init sa11x0_pcmcia_init(void)
 {
-       return driver_register(&sa11x0_pcmcia_driver);
+       return platform_driver_register(&sa11x0_pcmcia_driver);
 }
 
 /* sa11x0_pcmcia_exit()
@@ -110,7 +128,7 @@ static int __init sa11x0_pcmcia_init(void)
  */
 static void __exit sa11x0_pcmcia_exit(void)
 {
-       driver_unregister(&sa11x0_pcmcia_driver);
+       platform_driver_unregister(&sa11x0_pcmcia_driver);
 }
 
 MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
index 2a613e920fd4d19c4b9b802ec0ce291916c85fd8..9ad97ea836e8a0fc6ccb4f0721f387fae44f5d68 100644 (file)
@@ -363,13 +363,25 @@ static int __init get_tcic_id(void)
     return id;
 }
 
+static int tcic_drv_pcmcia_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int tcic_drv_pcmcia_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
 /*====================================================================*/
 
-static struct device_driver tcic_driver = {
-       .name = "tcic-pcmcia",
-       .bus = &platform_bus_type,
-       .suspend = pcmcia_socket_dev_suspend,
-       .resume = pcmcia_socket_dev_resume,
+static struct platform_driver tcic_driver = {
+       .driver = {
+               .name = "tcic-pcmcia",
+               .owner          = THIS_MODULE,
+       },
+       .suspend        = tcic_drv_pcmcia_suspend,
+       .resume         = tcic_drv_pcmcia_resume,
 };
 
 static struct platform_device tcic_device = {
@@ -383,7 +395,7 @@ static int __init init_tcic(void)
     int i, sock, ret = 0;
     u_int mask, scan;
 
-    if (driver_register(&tcic_driver))
+    if (platform_driver_register(&tcic_driver))
        return -1;
     
     printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
@@ -391,7 +403,7 @@ static int __init init_tcic(void)
 
     if (!request_region(tcic_base, 16, "tcic-2")) {
        printk("could not allocate ports,\n ");
-       driver_unregister(&tcic_driver);
+       platform_driver_unregister(&tcic_driver);
        return -ENODEV;
     }
     else {
@@ -414,7 +426,7 @@ static int __init init_tcic(void)
     if (sock == 0) {
        printk("not found.\n");
        release_region(tcic_base, 16);
-       driver_unregister(&tcic_driver);
+       platform_driver_unregister(&tcic_driver);
        return -ENODEV;
     }
 
@@ -542,7 +554,7 @@ static void __exit exit_tcic(void)
     }
 
     platform_device_unregister(&tcic_device);
-    driver_unregister(&tcic_driver);
+    platform_driver_unregister(&tcic_driver);
 } /* exit_tcic */
 
 /*====================================================================*/
index b2c412419059f9f5d03117305323378e784fb266..659421d0ca46aeab37fac76aefdee41cc6a5562d 100644 (file)
@@ -704,24 +704,37 @@ static int __devinit vrc4171_card_setup(char *options)
 
 __setup("vrc4171_card=", vrc4171_card_setup);
 
-static struct device_driver vrc4171_card_driver = {
-       .name           = vrc4171_card_name,
-       .bus            = &platform_bus_type,
-       .suspend        = pcmcia_socket_dev_suspend,
-       .resume         = pcmcia_socket_dev_resume,
+static int vrc4171_card_suspend(struct platform_device *dev,
+                                    pm_message_t state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int vrc4171_card_resume(struct platform_device *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
+
+static struct platform_driver vrc4171_card_driver = {
+       .driver = {
+               .name           = vrc4171_card_name,
+               .owner          = THIS_MODULE,
+       },
+       .suspend        = vrc4171_card_suspend,
+       .resume         = vrc4171_card_resume,
 };
 
 static int __devinit vrc4171_card_init(void)
 {
        int retval;
 
-       retval = driver_register(&vrc4171_card_driver);
+       retval = platform_driver_register(&vrc4171_card_driver);
        if (retval < 0)
                return retval;
 
        retval = platform_device_register(&vrc4171_card_device);
        if (retval < 0) {
-               driver_unregister(&vrc4171_card_driver);
+               platform_driver_unregister(&vrc4171_card_driver);
                return retval;
        }
 
@@ -735,11 +748,12 @@ static int __devinit vrc4171_card_init(void)
        if (retval < 0) {
                vrc4171_remove_sockets();
                platform_device_unregister(&vrc4171_card_device);
-               driver_unregister(&vrc4171_card_driver);
+               platform_driver_unregister(&vrc4171_card_driver);
                return retval;
        }
 
-       printk(KERN_INFO "%s, connected to IRQ %d\n", vrc4171_card_driver.name, vrc4171_irq);
+       printk(KERN_INFO "%s, connected to IRQ %d\n",
+               vrc4171_card_driver.driver.name, vrc4171_irq);
 
        return 0;
 }
@@ -749,7 +763,7 @@ static void __devexit vrc4171_card_exit(void)
        free_irq(vrc4171_irq, vrc4171_sockets);
        vrc4171_remove_sockets();
        platform_device_unregister(&vrc4171_card_device);
-       driver_unregister(&vrc4171_card_driver);
+       platform_driver_unregister(&vrc4171_card_driver);
 }
 
 module_init(vrc4171_card_init);
index addb87cf44d9954ecebe90687409dcf0c9aecb77..3222fa3c808ca4c96eeb3fc436122f041a84eebc 100644 (file)
@@ -193,7 +193,7 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
 }
 
 static struct device rio_bus = {
-       .bus_id = "rapidio",
+       .init_name = "rapidio",
 };
 
 struct bus_type rio_bus_type = {
index d5e4e637ddecb5a4f63db385510e3962cb0bb3dc..86c61f1435155a2707ea40a90b1889d4a5374ae8 100644 (file)
@@ -351,7 +351,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        /* register irq handler after we know what name we'll use */
        ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
                                IRQF_DISABLED | IRQF_SHARED,
-                               rtc->rtcdev->dev.bus_id, rtc);
+                               dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
                rtc_device_unregister(rtc->rtcdev);
@@ -366,7 +366,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
 
        if (gpbr_readl(rtc) == 0)
                dev_warn(&pdev->dev, "%s: SET TIME!\n",
-                               rtc->rtcdev->dev.bus_id);
+                               dev_name(&rtc->rtcdev->dev));
 
        return 0;
 
index 2cbeb0794f142f2172b75566ed6e4929315f99f1..bd1ce8e2bc1866d8a6fbeff8318b5ac7d105675a 100644 (file)
@@ -377,13 +377,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
 
        /* handle periodic and alarm irqs */
        if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
-                       rtc->dev.bus_id, rtc)) {
+                       dev_name(&rtc->dev), rtc)) {
                pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_timer);
                goto fail0;
        }
        if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
-                       rtc->dev.bus_id, rtc)) {
+                       dev_name(&rtc->dev), rtc)) {
                pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_alarm);
                goto fail1;
index 1c3fc6b428e9a705c8b711053401e859f52bca6d..4898f7fe8518062f1beb60b9952fb3fba87a3de6 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/rtc.h>
 
 #define DRV_NAME       "sh-rtc"
-#define DRV_VERSION    "0.2.0"
+#define DRV_VERSION    "0.2.1"
 
 #define RTC_REG(r)     ((r) * rtc_reg_size)
 
@@ -99,56 +99,51 @@ struct sh_rtc {
        unsigned short periodic_freq;
 };
 
-static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
+static int __sh_rtc_interrupt(struct sh_rtc *rtc)
 {
-       struct sh_rtc *rtc = dev_id;
-       unsigned int tmp;
-
-       spin_lock(&rtc->lock);
+       unsigned int tmp, pending;
 
        tmp = readb(rtc->regbase + RCR1);
+       pending = tmp & RCR1_CF;
        tmp &= ~RCR1_CF;
        writeb(tmp, rtc->regbase + RCR1);
 
        /* Users have requested One x Second IRQ */
-       if (rtc->periodic_freq & PF_OXS)
+       if (pending && rtc->periodic_freq & PF_OXS)
                rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
 
-       spin_unlock(&rtc->lock);
-
-       return IRQ_HANDLED;
+       return pending;
 }
 
-static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
+static int __sh_rtc_alarm(struct sh_rtc *rtc)
 {
-       struct sh_rtc *rtc = dev_id;
-       unsigned int tmp;
-
-       spin_lock(&rtc->lock);
+       unsigned int tmp, pending;
 
        tmp = readb(rtc->regbase + RCR1);
+       pending = tmp & RCR1_AF;
        tmp &= ~(RCR1_AF | RCR1_AIE);
-               writeb(tmp, rtc->regbase + RCR1);
-
-       rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+       writeb(tmp, rtc->regbase + RCR1);
 
-       spin_unlock(&rtc->lock);
+       if (pending)
+               rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
 
-       return IRQ_HANDLED;
+       return pending;
 }
 
-static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
+static int __sh_rtc_periodic(struct sh_rtc *rtc)
 {
-       struct sh_rtc *rtc = dev_id;
        struct rtc_device *rtc_dev = rtc->rtc_dev;
-       unsigned int tmp;
-
-       spin_lock(&rtc->lock);
+       struct rtc_task *irq_task;
+       unsigned int tmp, pending;
 
        tmp = readb(rtc->regbase + RCR2);
+       pending = tmp & RCR2_PEF;
        tmp &= ~RCR2_PEF;
        writeb(tmp, rtc->regbase + RCR2);
 
+       if (!pending)
+               return 0;
+
        /* Half period enabled than one skipped and the next notified */
        if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT))
                rtc->periodic_freq &= ~PF_COUNT;
@@ -157,16 +152,65 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
                        rtc->periodic_freq |= PF_COUNT;
                if (rtc->periodic_freq & PF_KOU) {
                        spin_lock(&rtc_dev->irq_task_lock);
-                       if (rtc_dev->irq_task)
-                               rtc_dev->irq_task->func(rtc_dev->irq_task->private_data);
+                       irq_task = rtc_dev->irq_task;
+                       if (irq_task)
+                               irq_task->func(irq_task->private_data);
                        spin_unlock(&rtc_dev->irq_task_lock);
                } else
                        rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
        }
 
+       return pending;
+}
+
+static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
+{
+       struct sh_rtc *rtc = dev_id;
+       int ret;
+
+       spin_lock(&rtc->lock);
+       ret = __sh_rtc_interrupt(rtc);
+       spin_unlock(&rtc->lock);
+
+       return IRQ_RETVAL(ret);
+}
+
+static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
+{
+       struct sh_rtc *rtc = dev_id;
+       int ret;
+
+       spin_lock(&rtc->lock);
+       ret = __sh_rtc_alarm(rtc);
+       spin_unlock(&rtc->lock);
+
+       return IRQ_RETVAL(ret);
+}
+
+static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
+{
+       struct sh_rtc *rtc = dev_id;
+       int ret;
+
+       spin_lock(&rtc->lock);
+       ret = __sh_rtc_periodic(rtc);
        spin_unlock(&rtc->lock);
 
-       return IRQ_HANDLED;
+       return IRQ_RETVAL(ret);
+}
+
+static irqreturn_t sh_rtc_shared(int irq, void *dev_id)
+{
+       struct sh_rtc *rtc = dev_id;
+       int ret;
+
+       spin_lock(&rtc->lock);
+       ret = __sh_rtc_interrupt(rtc);
+       ret |= __sh_rtc_alarm(rtc);
+       ret |= __sh_rtc_periodic(rtc);
+       spin_unlock(&rtc->lock);
+
+       return IRQ_RETVAL(ret);
 }
 
 static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
@@ -275,6 +319,25 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
+static inline void sh_rtc_setcie(struct device *dev, unsigned int enable)
+{
+       struct sh_rtc *rtc = dev_get_drvdata(dev);
+       unsigned int tmp;
+
+       spin_lock_irq(&rtc->lock);
+
+       tmp = readb(rtc->regbase + RCR1);
+
+       if (!enable)
+               tmp &= ~RCR1_CIE;
+       else
+               tmp |= RCR1_CIE;
+
+       writeb(tmp, rtc->regbase + RCR1);
+
+       spin_unlock_irq(&rtc->lock);
+}
+
 static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        struct sh_rtc *rtc = dev_get_drvdata(dev);
@@ -291,9 +354,11 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
                break;
        case RTC_UIE_OFF:
                rtc->periodic_freq &= ~PF_OXS;
+               sh_rtc_setcie(dev, 0);
                break;
        case RTC_UIE_ON:
                rtc->periodic_freq |= PF_OXS;
+               sh_rtc_setcie(dev, 1);
                break;
        case RTC_IRQP_READ:
                ret = put_user(rtc->rtc_dev->irq_freq,
@@ -356,18 +421,17 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_sec--;
 #endif
 
+       /* only keep the carry interrupt enabled if UIE is on */
+       if (!(rtc->periodic_freq & PF_OXS))
+               sh_rtc_setcie(dev, 0);
+
        dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
                "mday=%d, mon=%d, year=%d, wday=%d\n",
                __func__,
                tm->tm_sec, tm->tm_min, tm->tm_hour,
                tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
 
-       if (rtc_valid_tm(tm) < 0) {
-               dev_err(dev, "invalid date\n");
-               rtc_time_to_tm(0, tm);
-       }
-
-       return 0;
+       return rtc_valid_tm(tm);
 }
 
 static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -572,7 +636,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
 {
        struct sh_rtc *rtc;
        struct resource *res;
-       unsigned int tmp;
+       struct rtc_time r;
        int ret;
 
        rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
@@ -585,26 +649,12 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
        ret = platform_get_irq(pdev, 0);
        if (unlikely(ret <= 0)) {
                ret = -ENOENT;
-               dev_err(&pdev->dev, "No IRQ for period\n");
+               dev_err(&pdev->dev, "No IRQ resource\n");
                goto err_badres;
        }
        rtc->periodic_irq = ret;
-
-       ret = platform_get_irq(pdev, 1);
-       if (unlikely(ret <= 0)) {
-               ret = -ENOENT;
-               dev_err(&pdev->dev, "No IRQ for carry\n");
-               goto err_badres;
-       }
-       rtc->carry_irq = ret;
-
-       ret = platform_get_irq(pdev, 2);
-       if (unlikely(ret <= 0)) {
-               ret = -ENOENT;
-               dev_err(&pdev->dev, "No IRQ for alarm\n");
-               goto err_badres;
-       }
-       rtc->alarm_irq = ret;
+       rtc->carry_irq = platform_get_irq(pdev, 1);
+       rtc->alarm_irq = platform_get_irq(pdev, 2);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (unlikely(res == NULL)) {
@@ -646,47 +696,66 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
        }
 
        rtc->rtc_dev->max_user_freq = 256;
-       rtc->rtc_dev->irq_freq = 1;
-       rtc->periodic_freq = 0x60;
 
        platform_set_drvdata(pdev, rtc);
 
-       /* register periodic/carry/alarm irqs */
-       ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED,
-                         "sh-rtc period", rtc);
-       if (unlikely(ret)) {
-               dev_err(&pdev->dev,
-                       "request period IRQ failed with %d, IRQ %d\n", ret,
-                       rtc->periodic_irq);
-               goto err_unmap;
-       }
+       if (rtc->carry_irq <= 0) {
+               /* register shared periodic/carry/alarm irq */
+               ret = request_irq(rtc->periodic_irq, sh_rtc_shared,
+                                 IRQF_DISABLED, "sh-rtc", rtc);
+               if (unlikely(ret)) {
+                       dev_err(&pdev->dev,
+                               "request IRQ failed with %d, IRQ %d\n", ret,
+                               rtc->periodic_irq);
+                       goto err_unmap;
+               }
+       } else {
+               /* register periodic/carry/alarm irqs */
+               ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
+                                 IRQF_DISABLED, "sh-rtc period", rtc);
+               if (unlikely(ret)) {
+                       dev_err(&pdev->dev,
+                               "request period IRQ failed with %d, IRQ %d\n",
+                               ret, rtc->periodic_irq);
+                       goto err_unmap;
+               }
 
-       ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
-                         "sh-rtc carry", rtc);
-       if (unlikely(ret)) {
-               dev_err(&pdev->dev,
-                       "request carry IRQ failed with %d, IRQ %d\n", ret,
-                       rtc->carry_irq);
-               free_irq(rtc->periodic_irq, rtc);
-               goto err_unmap;
-       }
+               ret = request_irq(rtc->carry_irq, sh_rtc_interrupt,
+                                 IRQF_DISABLED, "sh-rtc carry", rtc);
+               if (unlikely(ret)) {
+                       dev_err(&pdev->dev,
+                               "request carry IRQ failed with %d, IRQ %d\n",
+                               ret, rtc->carry_irq);
+                       free_irq(rtc->periodic_irq, rtc);
+                       goto err_unmap;
+               }
 
-       ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
-                         "sh-rtc alarm", rtc);
-       if (unlikely(ret)) {
-               dev_err(&pdev->dev,
-                       "request alarm IRQ failed with %d, IRQ %d\n", ret,
-                       rtc->alarm_irq);
-               free_irq(rtc->carry_irq, rtc);
-               free_irq(rtc->periodic_irq, rtc);
-               goto err_unmap;
+               ret = request_irq(rtc->alarm_irq, sh_rtc_alarm,
+                                 IRQF_DISABLED, "sh-rtc alarm", rtc);
+               if (unlikely(ret)) {
+                       dev_err(&pdev->dev,
+                               "request alarm IRQ failed with %d, IRQ %d\n",
+                               ret, rtc->alarm_irq);
+                       free_irq(rtc->carry_irq, rtc);
+                       free_irq(rtc->periodic_irq, rtc);
+                       goto err_unmap;
+               }
        }
 
-       tmp = readb(rtc->regbase + RCR1);
-       tmp &= ~RCR1_CF;
-       tmp |= RCR1_CIE;
-       writeb(tmp, rtc->regbase + RCR1);
+       /* everything disabled by default */
+       rtc->periodic_freq = 0;
+       rtc->rtc_dev->irq_freq = 0;
+       sh_rtc_setpie(&pdev->dev, 0);
+       sh_rtc_setaie(&pdev->dev, 0);
+       sh_rtc_setcie(&pdev->dev, 0);
+
+       /* reset rtc to epoch 0 if time is invalid */
+       if (rtc_read_time(rtc->rtc_dev, &r) < 0) {
+               rtc_time_to_tm(0, &r);
+               rtc_set_time(rtc->rtc_dev, &r);
+       }
 
+       device_init_wakeup(&pdev->dev, 1);
        return 0;
 
 err_unmap:
@@ -708,10 +777,13 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev)
 
        sh_rtc_setpie(&pdev->dev, 0);
        sh_rtc_setaie(&pdev->dev, 0);
+       sh_rtc_setcie(&pdev->dev, 0);
 
-       free_irq(rtc->carry_irq, rtc);
        free_irq(rtc->periodic_irq, rtc);
-       free_irq(rtc->alarm_irq, rtc);
+       if (rtc->carry_irq > 0) {
+               free_irq(rtc->carry_irq, rtc);
+               free_irq(rtc->alarm_irq, rtc);
+       }
 
        release_resource(rtc->res);
 
index ad35f76c46b7f1a2ee84f7b12e883b50e5e299cf..a6341e4f9a0ff9e489c017fe8ea6e7e81474dc35 100644 (file)
@@ -426,7 +426,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
 
        ret = request_irq(irq, twl4030_rtc_interrupt,
                                IRQF_TRIGGER_RISING,
-                               rtc->dev.bus_id, rtc);
+                               dev_name(&rtc->dev), rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
                goto out1;
index 918e6fce2573fcd9fe18e61a41c6d26fd3872c56..b91c1719b07563db660db3522b057bcd3373c49d 100644 (file)
@@ -104,8 +104,9 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const
        rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
 out:
        if (rc) {
-               /* Release onoff "lock" when ungrouping failed. */
-               atomic_set(&gdev->onoff, 0);
+               if (rc != -EAGAIN)
+                       /* Release onoff "lock" when ungrouping failed. */
+                       atomic_set(&gdev->onoff, 0);
                return rc;
        }
        return count;
index 0a2f2edafc03ea17bd54dcb7ef758002c021146c..93eca1731b81a56bb7d934a8c5e62119e8178eb9 100644 (file)
@@ -84,8 +84,8 @@ static int chsc_subchannel_probe(struct subchannel *sch)
                kfree(private);
        } else {
                sch->private = private;
-               if (sch->dev.uevent_suppress) {
-                       sch->dev.uevent_suppress = 0;
+               if (dev_get_uevent_suppress(&sch->dev)) {
+                       dev_set_uevent_suppress(&sch->dev, 0);
                        kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
                }
        }
index 8019288bc6dee0a730f79b6a4ed86228a3a052f3..427d11d88069c24cc4f2c77170aa36f6f6d95733 100644 (file)
@@ -272,7 +272,7 @@ static int css_register_subchannel(struct subchannel *sch)
         * the subchannel driver can decide itself when it wants to inform
         * userspace of its existence.
         */
-       sch->dev.uevent_suppress = 1;
+       dev_set_uevent_suppress(&sch->dev, 1);
        css_update_ssd_info(sch);
        /* make it known to the system */
        ret = css_sch_device_register(sch);
@@ -287,7 +287,7 @@ static int css_register_subchannel(struct subchannel *sch)
                 * a fitting driver module may be loaded based on the
                 * modalias.
                 */
-               sch->dev.uevent_suppress = 0;
+               dev_set_uevent_suppress(&sch->dev, 0);
                kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
        }
        return ret;
index 23d5752349b59d0f85b3274c206eea556123e10e..e28f8ae534539c4014b095409ed51017504a0868 100644 (file)
@@ -799,7 +799,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
                return;
        other_sch = to_subchannel(cdev->dev.parent);
        /* Note: device_move() changes cdev->dev.parent */
-       ret = device_move(&cdev->dev, &sch->dev);
+       ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
        if (ret) {
                CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
                              "(ret=%d)!\n", cdev->private->dev_id.ssid,
@@ -830,7 +830,7 @@ static void sch_attach_orphaned_device(struct subchannel *sch,
         * Try to move the ccw device to its new subchannel.
         * Note: device_move() changes cdev->dev.parent
         */
-       ret = device_move(&cdev->dev, &sch->dev);
+       ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
        if (ret) {
                CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
                              "failed (ret=%d)!\n",
@@ -897,7 +897,8 @@ void ccw_device_move_to_orphanage(struct work_struct *work)
         * ccw device can take its place on the subchannel.
         * Note: device_move() changes cdev->dev.parent
         */
-       ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
+       ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev,
+               DPM_ORDER_NONE);
        if (ret) {
                CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
                              "(ret=%d)!\n", cdev->private->dev_id.ssid,
@@ -981,7 +982,7 @@ io_subchannel_register(struct work_struct *work)
         * Now we know this subchannel will stay, we can throw
         * our delayed uevent.
         */
-       sch->dev.uevent_suppress = 0;
+       dev_set_uevent_suppress(&sch->dev, 0);
        kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
        /* make it known to the system */
        ret = ccw_device_register(cdev);
@@ -1129,7 +1130,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
         * Try to move the ccw device to its new subchannel.
         * Note: device_move() changes cdev->dev.parent
         */
-       rc = device_move(&cdev->dev, &sch->dev);
+       rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
        mutex_unlock(&sch->reg_mutex);
        if (rc) {
                CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
@@ -1243,7 +1244,7 @@ static int io_subchannel_probe(struct subchannel *sch)
                 * the ccw_device and exit. This happens for all early
                 * devices, e.g. the console.
                 */
-               sch->dev.uevent_suppress = 0;
+               dev_set_uevent_suppress(&sch->dev, 0);
                kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
                cdev->dev.groups = ccwdev_attr_groups;
                device_initialize(&cdev->dev);
index 3d04920b9bb99cbc70f6eb1270e61c13bc628cd0..0dcc036d34aa01c1297cbe8bda71f5d43824f8df 100644 (file)
@@ -1038,7 +1038,7 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)
        rc = qeth_query_setadapterparms(card);
        if (rc) {
                QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: "
-                       "0x%x\n", card->gdev->dev.bus_id, rc);
+                       "0x%x\n", dev_name(&card->gdev->dev), rc);
                return rc;
        }
        if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
index d4bda201774652d9f3df315fa182832abb52610c..61af3d91ac8a5187e4405decfe8fa8a0783c6530 100644 (file)
@@ -35,7 +35,7 @@ static struct platform_device *a4000t_scsi_device;
 
 #define A4000T_SCSI_ADDR 0xdd0040
 
-static int __devinit a4000t_probe(struct device *dev)
+static int __devinit a4000t_probe(struct platform_device *dev)
 {
        struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
@@ -61,7 +61,8 @@ static int __devinit a4000t_probe(struct device *dev)
        hostdata->dcntl_extra = EA_710;
 
        /* and register the chip */
-       host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, dev);
+       host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata,
+                             &dev->dev);
        if (!host) {
                printk(KERN_ERR "a4000t-scsi: No host detected; "
                                "board configuration problem?\n");
@@ -78,7 +79,7 @@ static int __devinit a4000t_probe(struct device *dev)
                goto out_put_host;
        }
 
-       dev_set_drvdata(dev, host);
+       platform_set_drvdata(dev, host);
        scsi_scan_host(host);
 
        return 0;
@@ -93,9 +94,9 @@ static int __devinit a4000t_probe(struct device *dev)
        return -ENODEV;
 }
 
-static __devexit int a4000t_device_remove(struct device *dev)
+static __devexit int a4000t_device_remove(struct platform_device *dev)
 {
-       struct Scsi_Host *host = dev_get_drvdata(dev);
+       struct Scsi_Host *host = platform_get_drvdata(dev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
        scsi_remove_host(host);
@@ -108,25 +109,27 @@ static __devexit int a4000t_device_remove(struct device *dev)
        return 0;
 }
 
-static struct device_driver a4000t_scsi_driver = {
-       .name   = "a4000t-scsi",
-       .bus    = &platform_bus_type,
-       .probe  = a4000t_probe,
-       .remove = __devexit_p(a4000t_device_remove),
+static struct platform_driver a4000t_scsi_driver = {
+       .driver = {
+               .name           = "a4000t-scsi",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = a4000t_probe,
+       .remove         = __devexit_p(a4000t_device_remove),
 };
 
 static int __init a4000t_scsi_init(void)
 {
        int err;
 
-       err = driver_register(&a4000t_scsi_driver);
+       err = platform_driver_register(&a4000t_scsi_driver);
        if (err)
                return err;
 
        a4000t_scsi_device = platform_device_register_simple("a4000t-scsi",
                        -1, NULL, 0);
        if (IS_ERR(a4000t_scsi_device)) {
-               driver_unregister(&a4000t_scsi_driver);
+               platform_driver_register(&a4000t_scsi_driver);
                return PTR_ERR(a4000t_scsi_device);
        }
 
@@ -136,7 +139,7 @@ static int __init a4000t_scsi_init(void)
 static void __exit a4000t_scsi_exit(void)
 {
        platform_device_unregister(a4000t_scsi_device);
-       driver_unregister(&a4000t_scsi_driver);
+       platform_driver_unregister(&a4000t_scsi_driver);
 }
 
 module_init(a4000t_scsi_init);
index d858f3d412744583d320202ac44bbb12bd6cece5..5799cb5cba6b5643e4128cab450aa49d1f0f754c 100644 (file)
@@ -34,7 +34,7 @@ static struct scsi_host_template bvme6000_scsi_driver_template = {
 static struct platform_device *bvme6000_scsi_device;
 
 static __devinit int
-bvme6000_probe(struct device *dev)
+bvme6000_probe(struct platform_device *dev)
 {
        struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
@@ -58,7 +58,8 @@ bvme6000_probe(struct device *dev)
        hostdata->ctest7_extra = CTEST7_TT1;
 
        /* and register the chip */
-       host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev);
+       host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata,
+                             &dev->dev);
        if (!host) {
                printk(KERN_ERR "bvme6000-scsi: No host detected; "
                                "board configuration problem?\n");
@@ -73,7 +74,7 @@ bvme6000_probe(struct device *dev)
                goto out_put_host;
        }
 
-       dev_set_drvdata(dev, host);
+       platform_set_drvdata(dev, host);
        scsi_scan_host(host);
 
        return 0;
@@ -87,9 +88,9 @@ bvme6000_probe(struct device *dev)
 }
 
 static __devexit int
-bvme6000_device_remove(struct device *dev)
+bvme6000_device_remove(struct platform_device *dev)
 {
-       struct Scsi_Host *host = dev_get_drvdata(dev);
+       struct Scsi_Host *host = platform_get_drvdata(dev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
        scsi_remove_host(host);
@@ -100,25 +101,27 @@ bvme6000_device_remove(struct device *dev)
        return 0;
 }
 
-static struct device_driver bvme6000_scsi_driver = {
-       .name   = "bvme6000-scsi",
-       .bus    = &platform_bus_type,
-       .probe  = bvme6000_probe,
-       .remove = __devexit_p(bvme6000_device_remove),
+static struct platform_driver bvme6000_scsi_driver = {
+       .driver = {
+               .name           = "bvme6000-scsi",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = bvme6000_probe,
+       .remove         = __devexit_p(bvme6000_device_remove),
 };
 
 static int __init bvme6000_scsi_init(void)
 {
        int err;
 
-       err = driver_register(&bvme6000_scsi_driver);
+       err = platform_driver_register(&bvme6000_scsi_driver);
        if (err)
                return err;
 
        bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi",
                                                               -1, NULL, 0);
        if (IS_ERR(bvme6000_scsi_device)) {
-               driver_unregister(&bvme6000_scsi_driver);
+               platform_driver_unregister(&bvme6000_scsi_driver);
                return PTR_ERR(bvme6000_scsi_device);
        }
 
@@ -128,7 +131,7 @@ static int __init bvme6000_scsi_init(void)
 static void __exit bvme6000_scsi_exit(void)
 {
        platform_device_unregister(bvme6000_scsi_device);
-       driver_unregister(&bvme6000_scsi_driver);
+       platform_driver_unregister(&bvme6000_scsi_driver);
 }
 
 module_init(bvme6000_scsi_init);
index b264b499d982203e00134e19f1aa80c41014c750..b5fbfd6ce870af0294bb909fa3ea42455bf8a8ae 100644 (file)
@@ -34,7 +34,7 @@ static struct scsi_host_template mvme16x_scsi_driver_template = {
 static struct platform_device *mvme16x_scsi_device;
 
 static __devinit int
-mvme16x_probe(struct device *dev)
+mvme16x_probe(struct platform_device *dev)
 {
        struct Scsi_Host * host = NULL;
        struct NCR_700_Host_Parameters *hostdata;
@@ -64,7 +64,8 @@ mvme16x_probe(struct device *dev)
        hostdata->ctest7_extra = CTEST7_TT1;
 
        /* and register the chip */
-       host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev);
+       host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata,
+                             &dev->dev);
        if (!host) {
                printk(KERN_ERR "mvme16x-scsi: No host detected; "
                                "board configuration problem?\n");
@@ -88,7 +89,7 @@ mvme16x_probe(struct device *dev)
                out_be32(0xfff4202c, v);
        }
 
-       dev_set_drvdata(dev, host);
+       platform_set_drvdata(dev, host);
        scsi_scan_host(host);
 
        return 0;
@@ -102,9 +103,9 @@ mvme16x_probe(struct device *dev)
 }
 
 static __devexit int
-mvme16x_device_remove(struct device *dev)
+mvme16x_device_remove(struct platform_device *dev)
 {
-       struct Scsi_Host *host = dev_get_drvdata(dev);
+       struct Scsi_Host *host = platform_get_drvdata(dev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
        /* Disable scsi chip ints */
@@ -123,25 +124,27 @@ mvme16x_device_remove(struct device *dev)
        return 0;
 }
 
-static struct device_driver mvme16x_scsi_driver = {
-       .name   = "mvme16x-scsi",
-       .bus    = &platform_bus_type,
-       .probe  = mvme16x_probe,
-       .remove = __devexit_p(mvme16x_device_remove),
+static struct platform_driver mvme16x_scsi_driver = {
+       .driver = {
+               .name           = "mvme16x-scsi",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = mvme16x_probe,
+       .remove         = __devexit_p(mvme16x_device_remove),
 };
 
 static int __init mvme16x_scsi_init(void)
 {
        int err;
 
-       err = driver_register(&mvme16x_scsi_driver);
+       err = platform_driver_register(&mvme16x_scsi_driver);
        if (err)
                return err;
 
        mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi",
                                                              -1, NULL, 0);
        if (IS_ERR(mvme16x_scsi_device)) {
-               driver_unregister(&mvme16x_scsi_driver);
+               platform_driver_unregister(&mvme16x_scsi_driver);
                return PTR_ERR(mvme16x_scsi_device);
        }
 
@@ -151,7 +154,7 @@ static int __init mvme16x_scsi_init(void)
 static void __exit mvme16x_scsi_exit(void)
 {
        platform_device_unregister(mvme16x_scsi_device);
-       driver_unregister(&mvme16x_scsi_driver);
+       platform_driver_unregister(&mvme16x_scsi_driver);
 }
 
 module_init(mvme16x_scsi_init);
index 557b54ab2f25d22b0f623b7f6dde18cb12cc47f2..dbf5357a77b30e1678e268a485ae51e98c3eb7ce 100644 (file)
@@ -139,7 +139,7 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
        } while (!(status & SCxSR_TDxE(port)));
 
        sci_in(port, SCxSR);            /* Dummy read */
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
        sci_out(port, SCxTDR, c);
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -263,6 +263,7 @@ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
       defined(CONFIG_CPU_SUBTYPE_SH7780) || \
       defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
       defined(CONFIG_CPU_SUBTYPE_SHX3)
 static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
@@ -284,7 +285,8 @@ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
 static inline int scif_txroom(struct uart_port *port)
 {
        return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
@@ -1095,6 +1097,7 @@ static void serial_console_write(struct console *co, const char *s,
                                 unsigned count)
 {
        struct uart_port *port = &serial_console_port->port;
+       unsigned short bits;
        int i;
 
        for (i = 0; i < count; i++) {
@@ -1103,6 +1106,11 @@ static void serial_console_write(struct console *co, const char *s,
 
                sci_poll_put_char(port, *s++);
        }
+
+       /* wait until fifo is empty and last bit has been transmitted */
+       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
+       while ((sci_in(port, SCxSR) & bits) != bits)
+               cpu_relax();
 }
 
 static int __init serial_console_setup(struct console *co, char *options)
index 022e89ffec1da4bc8da86bf6ba8471634f4fdaad..d0aa82d7fce0930e9016a929300966c7bf4aa9f5 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/serial_core.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 #if defined(CONFIG_H83007) || defined(CONFIG_H83068)
 #include <asm/regs306x.h>
 # define SCSPTR1       0xffe10024      /* 16 bit SCIF */
 # define SCIF_ORER     0x0001          /* Overrun error bit */
 # define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786)
 # define SCSPTR0       0xffea0024      /* 16 bit SCIF */
 # define SCSPTR1       0xffeb0024      /* 16 bit SCIF */
 # define SCSPTR2       0xffec0024      /* 16 bit SCIF */
     defined(CONFIG_CPU_SUBTYPE_SH7763)  || \
     defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)  || \
     defined(CONFIG_CPU_SUBTYPE_SHX3)
 #define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
 #else
@@ -413,7 +415,8 @@ SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
 SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
 SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
 SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
 SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
@@ -644,7 +647,8 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
        return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786)
 static inline int sci_rxd_in(struct uart_port *port)
 {
        if (port->mapbase == 0xffea0000)
@@ -746,7 +750,8 @@ static inline int sci_rxd_in(struct uart_port *port)
  */
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
       defined(CONFIG_CPU_SUBTYPE_SH7720) || \
index 45a299f35617bc8eb27bd8b0fef9c6256f2cdbf0..e09d3cebb4fb4d221b12b8b0b022a434ebaee7f4 100644 (file)
@@ -1438,12 +1438,12 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
        } else {
                printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
                       "is a %s\n",
-                      op->dev.bus_id,
+                      dev_name(&op->dev),
                       (unsigned long long) up[0].port.mapbase,
                       op->irqs[0], sunzilog_type(&up[0].port));
                printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
                       "is a %s\n",
-                      op->dev.bus_id,
+                      dev_name(&op->dev),
                       (unsigned long long) up[1].port.mapbase,
                       op->irqs[0], sunzilog_type(&up[1].port));
                kbm_inst++;
index 58d24c5a76cea5732d9a8b13cca5294dc95700a0..2269fbcaa1824c892ec91afa1409b96e37f7d03e 100644 (file)
@@ -568,6 +568,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
        if (!data[0] && data[1])
                primary = 1;
 
+       if (!data[0] && !data[1])
+               pr_warning("intc: missing unique irq mask for "
+                          "irq %d (vect 0x%04x)\n", irq, irq2evt(irq));
+
        data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
        data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
 
@@ -641,6 +645,17 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
        return 0;
 }
 
+static unsigned char *intc_evt2irq_table;
+
+unsigned int intc_evt2irq(unsigned int vector)
+{
+       unsigned int irq = evt2irq(vector);
+
+       if (intc_evt2irq_table && intc_evt2irq_table[irq])
+               irq = intc_evt2irq_table[irq];
+
+       return irq;
+}
 
 void __init register_intc_controller(struct intc_desc *desc)
 {
@@ -705,9 +720,41 @@ void __init register_intc_controller(struct intc_desc *desc)
 
        BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
 
+       /* keep the first vector only if same enum is used multiple times */
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+               int first_irq = evt2irq(vect->vect);
+
+               if (!vect->enum_id)
+                       continue;
+
+               for (k = i + 1; k < desc->nr_vectors; k++) {
+                       struct intc_vect *vect2 = desc->vectors + k;
+
+                       if (vect->enum_id != vect2->enum_id)
+                               continue;
+
+                       vect2->enum_id = 0;
+
+                       if (!intc_evt2irq_table)
+                               intc_evt2irq_table = alloc_bootmem(NR_IRQS);
+
+                       if (!intc_evt2irq_table) {
+                               pr_warning("intc: cannot allocate evt2irq!\n");
+                               continue;
+                       }
+
+                       intc_evt2irq_table[evt2irq(vect2->vect)] = first_irq;
+               }
+       }
+
+       /* register the vectors one by one */
        for (i = 0; i < desc->nr_vectors; i++) {
                struct intc_vect *vect = desc->vectors + i;
 
+               if (!vect->enum_id)
+                       continue;
+
                intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
        }
 }
index 63f0de29aa14eeb508645dd0b917e7c4163950c1..cab1ab7cfb789204f70924975fc78b94bafe802a 100644 (file)
@@ -1,16 +1,10 @@
 /*
  * Core maple bus functionality
  *
- *  Copyright (C) 2007, 2008 Adrian McMenamin
+ *  Copyright (C) 2007 - 2009 Adrian McMenamin
  *  Copyright (C) 2001 - 2008 Paul Mundt
- *
- * Based on 2.4 code by:
- *
- *  Copyright (C) 2000-2001 YAEGASHI Takeshi
+ *  Copyright (C) 2000 - 2001 YAEGASHI Takeshi
  *  Copyright (C) 2001 M. R. Brown
- *  Copyright (C) 2001 Paul Mundt
- *
- * and others.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -32,7 +26,7 @@
 #include <mach/dma.h>
 #include <mach/sysasic.h>
 
-MODULE_AUTHOR("Yaegashi Takeshi, Paul Mundt, M. R. Brown, Adrian McMenamin");
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
 MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
 MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
@@ -49,7 +43,7 @@ static LIST_HEAD(maple_sentq);
 /* mutex to protect queue of waiting packets */
 static DEFINE_MUTEX(maple_wlist_lock);
 
-static struct maple_driver maple_dummy_driver;
+static struct maple_driver maple_unsupported_device;
 static struct device maple_bus;
 static int subdevice_map[MAPLE_PORTS];
 static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
@@ -62,8 +56,9 @@ struct maple_device_specify {
        int unit;
 };
 
-static bool checked[4];
-static struct maple_device *baseunits[4];
+static bool checked[MAPLE_PORTS];
+static bool empty[MAPLE_PORTS];
+static struct maple_device *baseunits[MAPLE_PORTS];
 
 /**
  * maple_driver_register - register a maple driver
@@ -97,12 +92,20 @@ void maple_driver_unregister(struct maple_driver *drv)
 EXPORT_SYMBOL_GPL(maple_driver_unregister);
 
 /* set hardware registers to enable next round of dma */
-static void maplebus_dma_reset(void)
+static void maple_dma_reset(void)
 {
        ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
        /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
        ctrl_outl(1, MAPLE_TRIGTYPE);
-       ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);
+       /*
+       * Maple system register
+       * bits 31 - 16  timeout in units of 20nsec
+       * bit 12        hard trigger - set 0 to keep responding to VBLANK
+       * bits 9 - 8    set 00 for 2 Mbps, 01 for 1 Mbps
+       * bits 3 - 0    delay (in 1.3ms) between VBLANK and start of DMA
+       * max delay is 11
+       */
+       ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
        ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
        ctrl_outl(1, MAPLE_ENABLE);
 }
@@ -134,21 +137,16 @@ static void maple_release_device(struct device *dev)
 {
        struct maple_device *mdev;
        struct mapleq *mq;
-       if (!dev)
-               return;
+
        mdev = to_maple_dev(dev);
        mq = mdev->mq;
-       if (mq) {
-               if (mq->recvbufdcsp)
-                       kmem_cache_free(maple_queue_cache, mq->recvbufdcsp);
-               kfree(mq);
-               mq = NULL;
-       }
+       kmem_cache_free(maple_queue_cache, mq->recvbuf);
+       kfree(mq);
        kfree(mdev);
 }
 
 /**
- * maple_add_packet - add a single instruction to the queue
+ * maple_add_packet - add a single instruction to the maple bus queue
  * @mdev: maple device
  * @function: function on device being queried
  * @command: maple command to add
@@ -158,68 +156,12 @@ static void maple_release_device(struct device *dev)
 int maple_add_packet(struct maple_device *mdev, u32 function, u32 command,
        size_t length, void *data)
 {
-       int locking, ret = 0;
+       int ret = 0;
        void *sendbuf = NULL;
 
-       mutex_lock(&maple_wlist_lock);
-       /* bounce if device already locked */
-       locking = mutex_is_locked(&mdev->mq->mutex);
-       if (locking) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       mutex_lock(&mdev->mq->mutex);
-
        if (length) {
-               sendbuf = kmalloc(length * 4, GFP_KERNEL);
+               sendbuf = kzalloc(length * 4, GFP_KERNEL);
                if (!sendbuf) {
-                       mutex_unlock(&mdev->mq->mutex);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               ((__be32 *)sendbuf)[0] = cpu_to_be32(function);
-       }
-
-       mdev->mq->command = command;
-       mdev->mq->length = length;
-       if (length > 1)
-               memcpy(sendbuf + 4, data, (length - 1) * 4);
-       mdev->mq->sendbuf = sendbuf;
-
-       list_add(&mdev->mq->list, &maple_waitq);
-out:
-       mutex_unlock(&maple_wlist_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(maple_add_packet);
-
-/**
- * maple_add_packet_sleeps - add a single instruction to the queue
- * @mdev: maple device
- * @function: function on device being queried
- * @command: maple command to add
- * @length: length of command string (in 32 bit words)
- * @data: remainder of command string
- *
- * Same as maple_add_packet(), but waits for the lock to become free.
- */
-int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
-       u32 command, size_t length, void *data)
-{
-       int locking, ret = 0;
-       void *sendbuf = NULL;
-
-       locking = mutex_lock_interruptible(&mdev->mq->mutex);
-       if (locking) {
-               ret = -EIO;
-               goto out;
-       }
-
-       if (length) {
-               sendbuf = kmalloc(length * 4, GFP_KERNEL);
-               if (!sendbuf) {
-                       mutex_unlock(&mdev->mq->mutex);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -233,38 +175,35 @@ int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
        mdev->mq->sendbuf = sendbuf;
 
        mutex_lock(&maple_wlist_lock);
-       list_add(&mdev->mq->list, &maple_waitq);
+       list_add_tail(&mdev->mq->list, &maple_waitq);
        mutex_unlock(&maple_wlist_lock);
 out:
        return ret;
 }
-EXPORT_SYMBOL_GPL(maple_add_packet_sleeps);
+EXPORT_SYMBOL_GPL(maple_add_packet);
 
 static struct mapleq *maple_allocq(struct maple_device *mdev)
 {
        struct mapleq *mq;
 
-       mq = kmalloc(sizeof(*mq), GFP_KERNEL);
+       mq = kzalloc(sizeof(*mq), GFP_KERNEL);
        if (!mq)
                goto failed_nomem;
 
+       INIT_LIST_HEAD(&mq->list);
        mq->dev = mdev;
-       mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
-       mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
+       mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
        if (!mq->recvbuf)
                goto failed_p2;
-       /*
-        * most devices do not need the mutex - but
-        * anything that injects block reads or writes
-        * will rely on it
-        */
-       mutex_init(&mq->mutex);
+       mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]);
 
        return mq;
 
 failed_p2:
        kfree(mq);
 failed_nomem:
+       dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n",
+               mdev->port, mdev->unit);
        return NULL;
 }
 
@@ -272,12 +211,16 @@ static struct maple_device *maple_alloc_dev(int port, int unit)
 {
        struct maple_device *mdev;
 
+       /* zero this out to avoid kobj subsystem
+       * thinking it has already been registered */
+
        mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
        if (!mdev)
                return NULL;
 
        mdev->port = port;
        mdev->unit = unit;
+
        mdev->mq = maple_allocq(mdev);
 
        if (!mdev->mq) {
@@ -286,19 +229,14 @@ static struct maple_device *maple_alloc_dev(int port, int unit)
        }
        mdev->dev.bus = &maple_bus_type;
        mdev->dev.parent = &maple_bus;
+       init_waitqueue_head(&mdev->maple_wait);
        return mdev;
 }
 
 static void maple_free_dev(struct maple_device *mdev)
 {
-       if (!mdev)
-               return;
-       if (mdev->mq) {
-               if (mdev->mq->recvbufdcsp)
-                       kmem_cache_free(maple_queue_cache,
-                               mdev->mq->recvbufdcsp);
-               kfree(mdev->mq);
-       }
+       kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf);
+       kfree(mdev->mq);
        kfree(mdev);
 }
 
@@ -320,7 +258,7 @@ static void maple_build_block(struct mapleq *mq)
        maple_lastptr = maple_sendptr;
 
        *maple_sendptr++ = (port << 16) | len | 0x80000000;
-       *maple_sendptr++ = PHYSADDR(mq->recvbuf);
+       *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf);
        *maple_sendptr++ =
            mq->command | (to << 8) | (from << 16) | (len << 24);
        while (len-- > 0)
@@ -333,20 +271,28 @@ static void maple_send(void)
        int i, maple_packets = 0;
        struct mapleq *mq, *nmq;
 
-       if (!list_empty(&maple_sentq))
+       if (!maple_dma_done())
                return;
+
+       /* disable DMA */
+       ctrl_outl(0, MAPLE_ENABLE);
+
+       if (!list_empty(&maple_sentq))
+               goto finish;
+
        mutex_lock(&maple_wlist_lock);
-       if (list_empty(&maple_waitq) || !maple_dma_done()) {
+       if (list_empty(&maple_waitq)) {
                mutex_unlock(&maple_wlist_lock);
-               return;
+               goto finish;
        }
-       mutex_unlock(&maple_wlist_lock);
+
        maple_lastptr = maple_sendbuf;
        maple_sendptr = maple_sendbuf;
-       mutex_lock(&maple_wlist_lock);
+
        list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
                maple_build_block(mq);
-               list_move(&mq->list, &maple_sentq);
+               list_del_init(&mq->list);
+               list_add_tail(&mq->list, &maple_sentq);
                if (maple_packets++ > MAPLE_MAXPACKETS)
                        break;
        }
@@ -356,10 +302,13 @@ static void maple_send(void)
                        dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
                                       PAGE_SIZE, DMA_BIDIRECTIONAL);
        }
+
+finish:
+       maple_dma_reset();
 }
 
 /* check if there is a driver registered likely to match this device */
-static int check_matching_maple_driver(struct device_driver *driver,
+static int maple_check_matching_driver(struct device_driver *driver,
                                        void *devptr)
 {
        struct maple_driver *maple_drv;
@@ -374,10 +323,7 @@ static int check_matching_maple_driver(struct device_driver *driver,
 
 static void maple_detach_driver(struct maple_device *mdev)
 {
-       if (!mdev)
-               return;
        device_unregister(&mdev->dev);
-       mdev = NULL;
 }
 
 /* process initial MAPLE_COMMAND_DEVINFO for each device or port */
@@ -385,9 +331,9 @@ static void maple_attach_driver(struct maple_device *mdev)
 {
        char *p, *recvbuf;
        unsigned long function;
-       int matched, retval;
+       int matched, error;
 
-       recvbuf = mdev->mq->recvbuf;
+       recvbuf = mdev->mq->recvbuf->buf;
        /* copy the data as individual elements in
        * case of memory optimisation */
        memcpy(&mdev->devinfo.function, recvbuf + 4, 4);
@@ -395,7 +341,6 @@ static void maple_attach_driver(struct maple_device *mdev)
        memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1);
        memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1);
        memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30);
-       memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60);
        memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2);
        memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2);
        memcpy(mdev->product_name, mdev->devinfo.product_name, 30);
@@ -414,43 +359,39 @@ static void maple_attach_driver(struct maple_device *mdev)
                else
                        break;
 
-       printk(KERN_INFO "Maple device detected: %s\n",
-               mdev->product_name);
-       printk(KERN_INFO "Maple device: %s\n", mdev->product_licence);
-
        function = be32_to_cpu(mdev->devinfo.function);
 
+       dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n",
+               mdev->product_name, function, mdev->port, mdev->unit);
+
        if (function > 0x200) {
                /* Do this silently - as not a real device */
                function = 0;
-               mdev->driver = &maple_dummy_driver;
-               sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port);
+               mdev->driver = &maple_unsupported_device;
+               dev_set_name(&mdev->dev, "%d:0.port", mdev->port);
        } else {
-               printk(KERN_INFO
-                       "Maple bus at (%d, %d): Function 0x%lX\n",
-                       mdev->port, mdev->unit, function);
-
                matched =
                        bus_for_each_drv(&maple_bus_type, NULL, mdev,
-                               check_matching_maple_driver);
+                               maple_check_matching_driver);
 
                if (matched == 0) {
                        /* Driver does not exist yet */
-                       printk(KERN_INFO
-                               "No maple driver found.\n");
-                       mdev->driver = &maple_dummy_driver;
+                       dev_info(&mdev->dev, "no driver found\n");
+                       mdev->driver = &maple_unsupported_device;
                }
-               sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port,
-                       mdev->unit, function);
+               dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port,
+                            mdev->unit, function);
        }
+
        mdev->function = function;
        mdev->dev.release = &maple_release_device;
-       retval = device_register(&mdev->dev);
-       if (retval) {
-               printk(KERN_INFO
-               "Maple bus: Attempt to register device"
-               " (%x, %x) failed.\n",
-               mdev->port, mdev->unit);
+
+       atomic_set(&mdev->busy, 0);
+       error = device_register(&mdev->dev);
+       if (error) {
+               dev_warn(&mdev->dev, "could not register device at"
+                       " (%d, %d), with error 0x%X\n", mdev->unit,
+                       mdev->port, error);
                maple_free_dev(mdev);
                mdev = NULL;
                return;
@@ -462,7 +403,7 @@ static void maple_attach_driver(struct maple_device *mdev)
  * port and unit then return 1 - allows identification
  * of which devices need to be attached or detached
  */
-static int detach_maple_device(struct device *device, void *portptr)
+static int check_maple_device(struct device *device, void *portptr)
 {
        struct maple_device_specify *ds;
        struct maple_device *mdev;
@@ -477,21 +418,25 @@ static int detach_maple_device(struct device *device, void *portptr)
 static int setup_maple_commands(struct device *device, void *ignored)
 {
        int add;
-       struct maple_device *maple_dev = to_maple_dev(device);
-
-       if ((maple_dev->interval > 0)
-           && time_after(jiffies, maple_dev->when)) {
-               /* bounce if we cannot lock */
-               add = maple_add_packet(maple_dev,
-                       be32_to_cpu(maple_dev->devinfo.function),
+       struct maple_device *mdev = to_maple_dev(device);
+       if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 &&
+               time_after(jiffies, mdev->when)) {
+               /* bounce if we cannot add */
+               add = maple_add_packet(mdev,
+                       be32_to_cpu(mdev->devinfo.function),
                        MAPLE_COMMAND_GETCOND, 1, NULL);
                if (!add)
-                       maple_dev->when = jiffies + maple_dev->interval;
+                       mdev->when = jiffies + mdev->interval;
        } else {
                if (time_after(jiffies, maple_pnp_time))
-                       /* This will also bounce */
-                       maple_add_packet(maple_dev, 0,
-                               MAPLE_COMMAND_DEVINFO, 0, NULL);
+                       /* Ensure we don't have block reads and devinfo
+                       * calls interfering with one another - so flag the
+                       * device as busy */
+                       if (atomic_read(&mdev->busy) == 0) {
+                               atomic_set(&mdev->busy, 1);
+                               maple_add_packet(mdev, 0,
+                                       MAPLE_COMMAND_DEVINFO, 0, NULL);
+                       }
        }
        return 0;
 }
@@ -499,29 +444,50 @@ static int setup_maple_commands(struct device *device, void *ignored)
 /* VBLANK bottom half - implemented via workqueue */
 static void maple_vblank_handler(struct work_struct *work)
 {
-       if (!list_empty(&maple_sentq) || !maple_dma_done())
+       int x, locking;
+       struct maple_device *mdev;
+
+       if (!maple_dma_done())
                return;
 
        ctrl_outl(0, MAPLE_ENABLE);
 
+       if (!list_empty(&maple_sentq))
+               goto finish;
+
+       /*
+       * Set up essential commands - to fetch data and
+       * check devices are still present
+       */
        bus_for_each_dev(&maple_bus_type, NULL, NULL,
-                        setup_maple_commands);
+               setup_maple_commands);
+
+       if (time_after(jiffies, maple_pnp_time)) {
+               /*
+               * Scan the empty ports - bus is flakey and may have
+               * mis-reported emptyness
+               */
+               for (x = 0; x < MAPLE_PORTS; x++) {
+                       if (checked[x] && empty[x]) {
+                               mdev = baseunits[x];
+                               if (!mdev)
+                                       break;
+                               atomic_set(&mdev->busy, 1);
+                               locking = maple_add_packet(mdev, 0,
+                                       MAPLE_COMMAND_DEVINFO, 0, NULL);
+                               if (!locking)
+                                       break;
+                               }
+                       }
 
-       if (time_after(jiffies, maple_pnp_time))
                maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
-
-       mutex_lock(&maple_wlist_lock);
-       if (!list_empty(&maple_waitq) && list_empty(&maple_sentq)) {
-               mutex_unlock(&maple_wlist_lock);
-               maple_send();
-       } else {
-               mutex_unlock(&maple_wlist_lock);
        }
 
-       maplebus_dma_reset();
+finish:
+       maple_send();
 }
 
-/* handle devices added via hotplugs - placing them on queue for DEVINFO*/
+/* handle devices added via hotplugs - placing them on queue for DEVINFO */
 static void maple_map_subunits(struct maple_device *mdev, int submask)
 {
        int retval, k, devcheck;
@@ -533,7 +499,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask)
                ds.unit = k + 1;
                retval =
                    bus_for_each_dev(&maple_bus_type, NULL, &ds,
-                                    detach_maple_device);
+                                    check_maple_device);
                if (retval) {
                        submask = submask >> 1;
                        continue;
@@ -543,6 +509,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask)
                        mdev_add = maple_alloc_dev(mdev->port, k + 1);
                        if (!mdev_add)
                                return;
+                       atomic_set(&mdev_add->busy, 1);
                        maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO,
                                0, NULL);
                        /* mark that we are checking sub devices */
@@ -564,27 +531,45 @@ static void maple_clean_submap(struct maple_device *mdev)
 }
 
 /* handle empty port or hotplug removal */
-static void maple_response_none(struct maple_device *mdev,
-                               struct mapleq *mq)
-{
-       if (mdev->unit != 0) {
-               list_del(&mq->list);
-               maple_clean_submap(mdev);
-               printk(KERN_INFO
-                      "Maple bus device detaching at (%d, %d)\n",
-                      mdev->port, mdev->unit);
+static void maple_response_none(struct maple_device *mdev)
+{
+       maple_clean_submap(mdev);
+
+       if (likely(mdev->unit != 0)) {
+               /*
+               * Block devices play up
+               * and give the impression they have
+               * been removed even when still in place or
+               * trip the mtd layer when they have
+               * really gone - this code traps that eventuality
+               * and ensures we aren't overloaded with useless
+               * error messages
+               */
+               if (mdev->can_unload) {
+                       if (!mdev->can_unload(mdev)) {
+                               atomic_set(&mdev->busy, 2);
+                               wake_up(&mdev->maple_wait);
+                               return;
+                       }
+               }
+
+               dev_info(&mdev->dev, "detaching device at (%d, %d)\n",
+                       mdev->port, mdev->unit);
                maple_detach_driver(mdev);
                return;
-       }
-       if (!started || !fullscan) {
-               if (checked[mdev->port] == false) {
-                       checked[mdev->port] = true;
-                       printk(KERN_INFO "No maple devices attached"
-                               " to port %d\n", mdev->port);
+       } else {
+               if (!started || !fullscan) {
+                       if (checked[mdev->port] == false) {
+                               checked[mdev->port] = true;
+                               empty[mdev->port] = true;
+                               dev_info(&mdev->dev, "no devices"
+                                       " to port %d\n", mdev->port);
+                       }
+                       return;
                }
-               return;
        }
-       maple_clean_submap(mdev);
+       /* Some hardware devices generate false detach messages on unit 0 */
+       atomic_set(&mdev->busy, 0);
 }
 
 /* preprocess hotplugs or scans */
@@ -599,8 +584,11 @@ static void maple_response_devinfo(struct maple_device *mdev,
                } else {
                        if (mdev->unit != 0)
                                maple_attach_driver(mdev);
+                       if (mdev->unit == 0) {
+                               empty[mdev->port] = false;
+                               maple_attach_driver(mdev);
+                       }
                }
-               return;
        }
        if (mdev->unit == 0) {
                submask = recvbuf[2] & 0x1F;
@@ -611,6 +599,17 @@ static void maple_response_devinfo(struct maple_device *mdev,
        }
 }
 
+static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf)
+{
+       if (mdev->fileerr_handler) {
+               mdev->fileerr_handler(mdev, recvbuf);
+               return;
+       } else
+               dev_warn(&mdev->dev, "device at (%d, %d) reports"
+                       "file error 0x%X\n", mdev->port, mdev->unit,
+                       ((int *)recvbuf)[1]);
+}
+
 static void maple_port_rescan(void)
 {
        int i;
@@ -621,12 +620,6 @@ static void maple_port_rescan(void)
                if (checked[i] == false) {
                        fullscan = 0;
                        mdev = baseunits[i];
-                       /*
-                        *  test lock in case scan has failed
-                        *  but device is still locked
-                        */
-                       if (mutex_is_locked(&mdev->mq->mutex))
-                               mutex_unlock(&mdev->mq->mutex);
                        maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO,
                                0, NULL);
                }
@@ -637,7 +630,7 @@ static void maple_port_rescan(void)
 static void maple_dma_handler(struct work_struct *work)
 {
        struct mapleq *mq, *nmq;
-       struct maple_device *dev;
+       struct maple_device *mdev;
        char *recvbuf;
        enum maple_code code;
 
@@ -646,43 +639,56 @@ static void maple_dma_handler(struct work_struct *work)
        ctrl_outl(0, MAPLE_ENABLE);
        if (!list_empty(&maple_sentq)) {
                list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
-                       recvbuf = mq->recvbuf;
+                       mdev = mq->dev;
+                       recvbuf = mq->recvbuf->buf;
+                       dma_cache_sync(&mdev->dev, recvbuf, 0x400,
+                               DMA_FROM_DEVICE);
                        code = recvbuf[0];
-                       dev = mq->dev;
                        kfree(mq->sendbuf);
-                       mutex_unlock(&mq->mutex);
                        list_del_init(&mq->list);
-
                        switch (code) {
                        case MAPLE_RESPONSE_NONE:
-                               maple_response_none(dev, mq);
+                               maple_response_none(mdev);
                                break;
 
                        case MAPLE_RESPONSE_DEVINFO:
-                               maple_response_devinfo(dev, recvbuf);
+                               maple_response_devinfo(mdev, recvbuf);
+                               atomic_set(&mdev->busy, 0);
                                break;
 
                        case MAPLE_RESPONSE_DATATRF:
-                               if (dev->callback)
-                                       dev->callback(mq);
+                               if (mdev->callback)
+                                       mdev->callback(mq);
+                               atomic_set(&mdev->busy, 0);
+                               wake_up(&mdev->maple_wait);
                                break;
 
                        case MAPLE_RESPONSE_FILEERR:
+                               maple_response_fileerr(mdev, recvbuf);
+                               atomic_set(&mdev->busy, 0);
+                               wake_up(&mdev->maple_wait);
+                               break;
+
                        case MAPLE_RESPONSE_AGAIN:
                        case MAPLE_RESPONSE_BADCMD:
                        case MAPLE_RESPONSE_BADFUNC:
-                               printk(KERN_DEBUG
-                                      "Maple non-fatal error 0x%X\n",
-                                      code);
+                               dev_warn(&mdev->dev, "non-fatal error"
+                                       " 0x%X at (%d, %d)\n", code,
+                                       mdev->port, mdev->unit);
+                               atomic_set(&mdev->busy, 0);
                                break;
 
                        case MAPLE_RESPONSE_ALLINFO:
-                               printk(KERN_DEBUG
-                                      "Maple - extended device information"
-                                       " not supported\n");
+                               dev_notice(&mdev->dev, "extended"
+                               " device information request for (%d, %d)"
+                               " but call is not supported\n", mdev->port,
+                               mdev->unit);
+                               atomic_set(&mdev->busy, 0);
                                break;
 
                        case MAPLE_RESPONSE_OK:
+                               atomic_set(&mdev->busy, 0);
+                               wake_up(&mdev->maple_wait);
                                break;
 
                        default:
@@ -699,20 +705,19 @@ static void maple_dma_handler(struct work_struct *work)
                if (!fullscan)
                        maple_port_rescan();
                /* mark that we have been through the first scan */
-               if (started == 0)
-                       started = 1;
+               started = 1;
        }
-       maplebus_dma_reset();
+       maple_send();
 }
 
-static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id)
+static irqreturn_t maple_dma_interrupt(int irq, void *dev_id)
 {
        /* Load everything into the bottom half */
        schedule_work(&maple_dma_process);
        return IRQ_HANDLED;
 }
 
-static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
+static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id)
 {
        schedule_work(&maple_vblank_process);
        return IRQ_HANDLED;
@@ -720,14 +725,14 @@ static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
 
 static int maple_set_dma_interrupt_handler(void)
 {
-       return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt,
-               IRQF_SHARED, "maple bus DMA", &maple_dummy_driver);
+       return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt,
+               IRQF_SHARED, "maple bus DMA", &maple_unsupported_device);
 }
 
 static int maple_set_vblank_interrupt_handler(void)
 {
-       return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt,
-               IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver);
+       return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt,
+               IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device);
 }
 
 static int maple_get_dma_buffer(void)
@@ -740,7 +745,7 @@ static int maple_get_dma_buffer(void)
        return 0;
 }
 
-static int match_maple_bus_driver(struct device *devptr,
+static int maple_match_bus_driver(struct device *devptr,
                                  struct device_driver *drvptr)
 {
        struct maple_driver *maple_drv = to_maple_driver(drvptr);
@@ -765,22 +770,24 @@ static void maple_bus_release(struct device *dev)
 {
 }
 
-static struct maple_driver maple_dummy_driver = {
+static struct maple_driver maple_unsupported_device = {
        .drv = {
-               .name = "maple_dummy_driver",
+               .name = "maple_unsupported_device",
                .bus = &maple_bus_type,
        },
 };
-
+/**
+ * maple_bus_type - core maple bus structure
+ */
 struct bus_type maple_bus_type = {
        .name = "maple",
-       .match = match_maple_bus_driver,
+       .match = maple_match_bus_driver,
        .uevent = maple_bus_uevent,
 };
 EXPORT_SYMBOL_GPL(maple_bus_type);
 
 static struct device maple_bus = {
-       .bus_id = "maple",
+       .init_name = "maple",
        .release = maple_bus_release,
 };
 
@@ -788,7 +795,8 @@ static int __init maple_bus_init(void)
 {
        int retval, i;
        struct maple_device *mdev[MAPLE_PORTS];
-       ctrl_outl(0, MAPLE_STATE);
+
+       ctrl_outl(0, MAPLE_ENABLE);
 
        retval = device_register(&maple_bus);
        if (retval)
@@ -798,36 +806,33 @@ static int __init maple_bus_init(void)
        if (retval)
                goto cleanup_device;
 
-       retval = driver_register(&maple_dummy_driver.drv);
+       retval = driver_register(&maple_unsupported_device.drv);
        if (retval)
                goto cleanup_bus;
 
        /* allocate memory for maple bus dma */
        retval = maple_get_dma_buffer();
        if (retval) {
-               printk(KERN_INFO
-                      "Maple bus: Failed to allocate Maple DMA buffers\n");
+               dev_err(&maple_bus, "failed to allocate DMA buffers\n");
                goto cleanup_basic;
        }
 
        /* set up DMA interrupt handler */
        retval = maple_set_dma_interrupt_handler();
        if (retval) {
-               printk(KERN_INFO
-                      "Maple bus: Failed to grab maple DMA IRQ\n");
+               dev_err(&maple_bus, "bus failed to grab maple "
+                       "DMA IRQ\n");
                goto cleanup_dma;
        }
 
        /* set up VBLANK interrupt handler */
        retval = maple_set_vblank_interrupt_handler();
        if (retval) {
-               printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n");
+               dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n");
                goto cleanup_irq;
        }
 
-       maple_queue_cache =
-           kmem_cache_create("maple_queue_cache", 0x400, 0,
-                             SLAB_HWCACHE_ALIGN, NULL);
+       maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN);
 
        if (!maple_queue_cache)
                goto cleanup_bothirqs;
@@ -838,23 +843,23 @@ static int __init maple_bus_init(void)
        /* setup maple ports */
        for (i = 0; i < MAPLE_PORTS; i++) {
                checked[i] = false;
+               empty[i] = false;
                mdev[i] = maple_alloc_dev(i, 0);
-               baseunits[i] = mdev[i];
                if (!mdev[i]) {
                        while (i-- > 0)
                                maple_free_dev(mdev[i]);
                        goto cleanup_cache;
                }
+               baseunits[i] = mdev[i];
+               atomic_set(&mdev[i]->busy, 1);
                maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
                subdevice_map[i] = 0;
        }
 
-       /* setup maplebus hardware */
-       maplebus_dma_reset();
-       /* initial detection */
+       maple_pnp_time = jiffies + HZ;
+       /* prepare initial queue */
        maple_send();
-       maple_pnp_time = jiffies;
-       printk(KERN_INFO "Maple bus core now registered.\n");
+       dev_info(&maple_bus, "bus core now registered\n");
 
        return 0;
 
@@ -871,7 +876,7 @@ cleanup_dma:
        free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
 
 cleanup_basic:
-       driver_unregister(&maple_dummy_driver.drv);
+       driver_unregister(&maple_unsupported_device.drv);
 
 cleanup_bus:
        bus_unregister(&maple_bus_type);
@@ -880,7 +885,7 @@ cleanup_device:
        device_unregister(&maple_bus);
 
 cleanup:
-       printk(KERN_INFO "Maple bus registration failed\n");
+       printk(KERN_ERR "Maple bus registration failed\n");
        return retval;
 }
 /* Push init to later to ensure hardware gets detected */
index 4d0282b821b519b3bd750cd5266ea9a02b78cd26..2d9e7f3d56115aeaddea8eb250008dba7729d98e 100644 (file)
@@ -22,7 +22,7 @@
 static int superhyway_devices;
 
 static struct device superhyway_bus_device = {
-       .bus_id = "superhyway",
+       .init_name = "superhyway",
 };
 
 static void superhyway_device_release(struct device *dev)
@@ -83,7 +83,7 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
        dev->id.id              = dev->vcr.mod_id;
 
        sprintf(dev->name, "SuperHyway device %04x", dev->id.id);
-       sprintf(dev->dev.bus_id, "%02x", superhyway_devices);
+       dev_set_name(&dev->dev, "%02x", superhyway_devices);
 
        superhyway_devices++;
 
index 56ff3e6864ea748cc88be68621f0ea1239efa10d..12e443cc4ac93987bd3629ed9a5e7fcaf115372d 100644 (file)
@@ -322,7 +322,7 @@ static void atmel_spi_next_message(struct spi_master *master)
        spi = msg->spi;
 
        dev_dbg(master->dev.parent, "start message %p for %s\n",
-                       msg, spi->dev.bus_id);
+                       msg, dev_name(&spi->dev));
 
        /* select chip if it's not still active */
        if (as->stay) {
@@ -627,7 +627,7 @@ static int atmel_spi_setup(struct spi_device *spi)
                if (!asd)
                        return -ENOMEM;
 
-               ret = gpio_request(npcs_pin, spi->dev.bus_id);
+               ret = gpio_request(npcs_pin, dev_name(&spi->dev));
                if (ret) {
                        kfree(asd);
                        return ret;
@@ -668,7 +668,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
        as = spi_master_get_devdata(spi->master);
 
        dev_dbg(controller, "new message %p submitted for %s\n",
-                       msg, spi->dev.bus_id);
+                       msg, dev_name(&spi->dev));
 
        if (unlikely(list_empty(&msg->transfers)))
                return -EINVAL;
@@ -803,7 +803,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
        as->clk = clk;
 
        ret = request_irq(irq, atmel_spi_interrupt, 0,
-                       pdev->dev.bus_id, master);
+                       dev_name(&pdev->dev), master);
        if (ret)
                goto out_unmap_regs;
 
index 3b97803e1d11b0f4114e1104bbfd93c76c932eab..68c77a9115956cad8e57eb92bde8a1a03ae68a3d 100644 (file)
@@ -429,7 +429,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
        INIT_LIST_HEAD(&mps->queue);
 
        mps->workqueue = create_singlethread_workqueue(
-               master->dev.parent->bus_id);
+               dev_name(master->dev.parent));
        if (mps->workqueue == NULL) {
                ret = -EBUSY;
                goto free_irq;
index 454a2712e6290ee0f0f085667a0baec9ec6bb027..1c65e380c845efc6e8f612ae3825f60708f60a49 100644 (file)
@@ -1003,7 +1003,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                goto err1;
        }
        if (!request_mem_region(r->start, (r->end - r->start) + 1,
-                       pdev->dev.bus_id)) {
+                       dev_name(&pdev->dev))) {
                status = -EBUSY;
                goto err1;
        }
index bab6ff061e9145a95dad6756d6cbc4b25e69e671..60b5381c65c46008b5245a9c01255cf419699aed 100644 (file)
@@ -245,7 +245,7 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
 
 #ifdef VERBOSE
                        pr_debug("%s: write-%d =%04x\n",
-                                       spi->dev.bus_id, bits, val);
+                                       dev_name(&spi->dev), bits, val);
 #endif
                        if (wait_uwire_csr_flag(CSRB, 0, 0))
                                goto eio;
@@ -305,7 +305,7 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
                        status += bytes;
 #ifdef VERBOSE
                        pr_debug("%s: read-%d =%04x\n",
-                                       spi->dev.bus_id, bits, val);
+                                       dev_name(&spi->dev), bits, val);
 #endif
 
                }
@@ -331,7 +331,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        uwire = spi_master_get_devdata(spi->master);
 
        if (spi->chip_select > 3) {
-               pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select);
+               pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
                status = -ENODEV;
                goto done;
        }
@@ -343,7 +343,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                bits = 8;
 
        if (bits > 16) {
-               pr_debug("%s: wordsize %d?\n", spi->dev.bus_id, bits);
+               pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
                status = -ENODEV;
                goto done;
        }
@@ -378,7 +378,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                hz = t->speed_hz;
 
        if (!hz) {
-               pr_debug("%s: zero speed?\n", spi->dev.bus_id);
+               pr_debug("%s: zero speed?\n", dev_name(&spi->dev));
                status = -EINVAL;
                goto done;
        }
@@ -406,7 +406,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        }
        if (div1_idx == 4) {
                pr_debug("%s: lowest clock %ld, need %d\n",
-                       spi->dev.bus_id, rate / 10 / 8, hz);
+                       dev_name(&spi->dev), rate / 10 / 8, hz);
                status = -EDOM;
                goto done;
        }
index 014becb7d53007b20099b9b9c84d0eb09d19e5dc..c8b0babdc2a6f346466cf90a9eed21e261be6e68 100644 (file)
@@ -496,7 +496,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
        }
 
        if (!request_mem_region(r->start, (r->end - r->start) + 1,
-                               pdev->dev.bus_id)) {
+                               dev_name(&pdev->dev))) {
                status = -EBUSY;
                goto out;
        }
index d0fc4ca2f656abb56d263284bde5a311ff2e6acd..ec24f2d16f3cd33d279bda35382ecdf075ccdeb7 100644 (file)
@@ -1333,7 +1333,7 @@ static int __init init_queue(struct driver_data *drv_data)
 
        INIT_WORK(&drv_data->pump_messages, pump_messages);
        drv_data->workqueue = create_singlethread_workqueue(
-                                       drv_data->master->dev.parent->bus_id);
+                               dev_name(drv_data->master->dev.parent));
        if (drv_data->workqueue == NULL)
                return -EBUSY;
 
@@ -1462,7 +1462,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
                drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
        }
 
-       status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
+       status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data);
        if (status < 0) {
                dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
                goto out_error_master_alloc;
index 7fea3cf4588a37fa89589c8931862e704a62f156..3410b0c55ed2a8562713c376bc38fbfc8b711e54 100644 (file)
@@ -1160,8 +1160,8 @@ static inline int init_queue(struct driver_data *drv_data)
 
        /* init messages workqueue */
        INIT_WORK(&drv_data->pump_messages, pump_messages);
-       drv_data->workqueue =
-           create_singlethread_workqueue(drv_data->master->dev.parent->bus_id);
+       drv_data->workqueue = create_singlethread_workqueue(
+                               dev_name(drv_data->master->dev.parent));
        if (drv_data->workqueue == NULL)
                return -EBUSY;
 
index f5ed9721aabb33c24c9a75c79d58df19e595450f..d2866c293dee0a5f160e5342755ffc8be525f351 100644 (file)
@@ -191,7 +191,7 @@ static int spi_gpio_setup(struct spi_device *spi)
                return -EINVAL;
 
        if (!spi->controller_state) {
-               status = gpio_request(cs, spi->dev.bus_id);
+               status = gpio_request(cs, dev_name(&spi->dev));
                if (status)
                        return status;
                status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
index 269a55ec52ef0e617caff931c448056cc991c32a..0480d8bb19d32b7a6d81b2b43efafc2a7fe8defd 100644 (file)
@@ -1381,7 +1381,7 @@ static int __init init_queue(struct driver_data *drv_data)
 
        INIT_WORK(&drv_data->work, pump_messages);
        drv_data->workqueue = create_singlethread_workqueue(
-                                       drv_data->master->dev.parent->bus_id);
+                               dev_name(drv_data->master->dev.parent));
        if (drv_data->workqueue == NULL)
                return -EBUSY;
 
@@ -1525,7 +1525,8 @@ static int __init spi_imx_probe(struct platform_device *pdev)
                status = -ENODEV;
                goto err_no_irqres;
        }
-       status = request_irq(irq, spi_int, IRQF_DISABLED, dev->bus_id, drv_data);
+       status = request_irq(irq, spi_int, IRQF_DISABLED,
+                            dev_name(dev), drv_data);
        if (status < 0) {
                dev_err(&pdev->dev, "probe - cannot get IRQ (%d)\n", status);
                goto err_no_irqres;
index ac0e3e4b3c543e480028d90829c7f5606b7fde71..44a2b46ccb795e8d6dd8ccef2f43dcad482d5ef1 100644 (file)
@@ -637,7 +637,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
        INIT_LIST_HEAD(&mpc83xx_spi->queue);
 
        mpc83xx_spi->workqueue = create_singlethread_workqueue(
-               master->dev.parent->bus_id);
+               dev_name(master->dev.parent));
        if (mpc83xx_spi->workqueue == NULL) {
                ret = -EBUSY;
                goto free_irq;
@@ -649,7 +649,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
 
        printk(KERN_INFO
               "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
-              dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
+              dev_name(&dev->dev), mpc83xx_spi->base, mpc83xx_spi->irq);
 
        return ret;
 
index 2296f37ea3c636613a20dc422285093d02ddf52a..29cbb065618a048cdffdffd6cedd4ccee1232106 100644 (file)
@@ -404,7 +404,8 @@ static int __init txx9spi_probe(struct platform_device *dev)
        if (ret)
                goto exit;
 
-       c->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
+       c->workqueue = create_singlethread_workqueue(
+                               dev_name(master->dev.parent));
        if (!c->workqueue)
                goto exit_busy;
        c->last_chipselect = -1;
index a7de401f61ab22d1636939ba87ba939ad1f15654..cd19be6c00e09fa1f0256c3657f81989f1f1e4fe 100644 (file)
@@ -248,10 +248,11 @@ int go7007_snd_init(struct go7007 *go)
        spin_lock_init(&gosnd->lock);
        gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
        gosnd->capturing = 0;
-       gosnd->card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (gosnd->card == NULL) {
+       ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
+                             &gosnd->card);
+       if (ret < 0) {
                kfree(gosnd);
-               return -ENOMEM;
+               return ret;
        }
        ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
                        &go7007_snd_device_ops);
index f77f62a4b325d3bb3c898efe42d397a17238114a..e5bd4470a570a4d45fcd7ef97d6a93c0a90aa601 100644 (file)
@@ -86,7 +86,7 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus)
                               slot);
                        goto out_err;
                }
-               sprintf(tdev->dev.bus_id, "tc%x", slot);
+               dev_set_name(&tdev->dev, "tc%x", slot);
                tdev->bus = tbus;
                tdev->dev.parent = &tbus->dev;
                tdev->dev.bus = &tc_bus_type;
@@ -104,7 +104,7 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus)
                tdev->vendor[8] = 0;
                tdev->name[8] = 0;
 
-               pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
+               pr_info("%s: %s %s %s\n", dev_name(&tdev->dev), tdev->vendor,
                        tdev->name, tdev->firmware);
 
                devsize = readb(module + offset + TC_SLOT_SIZE);
@@ -118,7 +118,7 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus)
                } else {
                        printk(KERN_ERR "%s: Cannot provide slot space "
                               "(%dMiB required, up to %dMiB supported)\n",
-                              tdev->dev.bus_id, devsize >> 20,
+                              dev_name(&tdev->dev), devsize >> 20,
                               max(slotsize, extslotsize) >> 20);
                        kfree(tdev);
                        goto out_err;
@@ -146,7 +146,7 @@ static int __init tc_init(void)
                return 0;
 
        INIT_LIST_HEAD(&tc_bus.devices);
-       strcpy(tc_bus.dev.bus_id, "tc");
+       dev_set_name(&tc_bus.dev, "tc");
        device_register(&tc_bus.dev);
 
        if (tc_bus.info.slot_size) {
index 04b954cfce7608827a821138df74db9caccb9f80..7f86534de26970ef785b2b02066ff7e1c2bba19f 100644 (file)
@@ -58,6 +58,24 @@ config UIO_SMX
 
          If you compile this as a module, it will be called uio_smx.
 
+config UIO_AEC
+       tristate "AEC video timestamp device"
+       depends on PCI
+       default n
+       help
+
+         UIO driver for the Adrienne Electronics Corporation PCI time
+         code device.
+
+         This device differs from other UIO devices since it uses I/O
+         ports instead of memory mapped I/O. In order to make it
+         possible for UIO to work with this device a utility, uioport,
+         can be used to read and write the ports:
+
+           git clone git://ifup.org/philips/uioport.git
+
+         If you compile this as a module, it will be called uio_aec.
+
 config UIO_SERCOS3
        tristate "Automata Sercos III PCI card driver"
        default n
index e69558149859f0dd36b1d0433190d6e06773aafa..5c2586d75797685e8bb4aebeeee8a6d08ce2db8b 100644 (file)
@@ -3,4 +3,5 @@ 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
index 4ca85a113aa251e03387da5402e6a9d65a43a421..03efb065455fa6ef1e9db0d091db9bcad1960e12 100644 (file)
@@ -61,6 +61,14 @@ struct uio_map {
 };
 #define to_map(map) container_of(map, struct uio_map, kobj)
 
+static ssize_t map_name_show(struct uio_mem *mem, char *buf)
+{
+       if (unlikely(!mem->name))
+               mem->name = "";
+
+       return sprintf(buf, "%s\n", mem->name);
+}
+
 static ssize_t map_addr_show(struct uio_mem *mem, char *buf)
 {
        return sprintf(buf, "0x%lx\n", mem->addr);
@@ -82,6 +90,8 @@ struct map_sysfs_entry {
        ssize_t (*store)(struct uio_mem *, const char *, size_t);
 };
 
+static struct map_sysfs_entry name_attribute =
+       __ATTR(name, S_IRUGO, map_name_show, NULL);
 static struct map_sysfs_entry addr_attribute =
        __ATTR(addr, S_IRUGO, map_addr_show, NULL);
 static struct map_sysfs_entry size_attribute =
@@ -90,6 +100,7 @@ static struct map_sysfs_entry offset_attribute =
        __ATTR(offset, S_IRUGO, map_offset_show, NULL);
 
 static struct attribute *attrs[] = {
+       &name_attribute.attr,
        &addr_attribute.attr,
        &size_attribute.attr,
        &offset_attribute.attr,
@@ -133,6 +144,14 @@ struct uio_portio {
 };
 #define to_portio(portio) container_of(portio, struct uio_portio, kobj)
 
+static ssize_t portio_name_show(struct uio_port *port, char *buf)
+{
+       if (unlikely(!port->name))
+               port->name = "";
+
+       return sprintf(buf, "%s\n", port->name);
+}
+
 static ssize_t portio_start_show(struct uio_port *port, char *buf)
 {
        return sprintf(buf, "0x%lx\n", port->start);
@@ -159,6 +178,8 @@ struct portio_sysfs_entry {
        ssize_t (*store)(struct uio_port *, const char *, size_t);
 };
 
+static struct portio_sysfs_entry portio_name_attribute =
+       __ATTR(name, S_IRUGO, portio_name_show, NULL);
 static struct portio_sysfs_entry portio_start_attribute =
        __ATTR(start, S_IRUGO, portio_start_show, NULL);
 static struct portio_sysfs_entry portio_size_attribute =
@@ -167,6 +188,7 @@ static struct portio_sysfs_entry portio_porttype_attribute =
        __ATTR(porttype, S_IRUGO, portio_porttype_show, NULL);
 
 static struct attribute *portio_attrs[] = {
+       &portio_name_attribute.attr,
        &portio_start_attribute.attr,
        &portio_size_attribute.attr,
        &portio_porttype_attribute.attr,
@@ -686,7 +708,8 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
                return -EINVAL;
 
        requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-       actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+       actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK)
+                       + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
        if (requested_pages > actual_pages)
                return -EINVAL;
 
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c
new file mode 100644 (file)
index 0000000..b7830e9
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * uio_aec.c -- simple driver for Adrienne Electronics Corp time code PCI device
+ *
+ * Copyright (C) 2008 Brandon Philips <brandon@ifup.org>
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License version 2 as published
+ *   by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc., 59
+ *   Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_AEC 0xaecb
+#define PCI_DEVICE_ID_AEC_VITCLTC 0x6250
+
+#define INT_ENABLE_ADDR                0xFC
+#define INT_ENABLE             0x10
+#define INT_DISABLE            0x0
+
+#define INT_MASK_ADDR          0x2E
+#define INT_MASK_ALL           0x3F
+
+#define INTA_DRVR_ADDR         0xFE
+#define INTA_ENABLED_FLAG      0x08
+#define INTA_FLAG              0x01
+
+#define MAILBOX                        0x0F
+
+static struct pci_device_id ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AEC, PCI_DEVICE_ID_AEC_VITCLTC), },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ids);
+
+static irqreturn_t aectc_irq(int irq, struct uio_info *dev_info)
+{
+       void __iomem *int_flag = dev_info->priv + INTA_DRVR_ADDR;
+       unsigned char status = ioread8(int_flag);
+
+
+       if ((status & INTA_ENABLED_FLAG) && (status & INTA_FLAG)) {
+               /* application writes 0x00 to 0x2F to get next interrupt */
+               status = ioread8(dev_info->priv + MAILBOX);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static void print_board_data(struct pci_dev *pdev, struct uio_info *i)
+{
+       dev_info(&pdev->dev, "PCI-TC board vendor: %x%x number: %x%x"
+               " revision: %c%c\n",
+               ioread8(i->priv + 0x01),
+               ioread8(i->priv + 0x00),
+               ioread8(i->priv + 0x03),
+               ioread8(i->priv + 0x02),
+               ioread8(i->priv + 0x06),
+               ioread8(i->priv + 0x07));
+}
+
+static int __devinit probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct uio_info *info;
+       int ret;
+
+       info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (pci_enable_device(pdev))
+               goto out_free;
+
+       if (pci_request_regions(pdev, "aectc"))
+               goto out_disable;
+
+       info->name = "aectc";
+       info->port[0].start = pci_resource_start(pdev, 0);
+       if (!info->port[0].start)
+               goto out_release;
+       info->priv = pci_iomap(pdev, 0, 0);
+       if (!info->priv)
+               goto out_release;
+       info->port[0].size = pci_resource_len(pdev, 0);
+       info->port[0].porttype = UIO_PORT_GPIO;
+
+       info->version = "0.0.1";
+       info->irq = pdev->irq;
+       info->irq_flags = IRQF_SHARED;
+       info->handler = aectc_irq;
+
+       print_board_data(pdev, info);
+       ret = uio_register_device(&pdev->dev, info);
+       if (ret)
+               goto out_unmap;
+
+       iowrite32(INT_ENABLE, info->priv + INT_ENABLE_ADDR);
+       iowrite8(INT_MASK_ALL, info->priv + INT_MASK_ADDR);
+       if (!(ioread8(info->priv + INTA_DRVR_ADDR)
+                       & INTA_ENABLED_FLAG))
+               dev_err(&pdev->dev, "aectc: interrupts not enabled\n");
+
+       pci_set_drvdata(pdev, info);
+
+       return 0;
+
+out_unmap:
+       pci_iounmap(pdev, info->priv);
+out_release:
+       pci_release_regions(pdev);
+out_disable:
+       pci_disable_device(pdev);
+out_free:
+       kfree(info);
+       return -ENODEV;
+}
+
+static void remove(struct pci_dev *pdev)
+{
+       struct uio_info *info = pci_get_drvdata(pdev);
+
+       /* disable interrupts */
+       iowrite8(INT_DISABLE, info->priv + INT_MASK_ADDR);
+       iowrite32(INT_DISABLE, info->priv + INT_ENABLE_ADDR);
+       /* read mailbox to ensure board drops irq */
+       ioread8(info->priv + MAILBOX);
+
+       uio_unregister_device(info);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       iounmap(info->priv);
+
+       kfree(info);
+}
+
+static struct pci_driver pci_driver = {
+       .name = "aectc",
+       .id_table = ids,
+       .probe = probe,
+       .remove = remove,
+};
+
+static int __init aectc_init(void)
+{
+       return pci_register_driver(&pci_driver);
+}
+
+static void __exit aectc_exit(void)
+{
+       pci_unregister_driver(&pci_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(aectc_init);
+module_exit(aectc_exit);
index 83babb0a1df7146a34208754b348d0621f5b3e7e..c6c816b7ecb5d30cacf1dbfe4ca1115df3553788 100644 (file)
@@ -47,6 +47,7 @@ config USB_ARCH_HAS_OHCI
        default y if CPU_SUBTYPE_SH7720
        default y if CPU_SUBTYPE_SH7721
        default y if CPU_SUBTYPE_SH7763
+       default y if CPU_SUBTYPE_SH7786
        # more:
        default PCI
 
index 0e310b9aa7af4c8654b2c1a9775c6fca9da74ab3..22c65960c42971c4d94bb3ff83bd09dbfa6cbd94 100644 (file)
@@ -2625,7 +2625,7 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
        INIT_LIST_HEAD(&udc->gadget.ep_list);
        udc->gadget.ep0 = NULL;
 
-       strcpy(udc->gadget.dev.bus_id, "gadget");
+       dev_set_name(&udc->gadget.dev, "gadget");
        udc->gadget.dev.dma_mask = dev->dma_mask;
        udc->gadget.dev.parent   = dev;
        udc->gadget.dev.release  = udc_release;
index bb738bc96d4a0aa7f777047f47b6415fcf8571de..b9312dc6e04151f60c4dea4dce27b36c74e3ae87 100644 (file)
@@ -1099,10 +1099,9 @@ static int gmidi_register_card(struct gmidi_device *dev)
                .dev_free = gmidi_snd_free,
        };
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (!card) {
-               ERROR(dev, "snd_card_new failed\n");
-               err = -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0) {
+               ERROR(dev, "snd_card_create failed\n");
                goto fail;
        }
        dev->card = card;
index 8d3c6a960988e06082adc3c81d74225455ed3cd5..168658b4b4e26d2bc7b2614cf5b8cb891a3614e5 100644 (file)
@@ -1232,8 +1232,8 @@ static struct imx_udc_struct controller = {
                .ep0            = &controller.imx_ep[0].ep,
                .name           = driver_name,
                .dev = {
-                        .bus_id        = "gadget",
-                },
+                       .init_name      = "gadget",
+               },
        },
 
        .imx_ep[0] = {
index 34e14edf390bd2d49df420ab80a3b1297aead67b..ea8a4255c5da25b29136da57b8849c7bdd3f4285 100644 (file)
@@ -108,7 +108,7 @@ void fhci_dfs_create(struct fhci_hcd *fhci)
 {
        struct device *dev = fhci_to_hcd(fhci)->self.controller;
 
-       fhci->dfs_root = debugfs_create_dir(dev->bus_id, NULL);
+       fhci->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
        if (!fhci->dfs_root) {
                WARN_ON(1);
                return;
index ba622cc8a9bafa4db356a029c9898a067e6bb95d..0951818ef93b8838651597b3acef7795a193eca3 100644 (file)
@@ -583,7 +583,7 @@ static int __devinit of_fhci_probe(struct of_device *ofdev,
        if (sprop && strcmp(sprop, "host"))
                return -ENODEV;
 
-       hcd = usb_create_hcd(&fhci_driver, dev, dev->bus_id);
+       hcd = usb_create_hcd(&fhci_driver, dev, dev_name(dev));
        if (!hcd) {
                dev_err(dev, "could not create hcd\n");
                return -ENOMEM;
@@ -650,7 +650,7 @@ static int __devinit of_fhci_probe(struct of_device *ofdev,
                        }
                }
 
-               ret = gpio_request(gpio, dev->bus_id);
+               ret = gpio_request(gpio, dev_name(dev));
                if (ret) {
                        dev_err(dev, "failed to request gpio %d", i);
                        goto err_gpios;
index d052955439c32628e920bce428c52e8683bf5e66..25db704f3a2aa8c7d60ae1c48eab54270abab45e 100644 (file)
@@ -1049,7 +1049,8 @@ MODULE_LICENSE ("GPL");
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7763)
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
 #include "ohci-sh.c"
 #define PLATFORM_DRIVER                ohci_hcd_sh_driver
 #endif
index 62bd4441b5e06c81fc9c4366916ecb3a2747f09e..378f27745a1db94e18e8fd3b70d0318c2e88b490 100644 (file)
@@ -457,7 +457,7 @@ static struct fb_ops au1100fb_ops =
 
 /* AU1100 LCD controller device driver */
 
-static int __init au1100fb_drv_probe(struct device *dev)
+static int __init au1100fb_drv_probe(struct platform_device *dev)
 {
        struct au1100fb_device *fbdev = NULL;
        struct resource *regs_res;
@@ -475,7 +475,7 @@ static int __init au1100fb_drv_probe(struct device *dev)
 
        fbdev->panel = &known_lcd_panels[drv_info.panel_idx];
 
-       dev_set_drvdata(dev, (void*)fbdev);
+       platform_set_drvdata(dev, (void *)fbdev);
 
        /* Allocate region for our registers and map them */
        if (!(regs_res = platform_get_resource(to_platform_device(dev),
@@ -583,19 +583,19 @@ failed:
                fb_dealloc_cmap(&fbdev->info.cmap);
        }
        kfree(fbdev);
-       dev_set_drvdata(dev, NULL);
+       platform_set_drvdata(dev, NULL);
 
        return 0;
 }
 
-int au1100fb_drv_remove(struct device *dev)
+int au1100fb_drv_remove(struct platform_device *dev)
 {
        struct au1100fb_device *fbdev = NULL;
 
        if (!dev)
                return -ENODEV;
 
-       fbdev = (struct au1100fb_device*) dev_get_drvdata(dev);
+       fbdev = (struct au1100fb_device *) platform_get_drvdata(dev);
 
 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
        au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
@@ -620,9 +620,9 @@ int au1100fb_drv_remove(struct device *dev)
 static u32 sys_clksrc;
 static struct au1100fb_regs fbregs;
 
-int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
+int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+       struct au1100fb_device *fbdev = platform_get_drvdata(dev);
 
        if (!fbdev)
                return 0;
@@ -641,9 +641,9 @@ int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
        return 0;
 }
 
-int au1100fb_drv_resume(struct device *dev)
+int au1100fb_drv_resume(struct platform_device *dev)
 {
-       struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+       struct au1100fb_device *fbdev = platform_get_drvdata(dev);
 
        if (!fbdev)
                return 0;
@@ -663,10 +663,11 @@ int au1100fb_drv_resume(struct device *dev)
 #define au1100fb_drv_resume NULL
 #endif
 
-static struct device_driver au1100fb_driver = {
-       .name           = "au1100-lcd",
-       .bus            = &platform_bus_type,
-
+static struct platform_driver au1100fb_driver = {
+       .driver = {
+               .name           = "au1100-lcd",
+               .owner          = THIS_MODULE,
+       },
        .probe          = au1100fb_drv_probe,
         .remove                = au1100fb_drv_remove,
        .suspend        = au1100fb_drv_suspend,
@@ -753,12 +754,12 @@ int __init au1100fb_init(void)
                return ret;
        }
 
-       return driver_register(&au1100fb_driver);
+       return platform_driver_register(&au1100fb_driver);
 }
 
 void __exit au1100fb_cleanup(void)
 {
-       driver_unregister(&au1100fb_driver);
+       platform_driver_unregister(&au1100fb_driver);
 
        kfree(drv_info.opt_mode);
 }
index 03e57ef88378cd03891402c0fc0b2f5f205bf0bc..0d96f1d2d4c5bd0d3d490becbc84a0c012d7e443 100644 (file)
@@ -1622,7 +1622,7 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 
 /* AU1200 LCD controller device driver */
 
-static int au1200fb_drv_probe(struct device *dev)
+static int au1200fb_drv_probe(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
        unsigned long page;
@@ -1645,7 +1645,7 @@ static int au1200fb_drv_probe(struct device *dev)
                /* Allocate the framebuffer to the maximum screen size */
                fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
 
-               fbdev->fb_mem = dma_alloc_noncoherent(dev,
+               fbdev->fb_mem = dma_alloc_noncoherent(&dev->dev,
                                PAGE_ALIGN(fbdev->fb_len),
                                &fbdev->fb_phys, GFP_KERNEL);
                if (!fbdev->fb_mem) {
@@ -1715,7 +1715,7 @@ failed:
        return ret;
 }
 
-static int au1200fb_drv_remove(struct device *dev)
+static int au1200fb_drv_remove(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
        int plane;
@@ -1733,7 +1733,8 @@ static int au1200fb_drv_remove(struct device *dev)
                /* Clean up all probe data */
                unregister_framebuffer(&fbdev->fb_info);
                if (fbdev->fb_mem)
-                       dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+                       dma_free_noncoherent(&dev->dev,
+                                       PAGE_ALIGN(fbdev->fb_len),
                                        fbdev->fb_mem, fbdev->fb_phys);
                if (fbdev->fb_info.cmap.len != 0)
                        fb_dealloc_cmap(&fbdev->fb_info.cmap);
@@ -1747,22 +1748,24 @@ static int au1200fb_drv_remove(struct device *dev)
 }
 
 #ifdef CONFIG_PM
-static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
+static int au1200fb_drv_suspend(struct platform_device *dev, u32 state)
 {
        /* TODO */
        return 0;
 }
 
-static int au1200fb_drv_resume(struct device *dev, u32 level)
+static int au1200fb_drv_resume(struct platform_device *dev)
 {
        /* TODO */
        return 0;
 }
 #endif /* CONFIG_PM */
 
-static struct device_driver au1200fb_driver = {
-       .name           = "au1200-lcd",
-       .bus            = &platform_bus_type,
+static struct platform_driver au1200fb_driver = {
+       .driver = {
+               .name           = "au1200-lcd",
+               .owner          = THIS_MODULE,
+       },
        .probe          = au1200fb_drv_probe,
        .remove         = au1200fb_drv_remove,
 #ifdef CONFIG_PM
@@ -1906,12 +1909,12 @@ static int __init au1200fb_init(void)
                printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
        #endif
 
-       return driver_register(&au1200fb_driver);
+       return platform_driver_register(&au1200fb_driver);
 }
 
 static void __exit au1200fb_cleanup(void)
 {
-       driver_unregister(&au1200fb_driver);
+       platform_driver_unregister(&au1200fb_driver);
 }
 
 module_init(au1200fb_init);
index 3a3f80f65219a77dcd1d8c855a8aa9bb09fcabd1..0573ec685a57ebc73156a2d4dcab8f3e177f9ae8 100644 (file)
@@ -151,7 +151,7 @@ static int __init pmagbafb_probe(struct device *dev)
 
        info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
        if (!info) {
-               printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
                return -ENOMEM;
        }
 
@@ -160,7 +160,7 @@ static int __init pmagbafb_probe(struct device *dev)
 
        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
                printk(KERN_ERR "%s: Cannot allocate color map\n",
-                      dev->bus_id);
+                      dev_name(dev));
                err = -ENOMEM;
                goto err_alloc;
        }
@@ -173,8 +173,9 @@ static int __init pmagbafb_probe(struct device *dev)
        /* Request the I/O MEM resource.  */
        start = tdev->resource.start;
        len = tdev->resource.end - start + 1;
-       if (!request_mem_region(start, len, dev->bus_id)) {
-               printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id);
+       if (!request_mem_region(start, len, dev_name(dev))) {
+               printk(KERN_ERR "%s: Cannot reserve FB region\n",
+                      dev_name(dev));
                err = -EBUSY;
                goto err_cmap;
        }
@@ -183,7 +184,7 @@ static int __init pmagbafb_probe(struct device *dev)
        info->fix.mmio_start = start;
        par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
        if (!par->mmio) {
-               printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
                err = -ENOMEM;
                goto err_resource;
        }
@@ -194,7 +195,7 @@ static int __init pmagbafb_probe(struct device *dev)
        info->screen_base = ioremap_nocache(info->fix.smem_start,
                                            info->fix.smem_len);
        if (!info->screen_base) {
-               printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
                err = -ENOMEM;
                goto err_mmio_map;
        }
@@ -205,14 +206,14 @@ static int __init pmagbafb_probe(struct device *dev)
        err = register_framebuffer(info);
        if (err < 0) {
                printk(KERN_ERR "%s: Cannot register framebuffer\n",
-                      dev->bus_id);
+                      dev_name(dev));
                goto err_smem_map;
        }
 
        get_device(dev);
 
        pr_info("fb%d: %s frame buffer device at %s\n",
-               info->node, info->fix.id, dev->bus_id);
+               info->node, info->fix.id, dev_name(dev));
 
        return 0;
 
index 9b80597241b0b592b4bed7bc35493e978b0fba16..98748723af9f88cf5e433de72889f69e6b0f7ef0 100644 (file)
@@ -258,7 +258,7 @@ static int __init pmagbbfb_probe(struct device *dev)
 
        info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
        if (!info) {
-               printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
                return -ENOMEM;
        }
 
@@ -267,7 +267,7 @@ static int __init pmagbbfb_probe(struct device *dev)
 
        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
                printk(KERN_ERR "%s: Cannot allocate color map\n",
-                      dev->bus_id);
+                      dev_name(dev));
                err = -ENOMEM;
                goto err_alloc;
        }
@@ -280,8 +280,9 @@ static int __init pmagbbfb_probe(struct device *dev)
        /* Request the I/O MEM resource.  */
        start = tdev->resource.start;
        len = tdev->resource.end - start + 1;
-       if (!request_mem_region(start, len, dev->bus_id)) {
-               printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id);
+       if (!request_mem_region(start, len, dev_name(dev))) {
+               printk(KERN_ERR "%s: Cannot reserve FB region\n",
+                      dev_name(dev));
                err = -EBUSY;
                goto err_cmap;
        }
@@ -290,7 +291,7 @@ static int __init pmagbbfb_probe(struct device *dev)
        info->fix.mmio_start = start;
        par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
        if (!par->mmio) {
-               printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
                err = -ENOMEM;
                goto err_resource;
        }
@@ -301,7 +302,7 @@ static int __init pmagbbfb_probe(struct device *dev)
        info->fix.smem_start = start + PMAGB_B_FBMEM;
        par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
        if (!par->smem) {
-               printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id);
+               printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
                err = -ENOMEM;
                goto err_mmio_map;
        }
@@ -316,7 +317,7 @@ static int __init pmagbbfb_probe(struct device *dev)
        err = register_framebuffer(info);
        if (err < 0) {
                printk(KERN_ERR "%s: Cannot register framebuffer\n",
-                      dev->bus_id);
+                      dev_name(dev));
                goto err_smem_map;
        }
 
@@ -328,7 +329,7 @@ static int __init pmagbbfb_probe(struct device *dev)
                 par->osc1 / 1000, par->osc1 % 1000);
 
        pr_info("fb%d: %s frame buffer device at %s\n",
-               info->node, info->fix.id, dev->bus_id);
+               info->node, info->fix.id, dev_name(dev));
        pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
                info->node, freq0, par->osc1 ? freq1 : "disabled",
                par->osc1 != 0);
index 87f826e4c958c8c19c5c6b8d9471f21c5481f0df..e00c1dff55de24316d905750619781960328968c 100644 (file)
@@ -1213,7 +1213,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        dev->core.driver_data = info;
 
        dev_info(info->device, "%s %s, using %u KiB of video memory\n",
-                dev_driver_string(info->dev), info->dev->bus_id,
+                dev_driver_string(info->dev), dev_name(info->dev),
                 info->fix.smem_len >> 10);
 
        task = kthread_run(ps3fbd, info, DEVICE_NAME);
index 0a0fd48a856696eee0e84a6b37b4368b56ba7c89..53f8f1100e81c671cc63c10814467dcb1e0275d9 100644 (file)
@@ -61,7 +61,7 @@
 #include <mach-dreamcast/mach/sysasic.h>
 #endif
 
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
 #include <linux/pagemap.h>
 #include <mach/dma.h>
 #include <asm/dma.h>
@@ -188,7 +188,7 @@ static unsigned int is_blanked = 0;         /* Is the screen blanked? */
 static unsigned long pvr2fb_map;
 #endif
 
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
 static unsigned int shdma = PVR2_CASCADE_CHAN;
 static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
 #endif
@@ -207,7 +207,7 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id);
 static int pvr2_init_cable(void);
 static int pvr2_get_param(const struct pvr2_params *p, const char *s,
                             int val, int size);
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
 static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
                            size_t count, loff_t *ppos);
 #endif
@@ -218,7 +218,7 @@ static struct fb_ops pvr2fb_ops = {
        .fb_blank       = pvr2fb_blank,
        .fb_check_var   = pvr2fb_check_var,
        .fb_set_par     = pvr2fb_set_par,
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
        .fb_write       = pvr2fb_write,
 #endif
        .fb_fillrect    = cfb_fillrect,
@@ -671,7 +671,7 @@ static int pvr2_init_cable(void)
        return cable_type;
 }
 
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
 static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
                            size_t count, loff_t *ppos)
 {
@@ -743,7 +743,7 @@ out_unmap:
 
        return ret;
 }
-#endif /* CONFIG_SH_DMA */
+#endif /* CONFIG_PVR2_DMA */
 
 /**
  * pvr2fb_common_init
@@ -893,7 +893,7 @@ static int __init pvr2fb_dc_init(void)
                return -EBUSY;
        }
 
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
        if (request_dma(pvr2dma, "pvr2") != 0) {
                free_irq(HW_EVENT_VSYNC, 0);
                return -EBUSY;
@@ -915,7 +915,7 @@ static void __exit pvr2fb_dc_exit(void)
        }
 
        free_irq(HW_EVENT_VSYNC, 0);
-#ifdef CONFIG_SH_DMA
+#ifdef CONFIG_PVR2_DMA
        free_dma(pvr2dma);
 #endif
 }
index 2c5d069e5f06bc0b0cc1461c4ed7d37d2ed3081d..92ea0ab44ce23cd141882dceed16889bc26a97b9 100644 (file)
@@ -33,6 +33,8 @@ struct sh_mobile_lcdc_chan {
        struct fb_info info;
        dma_addr_t dma_handle;
        struct fb_deferred_io defio;
+       unsigned long frame_end;
+       wait_queue_head_t frame_end_wait;
 };
 
 struct sh_mobile_lcdc_priv {
@@ -226,7 +228,10 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
        struct sh_mobile_lcdc_priv *priv = data;
+       struct sh_mobile_lcdc_chan *ch;
        unsigned long tmp;
+       int is_sub;
+       int k;
 
        /* acknowledge interrupt */
        tmp = lcdc_read(priv, _LDINTR);
@@ -234,8 +239,24 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
        tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
        lcdc_write(priv, _LDINTR, tmp);
 
-       /* disable clocks */
-       sh_mobile_lcdc_clk_off(priv);
+       /* figure out if this interrupt is for main or sub lcd */
+       is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+
+       /* wake up channel and disable clocks*/
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               ch = &priv->ch[k];
+
+               if (!ch->enabled)
+                       continue;
+
+               if (is_sub == lcdc_chan_is_sublcd(ch)) {
+                       ch->frame_end = 1;
+                       wake_up(&ch->frame_end_wait);
+
+                       sh_mobile_lcdc_clk_off(priv);
+               }
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -448,18 +469,27 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
        struct sh_mobile_lcdc_board_cfg *board_cfg;
        int k;
 
-       /* tell the board code to disable the panel */
+       /* clean up deferred io and ask board code to disable panel */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
-               board_cfg = &ch->cfg.board_cfg;
-               if (board_cfg->display_off)
-                       board_cfg->display_off(board_cfg->board_data);
 
-               /* cleanup deferred io if enabled */
+               /* deferred io mode:
+                * flush frame, and wait for frame end interrupt
+                * clean up deferred io and enable clock
+                */
                if (ch->info.fbdefio) {
+                       ch->frame_end = 0;
+                       schedule_delayed_work(&ch->info.deferred_work, 0);
+                       wait_event(ch->frame_end_wait, ch->frame_end);
                        fb_deferred_io_cleanup(&ch->info);
                        ch->info.fbdefio = NULL;
+                       sh_mobile_lcdc_clk_on(priv);
                }
+
+               board_cfg = &ch->cfg.board_cfg;
+               if (board_cfg->display_off)
+                       board_cfg->display_off(board_cfg->board_data);
+
        }
 
        /* stop the lcdc */
@@ -652,6 +682,26 @@ static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
        return 0;
 }
 
+static int sh_mobile_lcdc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
+       return 0;
+}
+
+static int sh_mobile_lcdc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
+}
+
+static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
+       .suspend = sh_mobile_lcdc_suspend,
+       .resume = sh_mobile_lcdc_resume,
+};
+
 static int sh_mobile_lcdc_remove(struct platform_device *pdev);
 
 static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -687,7 +737,7 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
        }
 
        error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
-                           pdev->dev.bus_id, priv);
+                           dev_name(&pdev->dev), priv);
        if (error) {
                dev_err(&pdev->dev, "unable to request irq\n");
                goto err1;
@@ -707,6 +757,7 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "unsupported interface type\n");
                        goto err1;
                }
+               init_waitqueue_head(&priv->ch[i].frame_end_wait);
 
                switch (pdata->ch[i].chan) {
                case LCDC_CHAN_MAINLCD:
@@ -860,6 +911,7 @@ static struct platform_driver sh_mobile_lcdc_driver = {
        .driver         = {
                .name           = "sh_mobile_lcdc_fb",
                .owner          = THIS_MODULE,
+               .pm             = &sh_mobile_lcdc_dev_pm_ops,
        },
        .probe          = sh_mobile_lcdc_probe,
        .remove         = sh_mobile_lcdc_remove,
index 7baf2dd12d5024f33b5e7af20f6288085e573b9c..a1eb0862255b2e4e51cffa93bf644a99d1ab7b9d 100644 (file)
@@ -751,7 +751,7 @@ static int __devinit tmiofb_probe(struct platform_device *dev)
        }
 
        retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
-                                       dev->dev.bus_id, info);
+                                       dev_name(&dev->dev), info);
 
        if (retval)
                goto err_request_irq;
index f1ae3729a19e2d85a2f78fa40f196bed75cca023..cce1982a1b58eb558b84187ae8e7743cc55b1d22 100644 (file)
@@ -59,8 +59,8 @@ static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long);
 static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *);
 static const struct resource *wdt_gpi_get_resource(struct platform_device *,
                                                const char *, unsigned int);
-static int __init wdt_gpi_probe(struct device *);
-static int __exit wdt_gpi_remove(struct device *);
+static int __init wdt_gpi_probe(struct platform_device *);
+static int __exit wdt_gpi_remove(struct platform_device *);
 
 
 static const char wdt_gpi_name[] = "wdt_gpi";
@@ -346,10 +346,9 @@ static const struct resource *wdt_gpi_get_resource(struct platform_device *pdv,
 }
 
 /* No hotplugging on the platform bus - use __init */
-static int __init wdt_gpi_probe(struct device *dev)
+static int __init wdt_gpi_probe(struct platform_device *pdv)
 {
        int res;
-       struct platform_device * const pdv = to_platform_device(dev);
        const struct resource
                * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS,
                                                  IORESOURCE_MEM),
@@ -374,7 +373,7 @@ static int __init wdt_gpi_probe(struct device *dev)
        return res;
 }
 
-static int __exit wdt_gpi_remove(struct device *dev)
+static int __exit wdt_gpi_remove(struct platform_device *dev)
 {
        int res;
 
@@ -387,15 +386,13 @@ static int __exit wdt_gpi_remove(struct device *dev)
 
 
 /* Device driver init & exit */
-static struct device_driver wdt_gpi_driver = {
-       .name           = (char *) wdt_gpi_name,
-       .bus            = &platform_bus_type,
-       .owner          = THIS_MODULE,
+static struct platform_driver wgt_gpi_driver = {
+       .driver = {
+               .name           = wdt_gpi_name,
+               .owner          = THIS_MODULE,
+       },
        .probe          = wdt_gpi_probe,
-       .remove         = __exit_p(wdt_gpi_remove),
-       .shutdown       = NULL,
-       .suspend        = NULL,
-       .resume         = NULL,
+       .remove         = __devexit_p(wdt_gpi_remove),
 };
 
 static int __init wdt_gpi_init_module(void)
@@ -403,12 +400,12 @@ static int __init wdt_gpi_init_module(void)
        atomic_set(&opencnt, 1);
        if (timeout > MAX_TIMEOUT_SECONDS)
                timeout = MAX_TIMEOUT_SECONDS;
-       return driver_register(&wdt_gpi_driver);
+       return platform_driver_register(&wdt_gpi_driver);
 }
 
 static void __exit wdt_gpi_cleanup_module(void)
 {
-       driver_unregister(&wdt_gpi_driver);
+       platform_driver_unregister(&wdt_gpi_driver);
 }
 
 module_init(wdt_gpi_init_module);
index a1585d6f6486e8e7165a87f4ca6811a7ec57f10c..d45fb34e2d2371f49b26bfd0f787ac0cb5ddf06b 100644 (file)
@@ -140,7 +140,7 @@ static int __init zorro_init(void)
 
     /* Initialize the Zorro bus */
     INIT_LIST_HEAD(&zorro_bus.devices);
-    strcpy(zorro_bus.dev.bus_id, "zorro");
+    dev_set_name(&zorro_bus.dev, "zorro");
     error = device_register(&zorro_bus.dev);
     if (error) {
        pr_err("Zorro: Error registering zorro_bus\n");
@@ -167,7 +167,7 @@ static int __init zorro_init(void)
        if (request_resource(zorro_find_parent_resource(z), &z->resource))
            pr_err("Zorro: Address space collision on device %s %pR\n",
                   z->name, &z->resource);
-       sprintf(z->dev.bus_id, "%02x", i);
+       dev_set_name(&z->dev, "%02x", i);
        z->dev.parent = &zorro_bus.dev;
        z->dev.bus = &zorro_bus_type;
        error = device_register(&z->dev);
index d0145ca27572890b958765c72795a2b291628c20..0949b43794a4896827dd70714d3b3b7b9a0ae6ed 100644 (file)
@@ -1402,6 +1402,7 @@ int compat_do_execve(char * filename,
        retval = mutex_lock_interruptible(&current->cred_exec_mutex);
        if (retval < 0)
                goto out_free;
+       current->in_execve = 1;
 
        retval = -ENOMEM;
        bprm->cred = prepare_exec_creds();
@@ -1454,6 +1455,7 @@ int compat_do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
        free_bprm(bprm);
@@ -1470,6 +1472,7 @@ out_file:
        }
 
 out_unlock:
+       current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
 
 out_free:
index 929b58004b7eace02d784a2a4fbba17fd02b0533..b9f1c144b7a1037b6eb6e449812f75e204b1fed2 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -45,6 +45,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/syscalls.h>
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
@@ -127,6 +128,9 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
                                 MAY_READ | MAY_EXEC | MAY_OPEN);
        if (error)
                goto exit;
+       error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN);
+       if (error)
+               goto exit;
 
        file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
        error = PTR_ERR(file);
@@ -672,6 +676,9 @@ struct file *open_exec(const char *name)
                goto out_path_put;
 
        err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN);
+       if (err)
+               goto out_path_put;
+       err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN);
        if (err)
                goto out_path_put;
 
@@ -1182,6 +1189,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
        struct linux_binfmt *fmt;
 
        retval = security_bprm_check(bprm);
+       if (retval)
+               return retval;
+       retval = ima_bprm_check(bprm);
        if (retval)
                return retval;
 
@@ -1284,6 +1294,7 @@ int do_execve(char * filename,
        retval = mutex_lock_interruptible(&current->cred_exec_mutex);
        if (retval < 0)
                goto out_free;
+       current->in_execve = 1;
 
        retval = -ENOMEM;
        bprm->cred = prepare_exec_creds();
@@ -1337,6 +1348,7 @@ int do_execve(char * filename,
                goto out;
 
        /* execve succeeded */
+       current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
        acct_update_integrals(current);
        free_bprm(bprm);
@@ -1355,6 +1367,7 @@ out_file:
        }
 
 out_unlock:
+       current->in_execve = 0;
        mutex_unlock(&current->cred_exec_mutex);
 
 out_free:
index bbeeac6efa1a85eca90bd59e85c620022502f3d7..da806aceae3f7c350c449821defb7647234c2840 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/eventpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/mount.h>
@@ -279,6 +280,7 @@ void __fput(struct file *file)
        if (file->f_op && file->f_op->release)
                file->f_op->release(inode, file);
        security_file_free(file);
+       ima_file_free(file);
        if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
                cdev_put(inode->i_cdev);
        fops_put(file->f_op);
index e563a6449811f2efd1c13206a2b69e87b17d81a5..3a981b7f64caf92ce0d48ddba427092e6c212055 100644 (file)
@@ -1,6 +1,10 @@
 config GFS2_FS
        tristate "GFS2 file system support"
        depends on EXPERIMENTAL && (64BIT || LBD)
+       select DLM if GFS2_FS_LOCKING_DLM
+       select CONFIGFS_FS if GFS2_FS_LOCKING_DLM
+       select SYSFS if GFS2_FS_LOCKING_DLM
+       select IP_SCTP if DLM_SCTP
        select FS_POSIX_ACL
        select CRC32
        help
@@ -18,17 +22,16 @@ config GFS2_FS
          the locking module below. Documentation and utilities for GFS2 can
          be found here: http://sources.redhat.com/cluster
 
-         The "nolock" lock module is now built in to GFS2 by default.
+         The "nolock" lock module is now built in to GFS2 by default. If
+         you want to use the DLM, be sure to enable HOTPLUG and IPv4/6
+         networking.
 
 config GFS2_FS_LOCKING_DLM
-       tristate "GFS2 DLM locking module"
-       depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n)
-       select IP_SCTP if DLM_SCTP
-       select CONFIGFS_FS
-       select DLM
+       bool "GFS2 DLM locking"
+       depends on (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && HOTPLUG
        help
          Multiple node locking module for GFS2
 
-         Most users of GFS2 will require this module. It provides the locking
+         Most users of GFS2 will require this. It provides the locking
          interface between GFS2 and the DLM, which is required to use GFS2
          in a cluster environment.
index c1b4ec6a96504d4f70d078b7022786a95819f4c3..a851ea4bdf70331a2b222f19dd7344d6f811e62e 100644 (file)
@@ -1,9 +1,9 @@
 obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
-       glops.o inode.o log.o lops.o locking.o main.o meta_io.o \
+       glops.o inode.o log.o lops.o main.o meta_io.o \
        mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
        ops_fstype.o ops_inode.o ops_super.o quota.o \
        recovery.o rgrp.o super.o sys.o trans.o util.o
 
-obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/
+gfs2-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
 
index e335dceb6a4ff3f631d51e9069e55aaae0adc382..43764f4fa763a148f8bd0b67ed69b8755fa070be 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/posix_acl.h>
 #include <linux/posix_acl_xattr.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index 11ffc56f1f819f0808fdbf9d081510478256ca08..3a5d3f883e10137938c10ec106aceccb3f4b6153 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index b7c8e5c70791b232f744bc047b3a6169634ffa07..aef4d0c067488ccb942065aab8b0c292e8947213 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
 #include <linux/vmalloc.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index f114ba2b3557b780dbcde834502da0abd39a3852..dee9b03e5b37a165c74a6f0791acc32cfffbf691 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
index 0d1c76d906aef7796b2e19bc565dde74391399ce..899763aed217498f827ed7743a4ad04c14f95b57 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/buffer_head.h>
 #include <linux/xattr.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
index 6b983aef785d6970b5eb6f1e8e75c539e250801c..3984e47d1d334dbb6112e3e2f99a91c76f55daa1 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/delay.h>
 #include <linux/sort.h>
@@ -18,7 +17,6 @@
 #include <linux/kallsyms.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/list.h>
-#include <linux/lm_interface.h>
 #include <linux/wait.h>
 #include <linux/module.h>
 #include <linux/rwsem.h>
@@ -155,13 +153,10 @@ static void glock_free(struct gfs2_glock *gl)
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct inode *aspace = gl->gl_aspace;
 
-       if (sdp->sd_lockstruct.ls_ops->lm_put_lock)
-               sdp->sd_lockstruct.ls_ops->lm_put_lock(gl->gl_lock);
-
        if (aspace)
                gfs2_aspace_put(aspace);
 
-       kmem_cache_free(gfs2_glock_cachep, gl);
+       sdp->sd_lockstruct.ls_ops->lm_put_lock(gfs2_glock_cachep, gl);
 }
 
 /**
@@ -172,6 +167,7 @@ static void glock_free(struct gfs2_glock *gl)
 
 static void gfs2_glock_hold(struct gfs2_glock *gl)
 {
+       GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0);
        atomic_inc(&gl->gl_ref);
 }
 
@@ -211,17 +207,15 @@ int gfs2_glock_put(struct gfs2_glock *gl)
                        atomic_dec(&lru_count);
                }
                spin_unlock(&lru_lock);
-               GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_UNLOCKED);
-               GLOCK_BUG_ON(gl, !list_empty(&gl->gl_lru));
                GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
                glock_free(gl);
                rv = 1;
                goto out;
        }
-       write_unlock(gl_lock_addr(gl->gl_hash));
        /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */
        if (atomic_read(&gl->gl_ref) == 2)
                gfs2_glock_schedule_for_reclaim(gl);
+       write_unlock(gl_lock_addr(gl->gl_hash));
 out:
        return rv;
 }
@@ -255,27 +249,6 @@ static struct gfs2_glock *search_bucket(unsigned int hash,
        return NULL;
 }
 
-/**
- * gfs2_glock_find() - Find glock by lock number
- * @sdp: The GFS2 superblock
- * @name: The lock name
- *
- * Returns: NULL, or the struct gfs2_glock with the requested number
- */
-
-static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
-                                         const struct lm_lockname *name)
-{
-       unsigned int hash = gl_hash(sdp, name);
-       struct gfs2_glock *gl;
-
-       read_lock(gl_lock_addr(hash));
-       gl = search_bucket(hash, sdp, name);
-       read_unlock(gl_lock_addr(hash));
-
-       return gl;
-}
-
 /**
  * may_grant - check if its ok to grant a new lock
  * @gl: The glock
@@ -523,7 +496,7 @@ out_locked:
 }
 
 static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
-                                unsigned int cur_state, unsigned int req_state,
+                                unsigned int req_state,
                                 unsigned int flags)
 {
        int ret = LM_OUT_ERROR;
@@ -532,7 +505,7 @@ static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
                return req_state == LM_ST_UNLOCKED ? 0 : req_state;
 
        if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
+               ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock,
                                                         req_state, flags);
        return ret;
 }
@@ -575,7 +548,7 @@ __acquires(&gl->gl_spin)
            gl->gl_state == LM_ST_DEFERRED) &&
            !(lck_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
                lck_flags |= LM_FLAG_TRY_1CB;
-       ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, target, lck_flags);
+       ret = gfs2_lm_lock(sdp, gl, target, lck_flags);
 
        if (!(ret & LM_OUT_ASYNC)) {
                finish_xmote(gl, ret);
@@ -624,10 +597,11 @@ __acquires(&gl->gl_spin)
 
        GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags));
 
+       down_read(&gfs2_umount_flush_sem);
        if (test_bit(GLF_DEMOTE, &gl->gl_flags) &&
            gl->gl_demote_state != gl->gl_state) {
                if (find_first_holder(gl))
-                       goto out;
+                       goto out_unlock;
                if (nonblock)
                        goto out_sched;
                set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
@@ -638,23 +612,26 @@ __acquires(&gl->gl_spin)
                        gfs2_demote_wake(gl);
                ret = do_promote(gl);
                if (ret == 0)
-                       goto out;
+                       goto out_unlock;
                if (ret == 2)
-                       return;
+                       goto out_sem;
                gh = find_first_waiter(gl);
                gl->gl_target = gh->gh_state;
                if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
                        do_error(gl, 0); /* Fail queued try locks */
        }
        do_xmote(gl, gh, gl->gl_target);
+out_sem:
+       up_read(&gfs2_umount_flush_sem);
        return;
 
 out_sched:
        gfs2_glock_hold(gl);
        if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
                gfs2_glock_put(gl);
-out:
+out_unlock:
        clear_bit(GLF_LOCK, &gl->gl_flags);
+       goto out_sem;
 }
 
 static void glock_work_func(struct work_struct *work)
@@ -681,18 +658,6 @@ static void glock_work_func(struct work_struct *work)
                gfs2_glock_put(gl);
 }
 
-static int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
-                    void **lockp)
-{
-       int error = -EIO;
-       if (!sdp->sd_lockstruct.ls_ops->lm_get_lock)
-               return 0;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
-                               sdp->sd_lockstruct.ls_lockspace, name, lockp);
-       return error;
-}
-
 /**
  * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
  * @sdp: The GFS2 superblock
@@ -719,10 +684,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl = search_bucket(hash, sdp, &name);
        read_unlock(gl_lock_addr(hash));
 
-       if (gl || !create) {
-               *glp = gl;
+       *glp = gl;
+       if (gl)
                return 0;
-       }
+       if (!create)
+               return -ENOENT;
 
        gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
        if (!gl)
@@ -736,7 +702,9 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_demote_state = LM_ST_EXCLUSIVE;
        gl->gl_hash = hash;
        gl->gl_ops = glops;
-       gl->gl_stamp = jiffies;
+       snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number);
+       memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
+       gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
        gl->gl_tchange = jiffies;
        gl->gl_object = NULL;
        gl->gl_sbd = sdp;
@@ -753,10 +721,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
                }
        }
 
-       error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock);
-       if (error)
-               goto fail_aspace;
-
        write_lock(gl_lock_addr(hash));
        tmp = search_bucket(hash, sdp, &name);
        if (tmp) {
@@ -772,9 +736,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
 
        return 0;
 
-fail_aspace:
-       if (gl->gl_aspace)
-               gfs2_aspace_put(gl->gl_aspace);
 fail:
        kmem_cache_free(gfs2_glock_cachep, gl);
        return error;
@@ -966,7 +927,7 @@ do_cancel:
        if (!(gh->gh_flags & LM_FLAG_PRIORITY)) {
                spin_unlock(&gl->gl_spin);
                if (sdp->sd_lockstruct.ls_ops->lm_cancel)
-                       sdp->sd_lockstruct.ls_ops->lm_cancel(gl->gl_lock);
+                       sdp->sd_lockstruct.ls_ops->lm_cancel(gl);
                spin_lock(&gl->gl_spin);
        }
        return;
@@ -1051,7 +1012,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
                        spin_lock(&gl->gl_spin);
                        clear_bit(GLF_LOCK, &gl->gl_flags);
                }
-               gl->gl_stamp = jiffies;
                if (list_empty(&gl->gl_holders) &&
                    !test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
                    !test_bit(GLF_DEMOTE, &gl->gl_flags))
@@ -1240,70 +1200,13 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
                gfs2_glock_dq_uninit(&ghs[x]);
 }
 
-static int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
-{
-       int error = -EIO;
-       if (!sdp->sd_lockstruct.ls_ops->lm_hold_lvb)
-               return 0;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
-       return error;
-}
-
-/**
- * gfs2_lvb_hold - attach a LVB from a glock
- * @gl: The glock in question
- *
- */
-
-int gfs2_lvb_hold(struct gfs2_glock *gl)
-{
-       int error;
-
-       if (!atomic_read(&gl->gl_lvb_count)) {
-               error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb);
-               if (error) 
-                       return error;
-               gfs2_glock_hold(gl);
-       }
-       atomic_inc(&gl->gl_lvb_count);
-
-       return 0;
-}
-
-/**
- * gfs2_lvb_unhold - detach a LVB from a glock
- * @gl: The glock in question
- *
- */
-
-void gfs2_lvb_unhold(struct gfs2_glock *gl)
-{
-       struct gfs2_sbd *sdp = gl->gl_sbd;
-
-       gfs2_glock_hold(gl);
-       gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0);
-       if (atomic_dec_and_test(&gl->gl_lvb_count)) {
-               if (sdp->sd_lockstruct.ls_ops->lm_unhold_lvb)
-                       sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(gl->gl_lock, gl->gl_lvb);
-               gl->gl_lvb = NULL;
-               gfs2_glock_put(gl);
-       }
-       gfs2_glock_put(gl);
-}
-
-static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
-                       unsigned int state)
+void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
 {
-       struct gfs2_glock *gl;
        unsigned long delay = 0;
        unsigned long holdtime;
        unsigned long now = jiffies;
 
-       gl = gfs2_glock_find(sdp, name);
-       if (!gl)
-               return;
-
+       gfs2_glock_hold(gl);
        holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
        if (time_before(now, holdtime))
                delay = holdtime - now;
@@ -1317,74 +1220,33 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
                gfs2_glock_put(gl);
 }
 
-static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
-{
-       struct gfs2_jdesc *jd;
-
-       spin_lock(&sdp->sd_jindex_spin);
-       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
-               if (jd->jd_jid != jid)
-                       continue;
-               jd->jd_dirty = 1;
-               break;
-       }
-       spin_unlock(&sdp->sd_jindex_spin);
-}
-
 /**
- * gfs2_glock_cb - Callback used by locking module
- * @sdp: Pointer to the superblock
- * @type: Type of callback
- * @data: Type dependent data pointer
+ * gfs2_glock_complete - Callback used by locking
+ * @gl: Pointer to the glock
+ * @ret: The return value from the dlm
  *
- * Called by the locking module when it wants to tell us something.
- * Either we need to drop a lock, one of our ASYNC requests completed, or
- * a journal from another client needs to be recovered.
  */
 
-void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
+void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
 {
-       struct gfs2_sbd *sdp = cb_data;
-
-       switch (type) {
-       case LM_CB_NEED_E:
-               blocking_cb(sdp, data, LM_ST_UNLOCKED);
-               return;
-
-       case LM_CB_NEED_D:
-               blocking_cb(sdp, data, LM_ST_DEFERRED);
-               return;
-
-       case LM_CB_NEED_S:
-               blocking_cb(sdp, data, LM_ST_SHARED);
-               return;
-
-       case LM_CB_ASYNC: {
-               struct lm_async_cb *async = data;
-               struct gfs2_glock *gl;
-
-               down_read(&gfs2_umount_flush_sem);
-               gl = gfs2_glock_find(sdp, &async->lc_name);
-               if (gfs2_assert_warn(sdp, gl))
+       struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+       gl->gl_reply = ret;
+       if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) {
+               struct gfs2_holder *gh;
+               spin_lock(&gl->gl_spin);
+               gh = find_first_waiter(gl);
+               if ((!(gh && (gh->gh_flags & LM_FLAG_NOEXP)) &&
+                    (gl->gl_target != LM_ST_UNLOCKED)) ||
+                   ((ret & ~LM_OUT_ST_MASK) != 0))
+                       set_bit(GLF_FROZEN, &gl->gl_flags);
+               spin_unlock(&gl->gl_spin);
+               if (test_bit(GLF_FROZEN, &gl->gl_flags))
                        return;
-               gl->gl_reply = async->lc_ret;
-               set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
-               if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
-                       gfs2_glock_put(gl);
-               up_read(&gfs2_umount_flush_sem);
-               return;
-       }
-
-       case LM_CB_NEED_RECOVERY:
-               gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data);
-               if (sdp->sd_recoverd_process)
-                       wake_up_process(sdp->sd_recoverd_process);
-               return;
-
-       default:
-               gfs2_assert_warn(sdp, 0);
-               return;
        }
+       set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
+       gfs2_glock_hold(gl);
+       if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+               gfs2_glock_put(gl);
 }
 
 /**
@@ -1515,6 +1377,25 @@ out:
        return has_entries;
 }
 
+
+/**
+ * thaw_glock - thaw out a glock which has an unprocessed reply waiting
+ * @gl: The glock to thaw
+ *
+ * N.B. When we freeze a glock, we leave a ref to the glock outstanding,
+ * so this has to result in the ref count being dropped by one.
+ */
+
+static void thaw_glock(struct gfs2_glock *gl)
+{
+       if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
+               return;
+       set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
+       gfs2_glock_hold(gl);
+       if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+               gfs2_glock_put(gl);
+}
+
 /**
  * clear_glock - look at a glock and see if we can free it from glock cache
  * @gl: the glock to look at
@@ -1539,6 +1420,20 @@ static void clear_glock(struct gfs2_glock *gl)
                gfs2_glock_put(gl);
 }
 
+/**
+ * gfs2_glock_thaw - Thaw any frozen glocks
+ * @sdp: The super block
+ *
+ */
+
+void gfs2_glock_thaw(struct gfs2_sbd *sdp)
+{
+       unsigned x;
+
+       for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+               examine_bucket(thaw_glock, sdp, x);
+}
+
 /**
  * gfs2_gl_hash_clear - Empty out the glock hash table
  * @sdp: the filesystem
@@ -1619,7 +1514,7 @@ static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags)
        if (flags & LM_FLAG_NOEXP)
                *p++ = 'e';
        if (flags & LM_FLAG_ANY)
-               *p++ = 'a';
+               *p++ = 'A';
        if (flags & LM_FLAG_PRIORITY)
                *p++ = 'p';
        if (flags & GL_ASYNC)
@@ -1683,6 +1578,10 @@ static const char *gflags2str(char *buf, const unsigned long *gflags)
                *p++ = 'i';
        if (test_bit(GLF_REPLY_PENDING, gflags))
                *p++ = 'r';
+       if (test_bit(GLF_INITIAL, gflags))
+               *p++ = 'I';
+       if (test_bit(GLF_FROZEN, gflags))
+               *p++ = 'F';
        *p = 0;
        return buf;
 }
@@ -1717,14 +1616,13 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
        dtime *= 1000000/HZ; /* demote time in uSec */
        if (!test_bit(GLF_DEMOTE, &gl->gl_flags))
                dtime = 0;
-       gfs2_print_dbg(seq, "G:  s:%s n:%u/%llu f:%s t:%s d:%s/%llu l:%d a:%d r:%d\n",
+       gfs2_print_dbg(seq, "G:  s:%s n:%u/%llu f:%s t:%s d:%s/%llu a:%d r:%d\n",
                  state2str(gl->gl_state),
                  gl->gl_name.ln_type,
                  (unsigned long long)gl->gl_name.ln_number,
                  gflags2str(gflags_buf, &gl->gl_flags),
                  state2str(gl->gl_target),
                  state2str(gl->gl_demote_state), dtime,
-                 atomic_read(&gl->gl_lvb_count),
                  atomic_read(&gl->gl_ail_count),
                  atomic_read(&gl->gl_ref));
 
index 543ec7ecfbda75c9ad18588549d8a74b603fc1a6..a602a28f6f08b5bc259624ff7ee1fb6193da6eb7 100644 (file)
 #define __GLOCK_DOT_H__
 
 #include <linux/sched.h>
+#include <linux/parser.h>
 #include "incore.h"
 
-/* Flags for lock requests; used in gfs2_holder gh_flag field.
-   From lm_interface.h:
+/* Options for hostdata parser */
+
+enum {
+       Opt_jid,
+       Opt_id,
+       Opt_first,
+       Opt_nodir,
+       Opt_err,
+};
+
+/*
+ * lm_lockname types
+ */
+
+#define LM_TYPE_RESERVED       0x00
+#define LM_TYPE_NONDISK                0x01
+#define LM_TYPE_INODE          0x02
+#define LM_TYPE_RGRP           0x03
+#define LM_TYPE_META           0x04
+#define LM_TYPE_IOPEN          0x05
+#define LM_TYPE_FLOCK          0x06
+#define LM_TYPE_PLOCK          0x07
+#define LM_TYPE_QUOTA          0x08
+#define LM_TYPE_JOURNAL                0x09
+
+/*
+ * lm_lock() states
+ *
+ * SHARED is compatible with SHARED, not with DEFERRED or EX.
+ * DEFERRED is compatible with DEFERRED, not with SHARED or EX.
+ */
+
+#define LM_ST_UNLOCKED         0
+#define LM_ST_EXCLUSIVE                1
+#define LM_ST_DEFERRED         2
+#define LM_ST_SHARED           3
+
+/*
+ * lm_lock() flags
+ *
+ * LM_FLAG_TRY
+ * Don't wait to acquire the lock if it can't be granted immediately.
+ *
+ * LM_FLAG_TRY_1CB
+ * Send one blocking callback if TRY is set and the lock is not granted.
+ *
+ * LM_FLAG_NOEXP
+ * GFS sets this flag on lock requests it makes while doing journal recovery.
+ * These special requests should not be blocked due to the recovery like
+ * ordinary locks would be.
+ *
+ * LM_FLAG_ANY
+ * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
+ * also be granted in SHARED.  The preferred state is whichever is compatible
+ * with other granted locks, or the specified state if no other locks exist.
+ *
+ * LM_FLAG_PRIORITY
+ * Override fairness considerations.  Suppose a lock is held in a shared state
+ * and there is a pending request for the deferred state.  A shared lock
+ * request with the priority flag would be allowed to bypass the deferred
+ * request and directly join the other shared lock.  A shared lock request
+ * without the priority flag might be forced to wait until the deferred
+ * requested had acquired and released the lock.
+ */
+
 #define LM_FLAG_TRY            0x00000001
 #define LM_FLAG_TRY_1CB                0x00000002
 #define LM_FLAG_NOEXP          0x00000004
 #define LM_FLAG_ANY            0x00000008
-#define LM_FLAG_PRIORITY       0x00000010 */
+#define LM_FLAG_PRIORITY       0x00000010
+#define GL_ASYNC               0x00000040
+#define GL_EXACT               0x00000080
+#define GL_SKIP                        0x00000100
+#define GL_ATIME               0x00000200
+#define GL_NOCACHE             0x00000400
+  
+/*
+ * lm_lock() and lm_async_cb return flags
+ *
+ * LM_OUT_ST_MASK
+ * Masks the lower two bits of lock state in the returned value.
+ *
+ * LM_OUT_CANCELED
+ * The lock request was canceled.
+ *
+ * LM_OUT_ASYNC
+ * The result of the request will be returned in an LM_CB_ASYNC callback.
+ *
+ */
+
+#define LM_OUT_ST_MASK         0x00000003
+#define LM_OUT_CANCELED                0x00000008
+#define LM_OUT_ASYNC           0x00000080
+#define LM_OUT_ERROR           0x00000100
+
+/*
+ * lm_recovery_done() messages
+ */
+
+#define LM_RD_GAVEUP           308
+#define LM_RD_SUCCESS          309
+
+#define GLR_TRYFAILED          13
+
+struct lm_lockops {
+       const char *lm_proto_name;
+       int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname);
+       void (*lm_unmount) (struct gfs2_sbd *sdp);
+       void (*lm_withdraw) (struct gfs2_sbd *sdp);
+       void (*lm_put_lock) (struct kmem_cache *cachep, void *gl);
+       unsigned int (*lm_lock) (struct gfs2_glock *gl,
+                                unsigned int req_state, unsigned int flags);
+       void (*lm_cancel) (struct gfs2_glock *gl);
+       const match_table_t *lm_tokens;
+};
+
+#define LM_FLAG_TRY            0x00000001
+#define LM_FLAG_TRY_1CB                0x00000002
+#define LM_FLAG_NOEXP          0x00000004
+#define LM_FLAG_ANY            0x00000008
+#define LM_FLAG_PRIORITY       0x00000010
 
 #define GL_ASYNC               0x00000040
 #define GL_EXACT               0x00000080
@@ -128,10 +243,12 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
 int gfs2_lvb_hold(struct gfs2_glock *gl);
 void gfs2_lvb_unhold(struct gfs2_glock *gl);
 
-void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
+void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state);
+void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
 void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
 void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
 void gfs2_glock_finish_truncate(struct gfs2_inode *ip);
+void gfs2_glock_thaw(struct gfs2_sbd *sdp);
 
 int __init gfs2_glock_init(void);
 void gfs2_glock_exit(void);
@@ -141,4 +258,6 @@ void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
 int gfs2_register_debugfs(void);
 void gfs2_unregister_debugfs(void);
 
+extern const struct lm_lockops gfs2_dlm_ops;
+
 #endif /* __GLOCK_DOT_H__ */
index 8522d3aa64fc6032e81abf0cafae92a7f0e002c1..bf23a62aa92525031aa3835c8eb2e92cd5ab4ad5 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <linux/bio.h>
 
 #include "gfs2.h"
 static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
-       unsigned int blocks;
        struct list_head *head = &gl->gl_ail_list;
        struct gfs2_bufdata *bd;
        struct buffer_head *bh;
-       int error;
+       struct gfs2_trans tr;
 
-       blocks = atomic_read(&gl->gl_ail_count);
-       if (!blocks)
-               return;
+       memset(&tr, 0, sizeof(tr));
+       tr.tr_revokes = atomic_read(&gl->gl_ail_count);
 
-       error = gfs2_trans_begin(sdp, 0, blocks);
-       if (gfs2_assert_withdraw(sdp, !error))
+       if (!tr.tr_revokes)
                return;
 
+       /* A shortened, inline version of gfs2_trans_begin() */
+       tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
+       tr.tr_ip = (unsigned long)__builtin_return_address(0);
+       INIT_LIST_HEAD(&tr.tr_list_buf);
+       gfs2_log_reserve(sdp, tr.tr_reserved);
+       BUG_ON(current->journal_info);
+       current->journal_info = &tr;
+
        gfs2_log_lock(sdp);
        while (!list_empty(head)) {
                bd = list_entry(head->next, struct gfs2_bufdata,
@@ -72,29 +76,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
 }
 
 /**
- * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
- * @gl: the glock
- *
- */
-
-static void gfs2_pte_inval(struct gfs2_glock *gl)
-{
-       struct gfs2_inode *ip;
-       struct inode *inode;
-
-       ip = gl->gl_object;
-       inode = &ip->i_inode;
-       if (!ip || !S_ISREG(inode->i_mode))
-               return;
-
-       unmap_shared_mapping_range(inode->i_mapping, 0, 0);
-       if (test_bit(GIF_SW_PAGED, &ip->i_flags))
-               set_bit(GLF_DIRTY, &gl->gl_flags);
-
-}
-
-/**
- * meta_go_sync - sync out the metadata for this glock
+ * rgrp_go_sync - sync out the metadata for this glock
  * @gl: the glock
  *
  * Called when demoting or unlocking an EX glock.  We must flush
@@ -102,36 +84,42 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
  * not return to caller to demote/unlock the glock until I/O is complete.
  */
 
-static void meta_go_sync(struct gfs2_glock *gl)
+static void rgrp_go_sync(struct gfs2_glock *gl)
 {
-       if (gl->gl_state != LM_ST_EXCLUSIVE)
+       struct address_space *metamapping = gl->gl_aspace->i_mapping;
+       int error;
+
+       if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
                return;
+       BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE);
 
-       if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
-               gfs2_log_flush(gl->gl_sbd, gl);
-               gfs2_meta_sync(gl);
-               gfs2_ail_empty_gl(gl);
-       }
+       gfs2_log_flush(gl->gl_sbd, gl);
+       filemap_fdatawrite(metamapping);
+       error = filemap_fdatawait(metamapping);
+        mapping_set_error(metamapping, error);
+       gfs2_ail_empty_gl(gl);
 }
 
 /**
- * meta_go_inval - invalidate the metadata for this glock
+ * rgrp_go_inval - invalidate the metadata for this glock
  * @gl: the glock
  * @flags:
  *
+ * We never used LM_ST_DEFERRED with resource groups, so that we
+ * should always see the metadata flag set here.
+ *
  */
 
-static void meta_go_inval(struct gfs2_glock *gl, int flags)
+static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
 {
-       if (!(flags & DIO_METADATA))
-               return;
+       struct address_space *mapping = gl->gl_aspace->i_mapping;
 
-       gfs2_meta_inval(gl);
-       if (gl->gl_object == GFS2_I(gl->gl_sbd->sd_rindex))
-               gl->gl_sbd->sd_rindex_uptodate = 0;
-       else if (gl->gl_ops == &gfs2_rgrp_glops && gl->gl_object) {
-               struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
+       BUG_ON(!(flags & DIO_METADATA));
+       gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));
+       truncate_inode_pages(mapping, 0);
 
+       if (gl->gl_object) {
+               struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
                rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
        }
 }
@@ -148,48 +136,54 @@ static void inode_go_sync(struct gfs2_glock *gl)
        struct address_space *metamapping = gl->gl_aspace->i_mapping;
        int error;
 
-       if (gl->gl_state != LM_ST_UNLOCKED)
-               gfs2_pte_inval(gl);
-       if (gl->gl_state != LM_ST_EXCLUSIVE)
-               return;
-
        if (ip && !S_ISREG(ip->i_inode.i_mode))
                ip = NULL;
+       if (ip && test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags))
+               unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0);
+       if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
+               return;
 
-       if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-               gfs2_log_flush(gl->gl_sbd, gl);
-               filemap_fdatawrite(metamapping);
-               if (ip) {
-                       struct address_space *mapping = ip->i_inode.i_mapping;
-                       filemap_fdatawrite(mapping);
-                       error = filemap_fdatawait(mapping);
-                       mapping_set_error(mapping, error);
-               }
-               error = filemap_fdatawait(metamapping);
-               mapping_set_error(metamapping, error);
-               clear_bit(GLF_DIRTY, &gl->gl_flags);
-               gfs2_ail_empty_gl(gl);
+       BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE);
+
+       gfs2_log_flush(gl->gl_sbd, gl);
+       filemap_fdatawrite(metamapping);
+       if (ip) {
+               struct address_space *mapping = ip->i_inode.i_mapping;
+               filemap_fdatawrite(mapping);
+               error = filemap_fdatawait(mapping);
+               mapping_set_error(mapping, error);
        }
+       error = filemap_fdatawait(metamapping);
+       mapping_set_error(metamapping, error);
+       gfs2_ail_empty_gl(gl);
 }
 
 /**
  * inode_go_inval - prepare a inode glock to be released
  * @gl: the glock
  * @flags:
+ * 
+ * Normally we invlidate everything, but if we are moving into
+ * LM_ST_DEFERRED from LM_ST_SHARED or LM_ST_EXCLUSIVE then we
+ * can keep hold of the metadata, since it won't have changed.
  *
  */
 
 static void inode_go_inval(struct gfs2_glock *gl, int flags)
 {
        struct gfs2_inode *ip = gl->gl_object;
-       int meta = (flags & DIO_METADATA);
 
-       if (meta) {
-               gfs2_meta_inval(gl);
+       gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));
+
+       if (flags & DIO_METADATA) {
+               struct address_space *mapping = gl->gl_aspace->i_mapping;
+               truncate_inode_pages(mapping, 0);
                if (ip)
                        set_bit(GIF_INVALID, &ip->i_flags);
        }
 
+       if (ip == GFS2_I(gl->gl_sbd->sd_rindex))
+               gl->gl_sbd->sd_rindex_uptodate = 0;
        if (ip && S_ISREG(ip->i_inode.i_mode))
                truncate_inode_pages(ip->i_inode.i_mapping, 0);
 }
@@ -390,20 +384,7 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl)
        return 0;
 }
 
-/**
- * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
- * @gl: the glock
- *
- * Returns: 1 if it's ok
- */
-
-static int quota_go_demote_ok(const struct gfs2_glock *gl)
-{
-       return !atomic_read(&gl->gl_lvb_count);
-}
-
 const struct gfs2_glock_operations gfs2_meta_glops = {
-       .go_xmote_th = meta_go_sync,
        .go_type = LM_TYPE_META,
 };
 
@@ -418,8 +399,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
-       .go_xmote_th = meta_go_sync,
-       .go_inval = meta_go_inval,
+       .go_xmote_th = rgrp_go_sync,
+       .go_inval = rgrp_go_inval,
        .go_demote_ok = rgrp_go_demote_ok,
        .go_lock = rgrp_go_lock,
        .go_unlock = rgrp_go_unlock,
@@ -448,7 +429,6 @@ const struct gfs2_glock_operations gfs2_nondisk_glops = {
 };
 
 const struct gfs2_glock_operations gfs2_quota_glops = {
-       .go_demote_ok = quota_go_demote_ok,
        .go_type = LM_TYPE_QUOTA,
 };
 
@@ -456,3 +436,15 @@ const struct gfs2_glock_operations gfs2_journal_glops = {
        .go_type = LM_TYPE_JOURNAL,
 };
 
+const struct gfs2_glock_operations *gfs2_glops_list[] = {
+       [LM_TYPE_META] = &gfs2_meta_glops,
+       [LM_TYPE_INODE] = &gfs2_inode_glops,
+       [LM_TYPE_RGRP] = &gfs2_rgrp_glops,
+       [LM_TYPE_NONDISK] = &gfs2_trans_glops,
+       [LM_TYPE_IOPEN] = &gfs2_iopen_glops,
+       [LM_TYPE_FLOCK] = &gfs2_flock_glops,
+       [LM_TYPE_NONDISK] = &gfs2_nondisk_glops,
+       [LM_TYPE_QUOTA] = &gfs2_quota_glops,
+       [LM_TYPE_JOURNAL] = &gfs2_journal_glops,
+};
+
index a1d9b5b024e633af2a95069e4ba12c3a36268a68..b3aa2e3210fd6028cd5615a9c07a79ad5433af2c 100644 (file)
@@ -21,5 +21,6 @@ extern const struct gfs2_glock_operations gfs2_flock_glops;
 extern const struct gfs2_glock_operations gfs2_nondisk_glops;
 extern const struct gfs2_glock_operations gfs2_quota_glops;
 extern const struct gfs2_glock_operations gfs2_journal_glops;
+extern const struct gfs2_glock_operations *gfs2_glops_list[];
 
 #endif /* __GLOPS_DOT_H__ */
index 608849d00021cc436f656d1afb7a0966aec63ba0..399d1b97804972b3b6f4f27c801f6f2b823dbd0b 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/fs.h>
 #include <linux/workqueue.h>
+#include <linux/dlm.h>
+#include <linux/buffer_head.h>
 
 #define DIO_WAIT       0x00000010
 #define DIO_METADATA   0x00000020
@@ -26,6 +28,7 @@ struct gfs2_trans;
 struct gfs2_ail;
 struct gfs2_jdesc;
 struct gfs2_sbd;
+struct lm_lockops;
 
 typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret);
 
@@ -121,6 +124,28 @@ struct gfs2_bufdata {
        struct list_head bd_ail_gl_list;
 };
 
+/*
+ * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a
+ * prefix of lock_dlm_ gets awkward.
+ */
+
+#define GDLM_STRNAME_BYTES     25
+#define GDLM_LVB_SIZE          32
+
+enum {
+       DFL_BLOCK_LOCKS         = 0,
+};
+
+struct lm_lockname {
+       u64 ln_number;
+       unsigned int ln_type;
+};
+
+#define lm_name_equal(name1, name2) \
+        (((name1)->ln_number == (name2)->ln_number) && \
+         ((name1)->ln_type == (name2)->ln_type))
+
+
 struct gfs2_glock_operations {
        void (*go_xmote_th) (struct gfs2_glock *gl);
        int (*go_xmote_bh) (struct gfs2_glock *gl, struct gfs2_holder *gh);
@@ -162,6 +187,8 @@ enum {
        GLF_LFLUSH                      = 7,
        GLF_INVALIDATE_IN_PROGRESS      = 8,
        GLF_REPLY_PENDING               = 9,
+       GLF_INITIAL                     = 10,
+       GLF_FROZEN                      = 11,
 };
 
 struct gfs2_glock {
@@ -176,16 +203,15 @@ struct gfs2_glock {
        unsigned int gl_target;
        unsigned int gl_reply;
        unsigned int gl_hash;
+       unsigned int gl_req;
        unsigned int gl_demote_state; /* state requested by remote node */
        unsigned long gl_demote_time; /* time of first demote request */
        struct list_head gl_holders;
 
        const struct gfs2_glock_operations *gl_ops;
-       void *gl_lock;
-       char *gl_lvb;
-       atomic_t gl_lvb_count;
-
-       unsigned long gl_stamp;
+       char gl_strname[GDLM_STRNAME_BYTES];
+       struct dlm_lksb gl_lksb;
+       char gl_lvb[32];
        unsigned long gl_tchange;
        void *gl_object;
 
@@ -283,7 +309,9 @@ enum {
 
 struct gfs2_quota_data {
        struct list_head qd_list;
-       unsigned int qd_count;
+       struct list_head qd_reclaim;
+
+       atomic_t qd_count;
 
        u32 qd_id;
        unsigned long qd_flags;         /* QDF_... */
@@ -303,7 +331,6 @@ struct gfs2_quota_data {
 
        u64 qd_sync_gen;
        unsigned long qd_last_warn;
-       unsigned long qd_last_touched;
 };
 
 struct gfs2_trans {
@@ -390,7 +417,7 @@ struct gfs2_args {
        unsigned int ar_suiddir:1;              /* suiddir support */
        unsigned int ar_data:2;                 /* ordered/writeback */
        unsigned int ar_meta:1;                 /* mount metafs */
-       unsigned int ar_num_glockd;             /* Number of glockd threads */
+       unsigned int ar_discard:1;              /* discard requests */
 };
 
 struct gfs2_tune {
@@ -406,7 +433,6 @@ struct gfs2_tune {
        unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */
        unsigned int gt_quota_scale_num; /* Numerator */
        unsigned int gt_quota_scale_den; /* Denominator */
-       unsigned int gt_quota_cache_secs;
        unsigned int gt_quota_quantum; /* Secs between syncs to quota file */
        unsigned int gt_new_files_jdata;
        unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
@@ -445,6 +471,31 @@ struct gfs2_sb_host {
 
        char sb_lockproto[GFS2_LOCKNAME_LEN];
        char sb_locktable[GFS2_LOCKNAME_LEN];
+       u8 sb_uuid[16];
+};
+
+/*
+ * lm_mount() return values
+ *
+ * ls_jid - the journal ID this node should use
+ * ls_first - this node is the first to mount the file system
+ * ls_lockspace - lock module's context for this file system
+ * ls_ops - lock module's functions
+ */
+
+struct lm_lockstruct {
+       u32 ls_id;
+       unsigned int ls_jid;
+       unsigned int ls_first;
+       unsigned int ls_first_done;
+       unsigned int ls_nodir;
+       const struct lm_lockops *ls_ops;
+       unsigned long ls_flags;
+       dlm_lockspace_t *ls_dlm;
+
+       int ls_recover_jid;
+       int ls_recover_jid_done;
+       int ls_recover_jid_status;
 };
 
 struct gfs2_sbd {
@@ -520,7 +571,6 @@ struct gfs2_sbd {
        spinlock_t sd_jindex_spin;
        struct mutex sd_jindex_mutex;
        unsigned int sd_journals;
-       unsigned long sd_jindex_refresh_time;
 
        struct gfs2_jdesc *sd_jdesc;
        struct gfs2_holder sd_journal_gh;
@@ -540,7 +590,6 @@ struct gfs2_sbd {
 
        struct list_head sd_quota_list;
        atomic_t sd_quota_count;
-       spinlock_t sd_quota_spin;
        struct mutex sd_quota_mutex;
        wait_queue_head_t sd_quota_wait;
        struct list_head sd_trunc_list;
index 3b87c188da41c59eabe5f082f7e832e94c0fa079..7b277d4491558f4e360ac8c51002237009535775 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/sort.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/security.h>
 #include <linux/time.h>
 
@@ -137,16 +136,16 @@ void gfs2_set_iop(struct inode *inode)
 
        if (S_ISREG(mode)) {
                inode->i_op = &gfs2_file_iops;
-               if (sdp->sd_args.ar_localflocks)
-                       inode->i_fop = &gfs2_file_fops_nolock;
+               if (gfs2_localflocks(sdp))
+                       inode->i_fop = gfs2_file_fops_nolock;
                else
-                       inode->i_fop = &gfs2_file_fops;
+                       inode->i_fop = gfs2_file_fops;
        } else if (S_ISDIR(mode)) {
                inode->i_op = &gfs2_dir_iops;
-               if (sdp->sd_args.ar_localflocks)
-                       inode->i_fop = &gfs2_dir_fops_nolock;
+               if (gfs2_localflocks(sdp))
+                       inode->i_fop = gfs2_dir_fops_nolock;
                else
-                       inode->i_fop = &gfs2_dir_fops;
+                       inode->i_fop = gfs2_dir_fops;
        } else if (S_ISLNK(mode)) {
                inode->i_op = &gfs2_symlink_iops;
        } else {
index d5329364cdffcf29030a1480c71573184a4b2906..dca4fee3078b39c7638138761222fce61757255c 100644 (file)
@@ -101,12 +101,26 @@ void gfs2_dinode_print(const struct gfs2_inode *ip);
 extern const struct inode_operations gfs2_file_iops;
 extern const struct inode_operations gfs2_dir_iops;
 extern const struct inode_operations gfs2_symlink_iops;
-extern const struct file_operations gfs2_file_fops;
-extern const struct file_operations gfs2_dir_fops;
-extern const struct file_operations gfs2_file_fops_nolock;
-extern const struct file_operations gfs2_dir_fops_nolock;
+extern const struct file_operations *gfs2_file_fops_nolock;
+extern const struct file_operations *gfs2_dir_fops_nolock;
 
 extern void gfs2_set_inode_flags(struct inode *inode);
+#ifdef CONFIG_GFS2_FS_LOCKING_DLM
+extern const struct file_operations *gfs2_file_fops;
+extern const struct file_operations *gfs2_dir_fops;
+static inline int gfs2_localflocks(const struct gfs2_sbd *sdp)
+{
+       return sdp->sd_args.ar_localflocks;
+}
+#else /* Single node only */
+#define gfs2_file_fops NULL
+#define gfs2_dir_fops NULL
+static inline int gfs2_localflocks(const struct gfs2_sbd *sdp)
+{
+       return 1;
+}
+#endif /* CONFIG_GFS2_FS_LOCKING_DLM */
 
 #endif /* __INODE_DOT_H__ */
 
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
new file mode 100644 (file)
index 0000000..46df988
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/fs.h>
+#include <linux/dlm.h>
+#include <linux/types.h>
+#include <linux/gfs2_ondisk.h>
+
+#include "incore.h"
+#include "glock.h"
+#include "util.h"
+
+
+static void gdlm_ast(void *arg)
+{
+       struct gfs2_glock *gl = arg;
+       unsigned ret = gl->gl_state;
+
+       BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
+
+       if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
+               memset(gl->gl_lvb, 0, GDLM_LVB_SIZE);
+
+       switch (gl->gl_lksb.sb_status) {
+       case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */
+               kmem_cache_free(gfs2_glock_cachep, gl);
+               return;
+       case -DLM_ECANCEL: /* Cancel while getting lock */
+               ret |= LM_OUT_CANCELED;
+               goto out;
+       case -EAGAIN: /* Try lock fails */
+               goto out;
+       case -EINVAL: /* Invalid */
+       case -ENOMEM: /* Out of memory */
+               ret |= LM_OUT_ERROR;
+               goto out;
+       case 0: /* Success */
+               break;
+       default: /* Something unexpected */
+               BUG();
+       }
+
+       ret = gl->gl_req;
+       if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) {
+               if (gl->gl_req == LM_ST_SHARED)
+                       ret = LM_ST_DEFERRED;
+               else if (gl->gl_req == LM_ST_DEFERRED)
+                       ret = LM_ST_SHARED;
+               else
+                       BUG();
+       }
+
+       set_bit(GLF_INITIAL, &gl->gl_flags);
+       gfs2_glock_complete(gl, ret);
+       return;
+out:
+       if (!test_bit(GLF_INITIAL, &gl->gl_flags))
+               gl->gl_lksb.sb_lkid = 0;
+       gfs2_glock_complete(gl, ret);
+}
+
+static void gdlm_bast(void *arg, int mode)
+{
+       struct gfs2_glock *gl = arg;
+
+       switch (mode) {
+       case DLM_LOCK_EX:
+               gfs2_glock_cb(gl, LM_ST_UNLOCKED);
+               break;
+       case DLM_LOCK_CW:
+               gfs2_glock_cb(gl, LM_ST_DEFERRED);
+               break;
+       case DLM_LOCK_PR:
+               gfs2_glock_cb(gl, LM_ST_SHARED);
+               break;
+       default:
+               printk(KERN_ERR "unknown bast mode %d", mode);
+               BUG();
+       }
+}
+
+/* convert gfs lock-state to dlm lock-mode */
+
+static int make_mode(const unsigned int lmstate)
+{
+       switch (lmstate) {
+       case LM_ST_UNLOCKED:
+               return DLM_LOCK_NL;
+       case LM_ST_EXCLUSIVE:
+               return DLM_LOCK_EX;
+       case LM_ST_DEFERRED:
+               return DLM_LOCK_CW;
+       case LM_ST_SHARED:
+               return DLM_LOCK_PR;
+       }
+       printk(KERN_ERR "unknown LM state %d", lmstate);
+       BUG();
+       return -1;
+}
+
+static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
+                     const int req)
+{
+       u32 lkf = 0;
+
+       if (gfs_flags & LM_FLAG_TRY)
+               lkf |= DLM_LKF_NOQUEUE;
+
+       if (gfs_flags & LM_FLAG_TRY_1CB) {
+               lkf |= DLM_LKF_NOQUEUE;
+               lkf |= DLM_LKF_NOQUEUEBAST;
+       }
+
+       if (gfs_flags & LM_FLAG_PRIORITY) {
+               lkf |= DLM_LKF_NOORDER;
+               lkf |= DLM_LKF_HEADQUE;
+       }
+
+       if (gfs_flags & LM_FLAG_ANY) {
+               if (req == DLM_LOCK_PR)
+                       lkf |= DLM_LKF_ALTCW;
+               else if (req == DLM_LOCK_CW)
+                       lkf |= DLM_LKF_ALTPR;
+               else
+                       BUG();
+       }
+
+       if (lkid != 0) 
+               lkf |= DLM_LKF_CONVERT;
+
+       lkf |= DLM_LKF_VALBLK;
+
+       return lkf;
+}
+
+static unsigned int gdlm_lock(struct gfs2_glock *gl,
+                             unsigned int req_state, unsigned int flags)
+{
+       struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+       int error;
+       int req;
+       u32 lkf;
+
+       gl->gl_req = req_state;
+       req = make_mode(req_state);
+       lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
+
+       /*
+        * Submit the actual lock request.
+        */
+
+       error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
+                        GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
+       if (error == -EAGAIN)
+               return 0;
+       if (error)
+               return LM_OUT_ERROR;
+       return LM_OUT_ASYNC;
+}
+
+static void gdlm_put_lock(struct kmem_cache *cachep, void *ptr)
+{
+       struct gfs2_glock *gl = ptr;
+       struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+       int error;
+
+       if (gl->gl_lksb.sb_lkid == 0) {
+               kmem_cache_free(cachep, gl);
+               return;
+       }
+
+       error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
+                          NULL, gl);
+       if (error) {
+               printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n",
+                      gl->gl_name.ln_type,
+                      (unsigned long long)gl->gl_name.ln_number, error);
+               return;
+       }
+}
+
+static void gdlm_cancel(struct gfs2_glock *gl)
+{
+       struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+       dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
+}
+
+static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int error;
+
+       if (fsname == NULL) {
+               fs_info(sdp, "no fsname found\n");
+               return -EINVAL;
+       }
+
+       error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm,
+                                 DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
+                                 (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
+                                 GDLM_LVB_SIZE);
+       if (error)
+               printk(KERN_ERR "dlm_new_lockspace error %d", error);
+
+       return error;
+}
+
+static void gdlm_unmount(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       if (ls->ls_dlm) {
+               dlm_release_lockspace(ls->ls_dlm, 2);
+               ls->ls_dlm = NULL;
+       }
+}
+
+static const match_table_t dlm_tokens = {
+       { Opt_jid, "jid=%d"},
+       { Opt_id, "id=%d"},
+       { Opt_first, "first=%d"},
+       { Opt_nodir, "nodir=%d"},
+       { Opt_err, NULL },
+};
+
+const struct lm_lockops gfs2_dlm_ops = {
+       .lm_proto_name = "lock_dlm",
+       .lm_mount = gdlm_mount,
+       .lm_unmount = gdlm_unmount,
+       .lm_put_lock = gdlm_put_lock,
+       .lm_lock = gdlm_lock,
+       .lm_cancel = gdlm_cancel,
+       .lm_tokens = &dlm_tokens,
+};
+
diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c
deleted file mode 100644 (file)
index 523243a..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/kmod.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/lm_interface.h>
-
-struct lmh_wrapper {
-       struct list_head lw_list;
-       const struct lm_lockops *lw_ops;
-};
-
-static int nolock_mount(char *table_name, char *host_data,
-                       lm_callback_t cb, void *cb_data,
-                       unsigned int min_lvb_size, int flags,
-                       struct lm_lockstruct *lockstruct,
-                       struct kobject *fskobj);
-
-/* List of registered low-level locking protocols.  A file system selects one
-   of them by name at mount time, e.g. lock_nolock, lock_dlm. */
-
-static const struct lm_lockops nolock_ops = {
-       .lm_proto_name = "lock_nolock",
-       .lm_mount = nolock_mount,
-};
-
-static struct lmh_wrapper nolock_proto  = {
-       .lw_list = LIST_HEAD_INIT(nolock_proto.lw_list),
-       .lw_ops = &nolock_ops,
-};
-
-static LIST_HEAD(lmh_list);
-static DEFINE_MUTEX(lmh_lock);
-
-static int nolock_mount(char *table_name, char *host_data,
-                       lm_callback_t cb, void *cb_data,
-                       unsigned int min_lvb_size, int flags,
-                       struct lm_lockstruct *lockstruct,
-                       struct kobject *fskobj)
-{
-       char *c;
-       unsigned int jid;
-
-       c = strstr(host_data, "jid=");
-       if (!c)
-               jid = 0;
-       else {
-               c += 4;
-               sscanf(c, "%u", &jid);
-       }
-
-       lockstruct->ls_jid = jid;
-       lockstruct->ls_first = 1;
-       lockstruct->ls_lvb_size = min_lvb_size;
-       lockstruct->ls_ops = &nolock_ops;
-       lockstruct->ls_flags = LM_LSFLAG_LOCAL;
-
-       return 0;
-}
-
-/**
- * gfs2_register_lockproto - Register a low-level locking protocol
- * @proto: the protocol definition
- *
- * Returns: 0 on success, -EXXX on failure
- */
-
-int gfs2_register_lockproto(const struct lm_lockops *proto)
-{
-       struct lmh_wrapper *lw;
-
-       mutex_lock(&lmh_lock);
-
-       list_for_each_entry(lw, &lmh_list, lw_list) {
-               if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
-                       mutex_unlock(&lmh_lock);
-                       printk(KERN_INFO "GFS2: protocol %s already exists\n",
-                              proto->lm_proto_name);
-                       return -EEXIST;
-               }
-       }
-
-       lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
-       if (!lw) {
-               mutex_unlock(&lmh_lock);
-               return -ENOMEM;
-       }
-
-       lw->lw_ops = proto;
-       list_add(&lw->lw_list, &lmh_list);
-
-       mutex_unlock(&lmh_lock);
-
-       return 0;
-}
-
-/**
- * gfs2_unregister_lockproto - Unregister a low-level locking protocol
- * @proto: the protocol definition
- *
- */
-
-void gfs2_unregister_lockproto(const struct lm_lockops *proto)
-{
-       struct lmh_wrapper *lw;
-
-       mutex_lock(&lmh_lock);
-
-       list_for_each_entry(lw, &lmh_list, lw_list) {
-               if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
-                       list_del(&lw->lw_list);
-                       mutex_unlock(&lmh_lock);
-                       kfree(lw);
-                       return;
-               }
-       }
-
-       mutex_unlock(&lmh_lock);
-
-       printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n",
-              proto->lm_proto_name);
-}
-
-/**
- * gfs2_mount_lockproto - Mount a lock protocol
- * @proto_name - the name of the protocol
- * @table_name - the name of the lock space
- * @host_data - data specific to this host
- * @cb - the callback to the code using the lock module
- * @sdp - The GFS2 superblock
- * @min_lvb_size - the mininum LVB size that the caller can deal with
- * @flags - LM_MFLAG_*
- * @lockstruct - a structure returned describing the mount
- *
- * Returns: 0 on success, -EXXX on failure
- */
-
-int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
-                        lm_callback_t cb, void *cb_data,
-                        unsigned int min_lvb_size, int flags,
-                        struct lm_lockstruct *lockstruct,
-                        struct kobject *fskobj)
-{
-       struct lmh_wrapper *lw = NULL;
-       int try = 0;
-       int error, found;
-
-
-retry:
-       mutex_lock(&lmh_lock);
-
-       if (list_empty(&nolock_proto.lw_list))
-               list_add(&nolock_proto.lw_list, &lmh_list);
-
-       found = 0;
-       list_for_each_entry(lw, &lmh_list, lw_list) {
-               if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (!found) {
-               if (!try && capable(CAP_SYS_MODULE)) {
-                       try = 1;
-                       mutex_unlock(&lmh_lock);
-                       request_module(proto_name);
-                       goto retry;
-               }
-               printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name);
-               error = -ENOENT;
-               goto out;
-       }
-
-       if (lw->lw_ops->lm_owner &&
-           !try_module_get(lw->lw_ops->lm_owner)) {
-               try = 0;
-               mutex_unlock(&lmh_lock);
-               msleep(1000);
-               goto retry;
-       }
-
-       error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data,
-                                    min_lvb_size, flags, lockstruct, fskobj);
-       if (error)
-               module_put(lw->lw_ops->lm_owner);
-out:
-       mutex_unlock(&lmh_lock);
-       return error;
-}
-
-void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
-{
-       mutex_lock(&lmh_lock);
-       if (lockstruct->ls_ops->lm_unmount)
-               lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
-       if (lockstruct->ls_ops->lm_owner)
-               module_put(lockstruct->ls_ops->lm_owner);
-       mutex_unlock(&lmh_lock);
-}
-
-/**
- * gfs2_withdraw_lockproto - abnormally unmount a lock module
- * @lockstruct: the lockstruct passed into mount
- *
- */
-
-void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
-{
-       mutex_lock(&lmh_lock);
-       lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
-       if (lockstruct->ls_ops->lm_owner)
-               module_put(lockstruct->ls_ops->lm_owner);
-       mutex_unlock(&lmh_lock);
-}
-
-EXPORT_SYMBOL_GPL(gfs2_register_lockproto);
-EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto);
-
diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile
deleted file mode 100644 (file)
index 2609bb6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
-lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o
-
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
deleted file mode 100644 (file)
index 2482c90..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include "lock_dlm.h"
-
-static char junk_lvb[GDLM_LVB_SIZE];
-
-
-/* convert dlm lock-mode to gfs lock-state */
-
-static s16 gdlm_make_lmstate(s16 dlmmode)
-{
-       switch (dlmmode) {
-       case DLM_LOCK_IV:
-       case DLM_LOCK_NL:
-               return LM_ST_UNLOCKED;
-       case DLM_LOCK_EX:
-               return LM_ST_EXCLUSIVE;
-       case DLM_LOCK_CW:
-               return LM_ST_DEFERRED;
-       case DLM_LOCK_PR:
-               return LM_ST_SHARED;
-       }
-       gdlm_assert(0, "unknown DLM mode %d", dlmmode);
-       return -1;
-}
-
-/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm
-   thread gets to it. */
-
-static void queue_submit(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-
-       spin_lock(&ls->async_lock);
-       list_add_tail(&lp->delay_list, &ls->submit);
-       spin_unlock(&ls->async_lock);
-       wake_up(&ls->thread_wait);
-}
-
-static void wake_up_ast(struct gdlm_lock *lp)
-{
-       clear_bit(LFL_AST_WAIT, &lp->flags);
-       smp_mb__after_clear_bit();
-       wake_up_bit(&lp->flags, LFL_AST_WAIT);
-}
-
-static void gdlm_delete_lp(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-
-       spin_lock(&ls->async_lock);
-       if (!list_empty(&lp->delay_list))
-               list_del_init(&lp->delay_list);
-       ls->all_locks_count--;
-       spin_unlock(&ls->async_lock);
-
-       kfree(lp);
-}
-
-static void gdlm_queue_delayed(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-
-       spin_lock(&ls->async_lock);
-       list_add_tail(&lp->delay_list, &ls->delayed);
-       spin_unlock(&ls->async_lock);
-}
-
-static void process_complete(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-       struct lm_async_cb acb;
-
-       memset(&acb, 0, sizeof(acb));
-
-       if (lp->lksb.sb_status == -DLM_ECANCEL) {
-               log_info("complete dlm cancel %x,%llx flags %lx",
-                        lp->lockname.ln_type,
-                        (unsigned long long)lp->lockname.ln_number,
-                        lp->flags);
-
-               lp->req = lp->cur;
-               acb.lc_ret |= LM_OUT_CANCELED;
-               if (lp->cur == DLM_LOCK_IV)
-                       lp->lksb.sb_lkid = 0;
-               goto out;
-       }
-
-       if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) {
-               if (lp->lksb.sb_status != -DLM_EUNLOCK) {
-                       log_info("unlock sb_status %d %x,%llx flags %lx",
-                                lp->lksb.sb_status, lp->lockname.ln_type,
-                                (unsigned long long)lp->lockname.ln_number,
-                                lp->flags);
-                       return;
-               }
-
-               lp->cur = DLM_LOCK_IV;
-               lp->req = DLM_LOCK_IV;
-               lp->lksb.sb_lkid = 0;
-
-               if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) {
-                       gdlm_delete_lp(lp);
-                       return;
-               }
-               goto out;
-       }
-
-       if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID)
-               memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE);
-
-       if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) {
-               if (lp->req == DLM_LOCK_PR)
-                       lp->req = DLM_LOCK_CW;
-               else if (lp->req == DLM_LOCK_CW)
-                       lp->req = DLM_LOCK_PR;
-       }
-
-       /*
-        * A canceled lock request.  The lock was just taken off the delayed
-        * list and was never even submitted to dlm.
-        */
-
-       if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) {
-               log_info("complete internal cancel %x,%llx",
-                        lp->lockname.ln_type,
-                        (unsigned long long)lp->lockname.ln_number);
-               lp->req = lp->cur;
-               acb.lc_ret |= LM_OUT_CANCELED;
-               goto out;
-       }
-
-       /*
-        * An error occured.
-        */
-
-       if (lp->lksb.sb_status) {
-               /* a "normal" error */
-               if ((lp->lksb.sb_status == -EAGAIN) &&
-                   (lp->lkf & DLM_LKF_NOQUEUE)) {
-                       lp->req = lp->cur;
-                       if (lp->cur == DLM_LOCK_IV)
-                               lp->lksb.sb_lkid = 0;
-                       goto out;
-               }
-
-               /* this could only happen with cancels I think */
-               log_info("ast sb_status %d %x,%llx flags %lx",
-                        lp->lksb.sb_status, lp->lockname.ln_type,
-                        (unsigned long long)lp->lockname.ln_number,
-                        lp->flags);
-               return;
-       }
-
-       /*
-        * This is an AST for an EX->EX conversion for sync_lvb from GFS.
-        */
-
-       if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) {
-               wake_up_ast(lp);
-               return;
-       }
-
-       /*
-        * A lock has been demoted to NL because it initially completed during
-        * BLOCK_LOCKS.  Now it must be requested in the originally requested
-        * mode.
-        */
-
-       if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) {
-               gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx",
-                           lp->lockname.ln_type,
-                           (unsigned long long)lp->lockname.ln_number);
-               gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx",
-                           lp->lockname.ln_type,
-                           (unsigned long long)lp->lockname.ln_number);
-
-               lp->cur = DLM_LOCK_NL;
-               lp->req = lp->prev_req;
-               lp->prev_req = DLM_LOCK_IV;
-               lp->lkf &= ~DLM_LKF_CONVDEADLK;
-
-               set_bit(LFL_NOCACHE, &lp->flags);
-
-               if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
-                   !test_bit(LFL_NOBLOCK, &lp->flags))
-                       gdlm_queue_delayed(lp);
-               else
-                       queue_submit(lp);
-               return;
-       }
-
-       /*
-        * A request is granted during dlm recovery.  It may be granted
-        * because the locks of a failed node were cleared.  In that case,
-        * there may be inconsistent data beneath this lock and we must wait
-        * for recovery to complete to use it.  When gfs recovery is done this
-        * granted lock will be converted to NL and then reacquired in this
-        * granted state.
-        */
-
-       if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
-           !test_bit(LFL_NOBLOCK, &lp->flags) &&
-           lp->req != DLM_LOCK_NL) {
-
-               lp->cur = lp->req;
-               lp->prev_req = lp->req;
-               lp->req = DLM_LOCK_NL;
-               lp->lkf |= DLM_LKF_CONVERT;
-               lp->lkf &= ~DLM_LKF_CONVDEADLK;
-
-               log_debug("rereq %x,%llx id %x %d,%d",
-                         lp->lockname.ln_type,
-                         (unsigned long long)lp->lockname.ln_number,
-                         lp->lksb.sb_lkid, lp->cur, lp->req);
-
-               set_bit(LFL_REREQUEST, &lp->flags);
-               queue_submit(lp);
-               return;
-       }
-
-       /*
-        * DLM demoted the lock to NL before it was granted so GFS must be
-        * told it cannot cache data for this lock.
-        */
-
-       if (lp->lksb.sb_flags & DLM_SBF_DEMOTED)
-               set_bit(LFL_NOCACHE, &lp->flags);
-
-out:
-       /*
-        * This is an internal lock_dlm lock
-        */
-
-       if (test_bit(LFL_INLOCK, &lp->flags)) {
-               clear_bit(LFL_NOBLOCK, &lp->flags);
-               lp->cur = lp->req;
-               wake_up_ast(lp);
-               return;
-       }
-
-       /*
-        * Normal completion of a lock request.  Tell GFS it now has the lock.
-        */
-
-       clear_bit(LFL_NOBLOCK, &lp->flags);
-       lp->cur = lp->req;
-
-       acb.lc_name = lp->lockname;
-       acb.lc_ret |= gdlm_make_lmstate(lp->cur);
-
-       ls->fscb(ls->sdp, LM_CB_ASYNC, &acb);
-}
-
-static void gdlm_ast(void *astarg)
-{
-       struct gdlm_lock *lp = astarg;
-       clear_bit(LFL_ACTIVE, &lp->flags);
-       process_complete(lp);
-}
-
-static void process_blocking(struct gdlm_lock *lp, int bast_mode)
-{
-       struct gdlm_ls *ls = lp->ls;
-       unsigned int cb = 0;
-
-       switch (gdlm_make_lmstate(bast_mode)) {
-       case LM_ST_EXCLUSIVE:
-               cb = LM_CB_NEED_E;
-               break;
-       case LM_ST_DEFERRED:
-               cb = LM_CB_NEED_D;
-               break;
-       case LM_ST_SHARED:
-               cb = LM_CB_NEED_S;
-               break;
-       default:
-               gdlm_assert(0, "unknown bast mode %u", bast_mode);
-       }
-
-       ls->fscb(ls->sdp, cb, &lp->lockname);
-}
-
-
-static void gdlm_bast(void *astarg, int mode)
-{
-       struct gdlm_lock *lp = astarg;
-
-       if (!mode) {
-               printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n",
-                       lp->lockname.ln_type,
-                       (unsigned long long)lp->lockname.ln_number);
-               return;
-       }
-
-       process_blocking(lp, mode);
-}
-
-/* convert gfs lock-state to dlm lock-mode */
-
-static s16 make_mode(s16 lmstate)
-{
-       switch (lmstate) {
-       case LM_ST_UNLOCKED:
-               return DLM_LOCK_NL;
-       case LM_ST_EXCLUSIVE:
-               return DLM_LOCK_EX;
-       case LM_ST_DEFERRED:
-               return DLM_LOCK_CW;
-       case LM_ST_SHARED:
-               return DLM_LOCK_PR;
-       }
-       gdlm_assert(0, "unknown LM state %d", lmstate);
-       return -1;
-}
-
-
-/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and
-   DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */
-
-static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state)
-{
-       s16 cur = make_mode(cur_state);
-       if (lp->cur != DLM_LOCK_IV)
-               gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur);
-}
-
-static inline unsigned int make_flags(struct gdlm_lock *lp,
-                                     unsigned int gfs_flags,
-                                     s16 cur, s16 req)
-{
-       unsigned int lkf = 0;
-
-       if (gfs_flags & LM_FLAG_TRY)
-               lkf |= DLM_LKF_NOQUEUE;
-
-       if (gfs_flags & LM_FLAG_TRY_1CB) {
-               lkf |= DLM_LKF_NOQUEUE;
-               lkf |= DLM_LKF_NOQUEUEBAST;
-       }
-
-       if (gfs_flags & LM_FLAG_PRIORITY) {
-               lkf |= DLM_LKF_NOORDER;
-               lkf |= DLM_LKF_HEADQUE;
-       }
-
-       if (gfs_flags & LM_FLAG_ANY) {
-               if (req == DLM_LOCK_PR)
-                       lkf |= DLM_LKF_ALTCW;
-               else if (req == DLM_LOCK_CW)
-                       lkf |= DLM_LKF_ALTPR;
-       }
-
-       if (lp->lksb.sb_lkid != 0) {
-               lkf |= DLM_LKF_CONVERT;
-       }
-
-       if (lp->lvb)
-               lkf |= DLM_LKF_VALBLK;
-
-       return lkf;
-}
-
-/* make_strname - convert GFS lock numbers to a string */
-
-static inline void make_strname(const struct lm_lockname *lockname,
-                               struct gdlm_strname *str)
-{
-       sprintf(str->name, "%8x%16llx", lockname->ln_type,
-               (unsigned long long)lockname->ln_number);
-       str->namelen = GDLM_STRNAME_BYTES;
-}
-
-static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
-                         struct gdlm_lock **lpp)
-{
-       struct gdlm_lock *lp;
-
-       lp = kzalloc(sizeof(struct gdlm_lock), GFP_NOFS);
-       if (!lp)
-               return -ENOMEM;
-
-       lp->lockname = *name;
-       make_strname(name, &lp->strname);
-       lp->ls = ls;
-       lp->cur = DLM_LOCK_IV;
-       INIT_LIST_HEAD(&lp->delay_list);
-
-       spin_lock(&ls->async_lock);
-       ls->all_locks_count++;
-       spin_unlock(&ls->async_lock);
-
-       *lpp = lp;
-       return 0;
-}
-
-int gdlm_get_lock(void *lockspace, struct lm_lockname *name,
-                 void **lockp)
-{
-       struct gdlm_lock *lp;
-       int error;
-
-       error = gdlm_create_lp(lockspace, name, &lp);
-
-       *lockp = lp;
-       return error;
-}
-
-void gdlm_put_lock(void *lock)
-{
-       gdlm_delete_lp(lock);
-}
-
-unsigned int gdlm_do_lock(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-       int error, bast = 1;
-
-       /*
-        * When recovery is in progress, delay lock requests for submission
-        * once recovery is done.  Requests for recovery (NOEXP) and unlocks
-        * can pass.
-        */
-
-       if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
-           !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) {
-               gdlm_queue_delayed(lp);
-               return LM_OUT_ASYNC;
-       }
-
-       /*
-        * Submit the actual lock request.
-        */
-
-       if (test_bit(LFL_NOBAST, &lp->flags))
-               bast = 0;
-
-       set_bit(LFL_ACTIVE, &lp->flags);
-
-       log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
-                 (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid,
-                 lp->cur, lp->req, lp->lkf);
-
-       error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
-                        lp->strname.name, lp->strname.namelen, 0, gdlm_ast,
-                        lp, bast ? gdlm_bast : NULL);
-
-       if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
-               lp->lksb.sb_status = -EAGAIN;
-               gdlm_ast(lp);
-               error = 0;
-       }
-
-       if (error) {
-               log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
-                         "flags=%lx", ls->fsname, lp->lockname.ln_type,
-                         (unsigned long long)lp->lockname.ln_number, error,
-                         lp->cur, lp->req, lp->lkf, lp->flags);
-               return LM_OUT_ERROR;
-       }
-       return LM_OUT_ASYNC;
-}
-
-static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
-{
-       struct gdlm_ls *ls = lp->ls;
-       unsigned int lkf = 0;
-       int error;
-
-       set_bit(LFL_DLM_UNLOCK, &lp->flags);
-       set_bit(LFL_ACTIVE, &lp->flags);
-
-       if (lp->lvb)
-               lkf = DLM_LKF_VALBLK;
-
-       log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type,
-                 (unsigned long long)lp->lockname.ln_number,
-                 lp->lksb.sb_lkid, lp->cur, lkf);
-
-       error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
-
-       if (error) {
-               log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
-                         "flags=%lx", ls->fsname, lp->lockname.ln_type,
-                         (unsigned long long)lp->lockname.ln_number, error,
-                         lp->cur, lp->req, lp->lkf, lp->flags);
-               return LM_OUT_ERROR;
-       }
-       return LM_OUT_ASYNC;
-}
-
-unsigned int gdlm_lock(void *lock, unsigned int cur_state,
-                      unsigned int req_state, unsigned int flags)
-{
-       struct gdlm_lock *lp = lock;
-
-       if (req_state == LM_ST_UNLOCKED)
-               return gdlm_unlock(lock, cur_state);
-
-       if (req_state == LM_ST_UNLOCKED)
-               return gdlm_unlock(lock, cur_state);
-
-       clear_bit(LFL_DLM_CANCEL, &lp->flags);
-       if (flags & LM_FLAG_NOEXP)
-               set_bit(LFL_NOBLOCK, &lp->flags);
-
-       check_cur_state(lp, cur_state);
-       lp->req = make_mode(req_state);
-       lp->lkf = make_flags(lp, flags, lp->cur, lp->req);
-
-       return gdlm_do_lock(lp);
-}
-
-unsigned int gdlm_unlock(void *lock, unsigned int cur_state)
-{
-       struct gdlm_lock *lp = lock;
-
-       clear_bit(LFL_DLM_CANCEL, &lp->flags);
-       if (lp->cur == DLM_LOCK_IV)
-               return 0;
-       return gdlm_do_unlock(lp);
-}
-
-void gdlm_cancel(void *lock)
-{
-       struct gdlm_lock *lp = lock;
-       struct gdlm_ls *ls = lp->ls;
-       int error, delay_list = 0;
-
-       if (test_bit(LFL_DLM_CANCEL, &lp->flags))
-               return;
-
-       log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type,
-                (unsigned long long)lp->lockname.ln_number, lp->flags);
-
-       spin_lock(&ls->async_lock);
-       if (!list_empty(&lp->delay_list)) {
-               list_del_init(&lp->delay_list);
-               delay_list = 1;
-       }
-       spin_unlock(&ls->async_lock);
-
-       if (delay_list) {
-               set_bit(LFL_CANCEL, &lp->flags);
-               set_bit(LFL_ACTIVE, &lp->flags);
-               gdlm_ast(lp);
-               return;
-       }
-
-       if (!test_bit(LFL_ACTIVE, &lp->flags) ||
-           test_bit(LFL_DLM_UNLOCK, &lp->flags)) {
-               log_info("gdlm_cancel skip %x,%llx flags %lx",
-                        lp->lockname.ln_type,
-                        (unsigned long long)lp->lockname.ln_number, lp->flags);
-               return;
-       }
-
-       /* the lock is blocked in the dlm */
-
-       set_bit(LFL_DLM_CANCEL, &lp->flags);
-       set_bit(LFL_ACTIVE, &lp->flags);
-
-       error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL,
-                          NULL, lp);
-
-       log_info("gdlm_cancel rv %d %x,%llx flags %lx", error,
-                lp->lockname.ln_type,
-                (unsigned long long)lp->lockname.ln_number, lp->flags);
-
-       if (error == -EBUSY)
-               clear_bit(LFL_DLM_CANCEL, &lp->flags);
-}
-
-static int gdlm_add_lvb(struct gdlm_lock *lp)
-{
-       char *lvb;
-
-       lvb = kzalloc(GDLM_LVB_SIZE, GFP_NOFS);
-       if (!lvb)
-               return -ENOMEM;
-
-       lp->lksb.sb_lvbptr = lvb;
-       lp->lvb = lvb;
-       return 0;
-}
-
-static void gdlm_del_lvb(struct gdlm_lock *lp)
-{
-       kfree(lp->lvb);
-       lp->lvb = NULL;
-       lp->lksb.sb_lvbptr = NULL;
-}
-
-static int gdlm_ast_wait(void *word)
-{
-       schedule();
-       return 0;
-}
-
-/* This can do a synchronous dlm request (requiring a lock_dlm thread to get
-   the completion) because gfs won't call hold_lvb() during a callback (from
-   the context of a lock_dlm thread). */
-
-static int hold_null_lock(struct gdlm_lock *lp)
-{
-       struct gdlm_lock *lpn = NULL;
-       int error;
-
-       if (lp->hold_null) {
-               printk(KERN_INFO "lock_dlm: lvb already held\n");
-               return 0;
-       }
-
-       error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn);
-       if (error)
-               goto out;
-
-       lpn->lksb.sb_lvbptr = junk_lvb;
-       lpn->lvb = junk_lvb;
-
-       lpn->req = DLM_LOCK_NL;
-       lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE;
-       set_bit(LFL_NOBAST, &lpn->flags);
-       set_bit(LFL_INLOCK, &lpn->flags);
-       set_bit(LFL_AST_WAIT, &lpn->flags);
-
-       gdlm_do_lock(lpn);
-       wait_on_bit(&lpn->flags, LFL_AST_WAIT, gdlm_ast_wait, TASK_UNINTERRUPTIBLE);
-       error = lpn->lksb.sb_status;
-       if (error) {
-               printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n",
-                      error);
-               gdlm_delete_lp(lpn);
-               lpn = NULL;
-       }
-out:
-       lp->hold_null = lpn;
-       return error;
-}
-
-/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get
-   the completion) because gfs may call unhold_lvb() during a callback (from
-   the context of a lock_dlm thread) which could cause a deadlock since the
-   other lock_dlm thread could be engaged in recovery. */
-
-static void unhold_null_lock(struct gdlm_lock *lp)
-{
-       struct gdlm_lock *lpn = lp->hold_null;
-
-       gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type,
-                   (unsigned long long)lp->lockname.ln_number);
-       lpn->lksb.sb_lvbptr = NULL;
-       lpn->lvb = NULL;
-       set_bit(LFL_UNLOCK_DELETE, &lpn->flags);
-       gdlm_do_unlock(lpn);
-       lp->hold_null = NULL;
-}
-
-/* Acquire a NL lock because gfs requires the value block to remain
-   intact on the resource while the lvb is "held" even if it's holding no locks
-   on the resource. */
-
-int gdlm_hold_lvb(void *lock, char **lvbp)
-{
-       struct gdlm_lock *lp = lock;
-       int error;
-
-       error = gdlm_add_lvb(lp);
-       if (error)
-               return error;
-
-       *lvbp = lp->lvb;
-
-       error = hold_null_lock(lp);
-       if (error)
-               gdlm_del_lvb(lp);
-
-       return error;
-}
-
-void gdlm_unhold_lvb(void *lock, char *lvb)
-{
-       struct gdlm_lock *lp = lock;
-
-       unhold_null_lock(lp);
-       gdlm_del_lvb(lp);
-}
-
-void gdlm_submit_delayed(struct gdlm_ls *ls)
-{
-       struct gdlm_lock *lp, *safe;
-
-       spin_lock(&ls->async_lock);
-       list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) {
-               list_del_init(&lp->delay_list);
-               list_add_tail(&lp->delay_list, &ls->submit);
-       }
-       spin_unlock(&ls->async_lock);
-       wake_up(&ls->thread_wait);
-}
-
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
deleted file mode 100644 (file)
index 3c98e7c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef LOCK_DLM_DOT_H
-#define LOCK_DLM_DOT_H
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/socket.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/kobject.h>
-#include <linux/fcntl.h>
-#include <linux/wait.h>
-#include <net/sock.h>
-
-#include <linux/dlm.h>
-#include <linux/dlm_plock.h>
-#include <linux/lm_interface.h>
-
-/*
- * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a
- * prefix of lock_dlm_ gets awkward.  Externally, GFS refers to this module
- * as "lock_dlm".
- */
-
-#define GDLM_STRNAME_BYTES     24
-#define GDLM_LVB_SIZE          32
-#define GDLM_DROP_COUNT                0
-#define GDLM_DROP_PERIOD       60
-#define GDLM_NAME_LEN          128
-
-/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number).
-   We sprintf these numbers into a 24 byte string of hex values to make them
-   human-readable (to make debugging simpler.) */
-
-struct gdlm_strname {
-       unsigned char           name[GDLM_STRNAME_BYTES];
-       unsigned short          namelen;
-};
-
-enum {
-       DFL_BLOCK_LOCKS         = 0,
-       DFL_SPECTATOR           = 1,
-       DFL_WITHDRAW            = 2,
-};
-
-struct gdlm_ls {
-       u32             id;
-       int                     jid;
-       int                     first;
-       int                     first_done;
-       unsigned long           flags;
-       struct kobject          kobj;
-       char                    clustername[GDLM_NAME_LEN];
-       char                    fsname[GDLM_NAME_LEN];
-       int                     fsflags;
-       dlm_lockspace_t         *dlm_lockspace;
-       lm_callback_t           fscb;
-       struct gfs2_sbd         *sdp;
-       int                     recover_jid;
-       int                     recover_jid_done;
-       int                     recover_jid_status;
-       spinlock_t              async_lock;
-       struct list_head        delayed;
-       struct list_head        submit;
-       u32             all_locks_count;
-       wait_queue_head_t       wait_control;
-       struct task_struct      *thread;
-       wait_queue_head_t       thread_wait;
-};
-
-enum {
-       LFL_NOBLOCK             = 0,
-       LFL_NOCACHE             = 1,
-       LFL_DLM_UNLOCK          = 2,
-       LFL_DLM_CANCEL          = 3,
-       LFL_SYNC_LVB            = 4,
-       LFL_FORCE_PROMOTE       = 5,
-       LFL_REREQUEST           = 6,
-       LFL_ACTIVE              = 7,
-       LFL_INLOCK              = 8,
-       LFL_CANCEL              = 9,
-       LFL_NOBAST              = 10,
-       LFL_HEADQUE             = 11,
-       LFL_UNLOCK_DELETE       = 12,
-       LFL_AST_WAIT            = 13,
-};
-
-struct gdlm_lock {
-       struct gdlm_ls          *ls;
-       struct lm_lockname      lockname;
-       struct gdlm_strname     strname;
-       char                    *lvb;
-       struct dlm_lksb         lksb;
-
-       s16                     cur;
-       s16                     req;
-       s16                     prev_req;
-       u32                     lkf;            /* dlm flags DLM_LKF_ */
-       unsigned long           flags;          /* lock_dlm flags LFL_ */
-
-       struct list_head        delay_list;     /* delayed */
-       struct gdlm_lock        *hold_null;     /* NL lock for hold_lvb */
-};
-
-#define gdlm_assert(assertion, fmt, args...)                                  \
-do {                                                                          \
-       if (unlikely(!(assertion))) {                                         \
-               printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \
-                                 "lock_dlm:  " fmt "\n",                     \
-                                 #assertion, ##args);                        \
-               BUG();                                                        \
-       }                                                                     \
-} while (0)
-
-#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg)
-#define log_info(fmt, arg...)  log_print(KERN_INFO , fmt , ## arg)
-#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg)
-#ifdef LOCK_DLM_LOG_DEBUG
-#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg)
-#else
-#define log_debug(fmt, arg...)
-#endif
-
-/* sysfs.c */
-
-int gdlm_sysfs_init(void);
-void gdlm_sysfs_exit(void);
-int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *);
-void gdlm_kobject_release(struct gdlm_ls *);
-
-/* thread.c */
-
-int gdlm_init_threads(struct gdlm_ls *);
-void gdlm_release_threads(struct gdlm_ls *);
-
-/* lock.c */
-
-void gdlm_submit_delayed(struct gdlm_ls *);
-unsigned int gdlm_do_lock(struct gdlm_lock *);
-
-int gdlm_get_lock(void *, struct lm_lockname *, void **);
-void gdlm_put_lock(void *);
-unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int);
-unsigned int gdlm_unlock(void *, unsigned int);
-void gdlm_cancel(void *);
-int gdlm_hold_lvb(void *, char **);
-void gdlm_unhold_lvb(void *, char *);
-
-/* mount.c */
-
-extern const struct lm_lockops gdlm_ops;
-
-#endif
-
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
deleted file mode 100644 (file)
index b9a03a7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/init.h>
-
-#include "lock_dlm.h"
-
-static int __init init_lock_dlm(void)
-{
-       int error;
-
-       error = gfs2_register_lockproto(&gdlm_ops);
-       if (error) {
-               printk(KERN_WARNING "lock_dlm:  can't register protocol: %d\n",
-                      error);
-               return error;
-       }
-
-       error = gdlm_sysfs_init();
-       if (error) {
-               gfs2_unregister_lockproto(&gdlm_ops);
-               return error;
-       }
-
-       printk(KERN_INFO
-              "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
-       return 0;
-}
-
-static void __exit exit_lock_dlm(void)
-{
-       gdlm_sysfs_exit();
-       gfs2_unregister_lockproto(&gdlm_ops);
-}
-
-module_init(init_lock_dlm);
-module_exit(exit_lock_dlm);
-
-MODULE_DESCRIPTION("GFS DLM Locking Module");
-MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL");
-
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
deleted file mode 100644 (file)
index 1aa7eb6..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include "lock_dlm.h"
-
-const struct lm_lockops gdlm_ops;
-
-
-static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
-                                int flags, char *table_name)
-{
-       struct gdlm_ls *ls;
-       char buf[256], *p;
-
-       ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
-       if (!ls)
-               return NULL;
-
-       ls->fscb = cb;
-       ls->sdp = sdp;
-       ls->fsflags = flags;
-       spin_lock_init(&ls->async_lock);
-       INIT_LIST_HEAD(&ls->delayed);
-       INIT_LIST_HEAD(&ls->submit);
-       init_waitqueue_head(&ls->thread_wait);
-       init_waitqueue_head(&ls->wait_control);
-       ls->jid = -1;
-
-       strncpy(buf, table_name, 256);
-       buf[255] = '\0';
-
-       p = strchr(buf, ':');
-       if (!p) {
-               log_info("invalid table_name \"%s\"", table_name);
-               kfree(ls);
-               return NULL;
-       }
-       *p = '\0';
-       p++;
-
-       strncpy(ls->clustername, buf, GDLM_NAME_LEN);
-       strncpy(ls->fsname, p, GDLM_NAME_LEN);
-
-       return ls;
-}
-
-static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
-{
-       char data[256];
-       char *options, *x, *y;
-       int error = 0;
-
-       memset(data, 0, 256);
-       strncpy(data, data_arg, 255);
-
-       if (!strlen(data)) {
-               log_error("no mount options, (u)mount helpers not installed");
-               return -EINVAL;
-       }
-
-       for (options = data; (x = strsep(&options, ":")); ) {
-               if (!*x)
-                       continue;
-
-               y = strchr(x, '=');
-               if (y)
-                       *y++ = 0;
-
-               if (!strcmp(x, "jid")) {
-                       if (!y) {
-                               log_error("need argument to jid");
-                               error = -EINVAL;
-                               break;
-                       }
-                       sscanf(y, "%u", &ls->jid);
-
-               } else if (!strcmp(x, "first")) {
-                       if (!y) {
-                               log_error("need argument to first");
-                               error = -EINVAL;
-                               break;
-                       }
-                       sscanf(y, "%u", &ls->first);
-
-               } else if (!strcmp(x, "id")) {
-                       if (!y) {
-                               log_error("need argument to id");
-                               error = -EINVAL;
-                               break;
-                       }
-                       sscanf(y, "%u", &ls->id);
-
-               } else if (!strcmp(x, "nodir")) {
-                       if (!y) {
-                               log_error("need argument to nodir");
-                               error = -EINVAL;
-                               break;
-                       }
-                       sscanf(y, "%u", nodir);
-
-               } else {
-                       log_error("unkonwn option: %s", x);
-                       error = -EINVAL;
-                       break;
-               }
-       }
-
-       return error;
-}
-
-static int gdlm_mount(char *table_name, char *host_data,
-                       lm_callback_t cb, void *cb_data,
-                       unsigned int min_lvb_size, int flags,
-                       struct lm_lockstruct *lockstruct,
-                       struct kobject *fskobj)
-{
-       struct gdlm_ls *ls;
-       int error = -ENOMEM, nodir = 0;
-
-       if (min_lvb_size > GDLM_LVB_SIZE)
-               goto out;
-
-       ls = init_gdlm(cb, cb_data, flags, table_name);
-       if (!ls)
-               goto out;
-
-       error = make_args(ls, host_data, &nodir);
-       if (error)
-               goto out;
-
-       error = gdlm_init_threads(ls);
-       if (error)
-               goto out_free;
-
-       error = gdlm_kobject_setup(ls, fskobj);
-       if (error)
-               goto out_thread;
-
-       error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
-                                 &ls->dlm_lockspace,
-                                 DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
-                                 (nodir ? DLM_LSFL_NODIR : 0),
-                                 GDLM_LVB_SIZE);
-       if (error) {
-               log_error("dlm_new_lockspace error %d", error);
-               goto out_kobj;
-       }
-
-       lockstruct->ls_jid = ls->jid;
-       lockstruct->ls_first = ls->first;
-       lockstruct->ls_lockspace = ls;
-       lockstruct->ls_ops = &gdlm_ops;
-       lockstruct->ls_flags = 0;
-       lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
-       return 0;
-
-out_kobj:
-       gdlm_kobject_release(ls);
-out_thread:
-       gdlm_release_threads(ls);
-out_free:
-       kfree(ls);
-out:
-       return error;
-}
-
-static void gdlm_unmount(void *lockspace)
-{
-       struct gdlm_ls *ls = lockspace;
-
-       log_debug("unmount flags %lx", ls->flags);
-
-       /* FIXME: serialize unmount and withdraw in case they
-          happen at once.  Also, if unmount follows withdraw,
-          wait for withdraw to finish. */
-
-       if (test_bit(DFL_WITHDRAW, &ls->flags))
-               goto out;
-
-       gdlm_kobject_release(ls);
-       dlm_release_lockspace(ls->dlm_lockspace, 2);
-       gdlm_release_threads(ls);
-       BUG_ON(ls->all_locks_count);
-out:
-       kfree(ls);
-}
-
-static void gdlm_recovery_done(void *lockspace, unsigned int jid,
-                               unsigned int message)
-{
-       char env_jid[20];
-       char env_status[20];
-       char *envp[] = { env_jid, env_status, NULL };
-       struct gdlm_ls *ls = lockspace;
-       ls->recover_jid_done = jid;
-       ls->recover_jid_status = message;
-       sprintf(env_jid, "JID=%d", jid);
-       sprintf(env_status, "RECOVERY=%s",
-               message == LM_RD_SUCCESS ? "Done" : "Failed");
-       kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp);
-}
-
-static void gdlm_others_may_mount(void *lockspace)
-{
-       char *message = "FIRSTMOUNT=Done";
-       char *envp[] = { message, NULL };
-       struct gdlm_ls *ls = lockspace;
-       ls->first_done = 1;
-       kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp);
-}
-
-/* Userspace gets the offline uevent, blocks new gfs locks on
-   other mounters, and lets us know (sets WITHDRAW flag).  Then,
-   userspace leaves the mount group while we leave the lockspace. */
-
-static void gdlm_withdraw(void *lockspace)
-{
-       struct gdlm_ls *ls = lockspace;
-
-       kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
-
-       wait_event_interruptible(ls->wait_control,
-                                test_bit(DFL_WITHDRAW, &ls->flags));
-
-       dlm_release_lockspace(ls->dlm_lockspace, 2);
-       gdlm_release_threads(ls);
-       gdlm_kobject_release(ls);
-}
-
-static int gdlm_plock(void *lockspace, struct lm_lockname *name,
-              struct file *file, int cmd, struct file_lock *fl)
-{
-       struct gdlm_ls *ls = lockspace;
-       return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl);
-}
-
-static int gdlm_punlock(void *lockspace, struct lm_lockname *name,
-                struct file *file, struct file_lock *fl)
-{
-       struct gdlm_ls *ls = lockspace;
-       return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl);
-}
-
-static int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
-                  struct file *file, struct file_lock *fl)
-{
-       struct gdlm_ls *ls = lockspace;
-       return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl);
-}
-
-const struct lm_lockops gdlm_ops = {
-       .lm_proto_name = "lock_dlm",
-       .lm_mount = gdlm_mount,
-       .lm_others_may_mount = gdlm_others_may_mount,
-       .lm_unmount = gdlm_unmount,
-       .lm_withdraw = gdlm_withdraw,
-       .lm_get_lock = gdlm_get_lock,
-       .lm_put_lock = gdlm_put_lock,
-       .lm_lock = gdlm_lock,
-       .lm_unlock = gdlm_unlock,
-       .lm_plock = gdlm_plock,
-       .lm_punlock = gdlm_punlock,
-       .lm_plock_get = gdlm_plock_get,
-       .lm_cancel = gdlm_cancel,
-       .lm_hold_lvb = gdlm_hold_lvb,
-       .lm_unhold_lvb = gdlm_unhold_lvb,
-       .lm_recovery_done = gdlm_recovery_done,
-       .lm_owner = THIS_MODULE,
-};
-
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
deleted file mode 100644 (file)
index 9b7edcf..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/ctype.h>
-#include <linux/stat.h>
-
-#include "lock_dlm.h"
-
-static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name);
-}
-
-static ssize_t block_show(struct gdlm_ls *ls, char *buf)
-{
-       ssize_t ret;
-       int val = 0;
-
-       if (test_bit(DFL_BLOCK_LOCKS, &ls->flags))
-               val = 1;
-       ret = sprintf(buf, "%d\n", val);
-       return ret;
-}
-
-static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len)
-{
-       ssize_t ret = len;
-       int val;
-
-       val = simple_strtol(buf, NULL, 0);
-
-       if (val == 1)
-               set_bit(DFL_BLOCK_LOCKS, &ls->flags);
-       else if (val == 0) {
-               clear_bit(DFL_BLOCK_LOCKS, &ls->flags);
-               gdlm_submit_delayed(ls);
-       } else {
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf)
-{
-       ssize_t ret;
-       int val = 0;
-
-       if (test_bit(DFL_WITHDRAW, &ls->flags))
-               val = 1;
-       ret = sprintf(buf, "%d\n", val);
-       return ret;
-}
-
-static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len)
-{
-       ssize_t ret = len;
-       int val;
-
-       val = simple_strtol(buf, NULL, 0);
-
-       if (val == 1)
-               set_bit(DFL_WITHDRAW, &ls->flags);
-       else
-               ret = -EINVAL;
-       wake_up(&ls->wait_control);
-       return ret;
-}
-
-static ssize_t id_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%u\n", ls->id);
-}
-
-static ssize_t jid_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->jid);
-}
-
-static ssize_t first_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->first);
-}
-
-static ssize_t first_done_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->first_done);
-}
-
-static ssize_t recover_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->recover_jid);
-}
-
-static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len)
-{
-       ls->recover_jid = simple_strtol(buf, NULL, 0);
-       ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid);
-       return len;
-}
-
-static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->recover_jid_done);
-}
-
-static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
-{
-       return sprintf(buf, "%d\n", ls->recover_jid_status);
-}
-
-struct gdlm_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct gdlm_ls *, char *);
-       ssize_t (*store)(struct gdlm_ls *, const char *, size_t);
-};
-
-#define GDLM_ATTR(_name,_mode,_show,_store) \
-static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-GDLM_ATTR(proto_name,     0444, proto_name_show,     NULL);
-GDLM_ATTR(block,          0644, block_show,          block_store);
-GDLM_ATTR(withdraw,       0644, withdraw_show,       withdraw_store);
-GDLM_ATTR(id,             0444, id_show,             NULL);
-GDLM_ATTR(jid,            0444, jid_show,            NULL);
-GDLM_ATTR(first,          0444, first_show,          NULL);
-GDLM_ATTR(first_done,     0444, first_done_show,     NULL);
-GDLM_ATTR(recover,        0644, recover_show,        recover_store);
-GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
-GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
-
-static struct attribute *gdlm_attrs[] = {
-       &gdlm_attr_proto_name.attr,
-       &gdlm_attr_block.attr,
-       &gdlm_attr_withdraw.attr,
-       &gdlm_attr_id.attr,
-       &gdlm_attr_jid.attr,
-       &gdlm_attr_first.attr,
-       &gdlm_attr_first_done.attr,
-       &gdlm_attr_recover.attr,
-       &gdlm_attr_recover_done.attr,
-       &gdlm_attr_recover_status.attr,
-       NULL,
-};
-
-static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr,
-                             char *buf)
-{
-       struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
-       struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
-       return a->show ? a->show(ls, buf) : 0;
-}
-
-static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr,
-                              const char *buf, size_t len)
-{
-       struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
-       struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
-       return a->store ? a->store(ls, buf, len) : len;
-}
-
-static struct sysfs_ops gdlm_attr_ops = {
-       .show  = gdlm_attr_show,
-       .store = gdlm_attr_store,
-};
-
-static struct kobj_type gdlm_ktype = {
-       .default_attrs = gdlm_attrs,
-       .sysfs_ops     = &gdlm_attr_ops,
-};
-
-static struct kset *gdlm_kset;
-
-int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
-{
-       int error;
-
-       ls->kobj.kset = gdlm_kset;
-       error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj,
-                                    "lock_module");
-       if (error)
-               log_error("can't register kobj %d", error);
-       kobject_uevent(&ls->kobj, KOBJ_ADD);
-
-       return error;
-}
-
-void gdlm_kobject_release(struct gdlm_ls *ls)
-{
-       kobject_put(&ls->kobj);
-}
-
-static int gdlm_uevent(struct kset *kset, struct kobject *kobj,
-                      struct kobj_uevent_env *env)
-{
-        struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
-        add_uevent_var(env, "LOCKTABLE=%s:%s", ls->clustername, ls->fsname);
-        add_uevent_var(env, "LOCKPROTO=lock_dlm");
-        return 0;
-}
-
-static struct kset_uevent_ops gdlm_uevent_ops = {
-       .uevent = gdlm_uevent,
-};
-
-
-int gdlm_sysfs_init(void)
-{
-       gdlm_kset = kset_create_and_add("lock_dlm", &gdlm_uevent_ops, kernel_kobj);
-       if (!gdlm_kset) {
-               printk(KERN_WARNING "%s: can not create kset\n", __func__);
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-void gdlm_sysfs_exit(void)
-{
-       kset_unregister(gdlm_kset);
-}
-
diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
deleted file mode 100644 (file)
index 38823ef..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include "lock_dlm.h"
-
-static inline int no_work(struct gdlm_ls *ls)
-{
-       int ret;
-
-       spin_lock(&ls->async_lock);
-       ret = list_empty(&ls->submit);
-       spin_unlock(&ls->async_lock);
-
-       return ret;
-}
-
-static int gdlm_thread(void *data)
-{
-       struct gdlm_ls *ls = (struct gdlm_ls *) data;
-       struct gdlm_lock *lp = NULL;
-
-       while (!kthread_should_stop()) {
-               wait_event_interruptible(ls->thread_wait,
-                               !no_work(ls) || kthread_should_stop());
-
-               spin_lock(&ls->async_lock);
-
-               if (!list_empty(&ls->submit)) {
-                       lp = list_entry(ls->submit.next, struct gdlm_lock,
-                                       delay_list);
-                       list_del_init(&lp->delay_list);
-                       spin_unlock(&ls->async_lock);
-                       gdlm_do_lock(lp);
-                       spin_lock(&ls->async_lock);
-               }
-               spin_unlock(&ls->async_lock);
-       }
-
-       return 0;
-}
-
-int gdlm_init_threads(struct gdlm_ls *ls)
-{
-       struct task_struct *p;
-       int error;
-
-       p = kthread_run(gdlm_thread, ls, "lock_dlm");
-       error = IS_ERR(p);
-       if (error) {
-               log_error("can't start lock_dlm thread %d", error);
-               return error;
-       }
-       ls->thread = p;
-
-       return 0;
-}
-
-void gdlm_release_threads(struct gdlm_ls *ls)
-{
-       kthread_stop(ls->thread);
-}
-
index ad305854bdc6bb833b98c37b63ab50578373960f..98918a756410ca576f3fec0ba49fa8a82869033f 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
index 4390f6f4047d3466c60899d4b1d2526de985d450..80e4f5f898bb5170c2168d42975ba1604f30157a 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index 7cacfde321942c2149afbed5ba11a8ffa64077df..a6892ed0840a33715c6143ef67cb95e1dbbae874 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <asm/atomic.h>
 
 #include "gfs2.h"
 #include "sys.h"
 #include "util.h"
 #include "glock.h"
+#include "quota.h"
+
+static struct shrinker qd_shrinker = {
+       .shrink = gfs2_shrink_qd_memory,
+       .seeks = DEFAULT_SEEKS,
+};
 
 static void gfs2_init_inode_once(void *foo)
 {
@@ -41,8 +46,6 @@ static void gfs2_init_glock_once(void *foo)
        INIT_HLIST_NODE(&gl->gl_list);
        spin_lock_init(&gl->gl_spin);
        INIT_LIST_HEAD(&gl->gl_holders);
-       gl->gl_lvb = NULL;
-       atomic_set(&gl->gl_lvb_count, 0);
        INIT_LIST_HEAD(&gl->gl_lru);
        INIT_LIST_HEAD(&gl->gl_ail_list);
        atomic_set(&gl->gl_ail_count, 0);
@@ -100,6 +103,8 @@ static int __init init_gfs2_fs(void)
        if (!gfs2_quotad_cachep)
                goto fail;
 
+       register_shrinker(&qd_shrinker);
+
        error = register_filesystem(&gfs2_fs_type);
        if (error)
                goto fail;
@@ -117,6 +122,7 @@ static int __init init_gfs2_fs(void)
 fail_unregister:
        unregister_filesystem(&gfs2_fs_type);
 fail:
+       unregister_shrinker(&qd_shrinker);
        gfs2_glock_exit();
 
        if (gfs2_quotad_cachep)
@@ -145,6 +151,7 @@ fail:
 
 static void __exit exit_gfs2_fs(void)
 {
+       unregister_shrinker(&qd_shrinker);
        gfs2_glock_exit();
        gfs2_unregister_debugfs();
        unregister_filesystem(&gfs2_fs_type);
index 09853620c95121ecd0b2f8b4dd05397eef969e1d..8d6f13256b2634c520543d7b7acb615c0c397d96 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/delay.h>
 #include <linux/bio.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -89,27 +88,6 @@ void gfs2_aspace_put(struct inode *aspace)
        iput(aspace);
 }
 
-/**
- * gfs2_meta_inval - Invalidate all buffers associated with a glock
- * @gl: the glock
- *
- */
-
-void gfs2_meta_inval(struct gfs2_glock *gl)
-{
-       struct gfs2_sbd *sdp = gl->gl_sbd;
-       struct inode *aspace = gl->gl_aspace;
-       struct address_space *mapping = gl->gl_aspace->i_mapping;
-
-       gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
-
-       atomic_inc(&aspace->i_writecount);
-       truncate_inode_pages(mapping, 0);
-       atomic_dec(&aspace->i_writecount);
-
-       gfs2_assert_withdraw(sdp, !mapping->nrpages);
-}
-
 /**
  * gfs2_meta_sync - Sync all buffers associated with a glock
  * @gl: The glock
index b1a5f3674d436d342a73f1142788b4f59848911c..de270c2f9b6352e55662ef265b777984da0d2265 100644 (file)
@@ -40,7 +40,6 @@ static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh,
 struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp);
 void gfs2_aspace_put(struct inode *aspace);
 
-void gfs2_meta_inval(struct gfs2_glock *gl);
 void gfs2_meta_sync(struct gfs2_glock *gl);
 
 struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
index 3cb0a44ba0237830d3874283eab33bcdc573be7d..f7e8527a21e07438e3ab7e8b759d276853acb587 100644 (file)
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <linux/parser.h>
 
 #include "gfs2.h"
 #include "incore.h"
-#include "mount.h"
+#include "super.h"
 #include "sys.h"
 #include "util.h"
 
@@ -37,11 +36,15 @@ enum {
        Opt_quota_off,
        Opt_quota_account,
        Opt_quota_on,
+       Opt_quota,
+       Opt_noquota,
        Opt_suiddir,
        Opt_nosuiddir,
        Opt_data_writeback,
        Opt_data_ordered,
        Opt_meta,
+       Opt_discard,
+       Opt_nodiscard,
        Opt_err,
 };
 
@@ -61,11 +64,15 @@ static const match_table_t tokens = {
        {Opt_quota_off, "quota=off"},
        {Opt_quota_account, "quota=account"},
        {Opt_quota_on, "quota=on"},
+       {Opt_quota, "quota"},
+       {Opt_noquota, "noquota"},
        {Opt_suiddir, "suiddir"},
        {Opt_nosuiddir, "nosuiddir"},
        {Opt_data_writeback, "data=writeback"},
        {Opt_data_ordered, "data=ordered"},
        {Opt_meta, "meta"},
+       {Opt_discard, "discard"},
+       {Opt_nodiscard, "nodiscard"},
        {Opt_err, NULL}
 };
 
@@ -77,101 +84,46 @@ static const match_table_t tokens = {
  * Return: errno
  */
 
-int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
+int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
 {
-       struct gfs2_args *args = &sdp->sd_args;
-       char *data = data_arg;
-       char *options, *o, *v;
-       int error = 0;
-
-       if (!remount) {
-               /*  Set some defaults  */
-               args->ar_quota = GFS2_QUOTA_DEFAULT;
-               args->ar_data = GFS2_DATA_DEFAULT;
-       }
+       char *o;
+       int token;
+       substring_t tmp[MAX_OPT_ARGS];
 
        /* Split the options into tokens with the "," character and
           process them */
 
-       for (options = data; (o = strsep(&options, ",")); ) {
-               int token;
-               substring_t tmp[MAX_OPT_ARGS];
-
-               if (!*o)
+       while (1) {
+               o = strsep(&options, ",");
+               if (o == NULL)
+                       break;
+               if (*o == '\0')
                        continue;
 
                token = match_token(o, tokens, tmp);
                switch (token) {
                case Opt_lockproto:
-                       v = match_strdup(&tmp[0]);
-                       if (!v) {
-                               fs_info(sdp, "no memory for lockproto\n");
-                               error = -ENOMEM;
-                               goto out_error;
-                       }
-
-                       if (remount && strcmp(v, args->ar_lockproto)) {
-                               kfree(v);
-                               goto cant_remount;
-                       }
-                       
-                       strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
-                       args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
-                       kfree(v);
+                       match_strlcpy(args->ar_lockproto, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
                        break;
                case Opt_locktable:
-                       v = match_strdup(&tmp[0]);
-                       if (!v) {
-                               fs_info(sdp, "no memory for locktable\n");
-                               error = -ENOMEM;
-                               goto out_error;
-                       }
-
-                       if (remount && strcmp(v, args->ar_locktable)) {
-                               kfree(v);
-                               goto cant_remount;
-                       }
-
-                       strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
-                       args->ar_locktable[GFS2_LOCKNAME_LEN - 1]  = 0;
-                       kfree(v);
+                       match_strlcpy(args->ar_locktable, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
                        break;
                case Opt_hostdata:
-                       v = match_strdup(&tmp[0]);
-                       if (!v) {
-                               fs_info(sdp, "no memory for hostdata\n");
-                               error = -ENOMEM;
-                               goto out_error;
-                       }
-
-                       if (remount && strcmp(v, args->ar_hostdata)) {
-                               kfree(v);
-                               goto cant_remount;
-                       }
-
-                       strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
-                       args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
-                       kfree(v);
+                       match_strlcpy(args->ar_hostdata, &tmp[0],
+                                     GFS2_LOCKNAME_LEN);
                        break;
                case Opt_spectator:
-                       if (remount && !args->ar_spectator)
-                               goto cant_remount;
                        args->ar_spectator = 1;
-                       sdp->sd_vfs->s_flags |= MS_RDONLY;
                        break;
                case Opt_ignore_local_fs:
-                       if (remount && !args->ar_ignore_local_fs)
-                               goto cant_remount;
                        args->ar_ignore_local_fs = 1;
                        break;
                case Opt_localflocks:
-                       if (remount && !args->ar_localflocks)
-                               goto cant_remount;
                        args->ar_localflocks = 1;
                        break;
                case Opt_localcaching:
-                       if (remount && !args->ar_localcaching)
-                               goto cant_remount;
                        args->ar_localcaching = 1;
                        break;
                case Opt_debug:
@@ -181,25 +133,23 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
                        args->ar_debug = 0;
                        break;
                case Opt_upgrade:
-                       if (remount && !args->ar_upgrade)
-                               goto cant_remount;
                        args->ar_upgrade = 1;
                        break;
                case Opt_acl:
                        args->ar_posix_acl = 1;
-                       sdp->sd_vfs->s_flags |= MS_POSIXACL;
                        break;
                case Opt_noacl:
                        args->ar_posix_acl = 0;
-                       sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
                        break;
                case Opt_quota_off:
+               case Opt_noquota:
                        args->ar_quota = GFS2_QUOTA_OFF;
                        break;
                case Opt_quota_account:
                        args->ar_quota = GFS2_QUOTA_ACCOUNT;
                        break;
                case Opt_quota_on:
+               case Opt_quota:
                        args->ar_quota = GFS2_QUOTA_ON;
                        break;
                case Opt_suiddir:
@@ -215,29 +165,21 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
                        args->ar_data = GFS2_DATA_ORDERED;
                        break;
                case Opt_meta:
-                       if (remount && args->ar_meta != 1)
-                               goto cant_remount;
                        args->ar_meta = 1;
                        break;
+               case Opt_discard:
+                       args->ar_discard = 1;
+                       break;
+               case Opt_nodiscard:
+                       args->ar_discard = 0;
+                       break;
                case Opt_err:
                default:
-                       fs_info(sdp, "unknown option: %s\n", o);
-                       error = -EINVAL;
-                       goto out_error;
+                       fs_info(sdp, "invalid mount option: %s\n", o);
+                       return -EINVAL;
                }
        }
 
-out_error:
-       if (error)
-               fs_info(sdp, "invalid mount option(s)\n");
-
-       if (data != data_arg)
-               kfree(data);
-
-       return error;
-
-cant_remount:
-       fs_info(sdp, "can't remount with option %s\n", o);
-       return -EINVAL;
+       return 0;
 }
 
diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h
deleted file mode 100644 (file)
index 401288a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef __MOUNT_DOT_H__
-#define __MOUNT_DOT_H__
-
-struct gfs2_sbd;
-
-int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount);
-
-#endif /* __MOUNT_DOT_H__ */
index 4ddab67867eb273553b6afbf0a42399f56c51735..a6dde1751e17dfc48d57979c7d71ab30f755214b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/writeback.h>
 #include <linux/swap.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <linux/backing-dev.h>
 
 #include "gfs2.h"
@@ -442,6 +441,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
         */
        if (unlikely(page->index)) {
                zero_user(page, 0, PAGE_CACHE_SIZE);
+               SetPageUptodate(page);
                return 0;
        }
 
@@ -1096,6 +1096,7 @@ static const struct address_space_operations gfs2_writeback_aops = {
        .releasepage = gfs2_releasepage,
        .direct_IO = gfs2_direct_IO,
        .migratepage = buffer_migrate_page,
+       .is_partially_uptodate = block_is_partially_uptodate,
 };
 
 static const struct address_space_operations gfs2_ordered_aops = {
@@ -1111,6 +1112,7 @@ static const struct address_space_operations gfs2_ordered_aops = {
        .releasepage = gfs2_releasepage,
        .direct_IO = gfs2_direct_IO,
        .migratepage = buffer_migrate_page,
+       .is_partially_uptodate = block_is_partially_uptodate,
 };
 
 static const struct address_space_operations gfs2_jdata_aops = {
@@ -1125,6 +1127,7 @@ static const struct address_space_operations gfs2_jdata_aops = {
        .bmap = gfs2_bmap,
        .invalidatepage = gfs2_invalidatepage,
        .releasepage = gfs2_releasepage,
+       .is_partially_uptodate = block_is_partially_uptodate,
 };
 
 void gfs2_set_aops(struct inode *inode)
index c2ad36330ca3446707668c69731e791c9d1cb615..5eb57b0443828e2c1c90e530e4c7e4fcb65d577e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index 7fdeb14ddd1add6cb99a1dbae7da16c6445abcdd..9200ef2217162e0c00e81af4adf9e88bb7899d62 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/exportfs.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
index 93fe41b67f9749ed6ed901943ab1e7ae0808eb00..3b9e8de3500be1c40b2fbb798cb8dcdc8d4b51b5 100644 (file)
 #include <linux/gfs2_ondisk.h>
 #include <linux/ext2_fs.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/writeback.h>
 #include <asm/uaccess.h>
+#include <linux/dlm.h>
+#include <linux/dlm_plock.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -354,7 +355,9 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        if (ret)
                goto out;
 
+       set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
+
        ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
        if (ret || !alloc_required)
                goto out_unlock;
@@ -560,57 +563,24 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
        return ret;
 }
 
+#ifdef CONFIG_GFS2_FS_LOCKING_DLM
+
 /**
  * gfs2_setlease - acquire/release a file lease
  * @file: the file pointer
  * @arg: lease type
  * @fl: file lock
  *
+ * We don't currently have a way to enforce a lease across the whole
+ * cluster; until we do, disable leases (by just returning -EINVAL),
+ * unless the administrator has requested purely local locking.
+ *
  * Returns: errno
  */
 
 static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
-
-       /*
-        * We don't currently have a way to enforce a lease across the whole
-        * cluster; until we do, disable leases (by just returning -EINVAL),
-        * unless the administrator has requested purely local locking.
-        */
-       if (!sdp->sd_args.ar_localflocks)
-               return -EINVAL;
-       return generic_setlease(file, arg, fl);
-}
-
-static int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
-                     struct file *file, struct file_lock *fl)
-{
-       int error = -EIO;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
-                               sdp->sd_lockstruct.ls_lockspace, name, file, fl);
-       return error;
-}
-
-static int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
-                 struct file *file, int cmd, struct file_lock *fl)
-{
-       int error = -EIO;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = sdp->sd_lockstruct.ls_ops->lm_plock(
-                               sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
-       return error;
-}
-
-static int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
-                   struct file *file, struct file_lock *fl)
-{
-       int error = -EIO;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = sdp->sd_lockstruct.ls_ops->lm_punlock(
-                               sdp->sd_lockstruct.ls_lockspace, name, file, fl);
-       return error;
+       return -EINVAL;
 }
 
 /**
@@ -626,9 +596,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
 {
        struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
        struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
-       struct lm_lockname name =
-               { .ln_number = ip->i_no_addr,
-                 .ln_type = LM_TYPE_PLOCK };
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 
        if (!(fl->fl_flags & FL_POSIX))
                return -ENOLCK;
@@ -640,12 +608,14 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
                cmd = F_SETLK;
                fl->fl_type = F_UNLCK;
        }
+       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+               return -EIO;
        if (IS_GETLK(cmd))
-               return gfs2_lm_plock_get(sdp, &name, file, fl);
+               return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
        else if (fl->fl_type == F_UNLCK)
-               return gfs2_lm_punlock(sdp, &name, file, fl);
+               return dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl);
        else
-               return gfs2_lm_plock(sdp, &name, file, cmd, fl);
+               return dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl);
 }
 
 static int do_flock(struct file *file, int cmd, struct file_lock *fl)
@@ -732,7 +702,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
        }
 }
 
-const struct file_operations gfs2_file_fops = {
+const struct file_operations *gfs2_file_fops = &(const struct file_operations){
        .llseek         = gfs2_llseek,
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
@@ -750,7 +720,7 @@ const struct file_operations gfs2_file_fops = {
        .setlease       = gfs2_setlease,
 };
 
-const struct file_operations gfs2_dir_fops = {
+const struct file_operations *gfs2_dir_fops = &(const struct file_operations){
        .readdir        = gfs2_readdir,
        .unlocked_ioctl = gfs2_ioctl,
        .open           = gfs2_open,
@@ -760,7 +730,9 @@ const struct file_operations gfs2_dir_fops = {
        .flock          = gfs2_flock,
 };
 
-const struct file_operations gfs2_file_fops_nolock = {
+#endif /* CONFIG_GFS2_FS_LOCKING_DLM */
+
+const struct file_operations *gfs2_file_fops_nolock = &(const struct file_operations){
        .llseek         = gfs2_llseek,
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
@@ -773,10 +745,10 @@ const struct file_operations gfs2_file_fops_nolock = {
        .fsync          = gfs2_fsync,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
-       .setlease       = gfs2_setlease,
+       .setlease       = generic_setlease,
 };
 
-const struct file_operations gfs2_dir_fops_nolock = {
+const struct file_operations *gfs2_dir_fops_nolock = &(const struct file_operations){
        .readdir        = gfs2_readdir,
        .unlocked_ioctl = gfs2_ioctl,
        .open           = gfs2_open,
index f91eebdde5817f1f3eba25a724d48f1dc6132c59..51883b3ad89cd3359d5e489b7befec257650df60 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -25,7 +24,6 @@
 #include "glock.h"
 #include "glops.h"
 #include "inode.h"
-#include "mount.h"
 #include "recovery.h"
 #include "rgrp.h"
 #include "super.h"
@@ -64,7 +62,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
        gt->gt_quota_warn_period = 10;
        gt->gt_quota_scale_num = 1;
        gt->gt_quota_scale_den = 1;
-       gt->gt_quota_cache_secs = 300;
        gt->gt_quota_quantum = 60;
        gt->gt_new_files_jdata = 0;
        gt->gt_max_readahead = 1 << 18;
@@ -100,7 +97,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
        mutex_init(&sdp->sd_jindex_mutex);
 
        INIT_LIST_HEAD(&sdp->sd_quota_list);
-       spin_lock_init(&sdp->sd_quota_spin);
        mutex_init(&sdp->sd_quota_mutex);
        init_waitqueue_head(&sdp->sd_quota_wait);
        INIT_LIST_HEAD(&sdp->sd_trunc_list);
@@ -238,6 +234,7 @@ static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf)
 
        memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
        memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
+       memcpy(sb->sb_uuid, str->sb_uuid, 16);
 }
 
 /**
@@ -299,15 +296,15 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector)
        __free_page(page);
        return 0;
 }
+
 /**
  * gfs2_read_sb - Read super block
  * @sdp: The GFS2 superblock
- * @gl: the glock for the superblock (assumed to be held)
  * @silent: Don't print message if mount fails
  *
  */
 
-static int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
+static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent)
 {
        u32 hash_blocks, ind_blocks, leaf_blocks;
        u32 tmp_blocks;
@@ -527,7 +524,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent)
                return ret;
        }
 
-       ret = gfs2_read_sb(sdp, sb_gh.gh_gl, silent);
+       ret = gfs2_read_sb(sdp, silent);
        if (ret) {
                fs_err(sdp, "can't read superblock: %d\n", ret);
                goto out;
@@ -630,13 +627,13 @@ static int map_journal_extents(struct gfs2_sbd *sdp)
        return rc;
 }
 
-static void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
+static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
 {
-       if (!sdp->sd_lockstruct.ls_ops->lm_others_may_mount)
-               return;
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
-                                       sdp->sd_lockstruct.ls_lockspace);
+       char *message = "FIRSTMOUNT=Done";
+       char *envp[] = { message, NULL };
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       ls->ls_first_done = 1;
+       kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
 /**
@@ -796,7 +793,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                        }
                }
 
-               gfs2_lm_others_may_mount(sdp);
+               gfs2_others_may_mount(sdp);
        } else if (!sdp->sd_args.ar_spectator) {
                error = gfs2_recover_journal(sdp->sd_jdesc);
                if (error) {
@@ -1005,7 +1002,6 @@ static int init_threads(struct gfs2_sbd *sdp, int undo)
                goto fail_quotad;
 
        sdp->sd_log_flush_time = jiffies;
-       sdp->sd_jindex_refresh_time = jiffies;
 
        p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
        error = IS_ERR(p);
@@ -1033,6 +1029,17 @@ fail:
        return error;
 }
 
+static const match_table_t nolock_tokens = {
+       { Opt_jid, "jid=%d\n", },
+       { Opt_err, NULL },
+};
+
+static const struct lm_lockops nolock_ops = {
+       .lm_proto_name = "lock_nolock",
+       .lm_put_lock = kmem_cache_free,
+       .lm_tokens = &nolock_tokens,
+};
+
 /**
  * gfs2_lm_mount - mount a locking protocol
  * @sdp: the filesystem
@@ -1044,31 +1051,73 @@ fail:
 
 static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
 {
-       char *proto = sdp->sd_proto_name;
-       char *table = sdp->sd_table_name;
-       int flags = LM_MFLAG_CONV_NODROP;
-       int error;
+       const struct lm_lockops *lm;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       struct gfs2_args *args = &sdp->sd_args;
+       const char *proto = sdp->sd_proto_name;
+       const char *table = sdp->sd_table_name;
+       const char *fsname;
+       char *o, *options;
+       int ret;
 
-       if (sdp->sd_args.ar_spectator)
-               flags |= LM_MFLAG_SPECTATOR;
+       if (!strcmp("lock_nolock", proto)) {
+               lm = &nolock_ops;
+               sdp->sd_args.ar_localflocks = 1;
+               sdp->sd_args.ar_localcaching = 1;
+#ifdef CONFIG_GFS2_FS_LOCKING_DLM
+       } else if (!strcmp("lock_dlm", proto)) {
+               lm = &gfs2_dlm_ops;
+#endif
+       } else {
+               printk(KERN_INFO "GFS2: can't find protocol %s\n", proto);
+               return -ENOENT;
+       }
 
        fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
 
-       error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
-                                    gfs2_glock_cb, sdp,
-                                    GFS2_MIN_LVB_SIZE, flags,
-                                    &sdp->sd_lockstruct, &sdp->sd_kobj);
-       if (error) {
-               fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
-                       proto, table, sdp->sd_args.ar_hostdata);
-               goto out;
-       }
+       ls->ls_ops = lm;
+       ls->ls_first = 1;
+       ls->ls_id = 0;
 
-       if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
-           gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
-                                 GFS2_MIN_LVB_SIZE)) {
-               gfs2_unmount_lockproto(&sdp->sd_lockstruct);
-               goto out;
+       for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) {
+               substring_t tmp[MAX_OPT_ARGS];
+               int token, option;
+
+               if (!o || !*o)
+                       continue;
+
+               token = match_token(o, *lm->lm_tokens, tmp);
+               switch (token) {
+               case Opt_jid:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || option < 0) 
+                               goto hostdata_error;
+                       ls->ls_jid = option;
+                       break;
+               case Opt_id:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret)
+                               goto hostdata_error;
+                       ls->ls_id = option;
+                       break;
+               case Opt_first:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || (option != 0 && option != 1))
+                               goto hostdata_error;
+                       ls->ls_first = option;
+                       break;
+               case Opt_nodir:
+                       ret = match_int(&tmp[0], &option);
+                       if (ret || (option != 0 && option != 1))
+                               goto hostdata_error;
+                       ls->ls_nodir = option;
+                       break;
+               case Opt_err:
+               default:
+hostdata_error:
+                       fs_info(sdp, "unknown hostdata (%s)\n", o);
+                       return -EINVAL;
+               }
        }
 
        if (sdp->sd_args.ar_spectator)
@@ -1077,22 +1126,25 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
                snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
                         sdp->sd_lockstruct.ls_jid);
 
-       fs_info(sdp, "Joined cluster. Now mounting FS...\n");
-
-       if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
-           !sdp->sd_args.ar_ignore_local_fs) {
-               sdp->sd_args.ar_localflocks = 1;
-               sdp->sd_args.ar_localcaching = 1;
+       fsname = strchr(table, ':');
+       if (fsname)
+               fsname++;
+       if (lm->lm_mount == NULL) {
+               fs_info(sdp, "Now mounting FS...\n");
+               return 0;
        }
-
-out:
-       return error;
+       ret = lm->lm_mount(sdp, fsname);
+       if (ret == 0)
+               fs_info(sdp, "Joined cluster. Now mounting FS...\n");
+       return ret;
 }
 
 void gfs2_lm_unmount(struct gfs2_sbd *sdp)
 {
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+       const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops;
+       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) &&
+           lm->lm_unmount)
+               lm->lm_unmount(sdp);
 }
 
 /**
@@ -1116,12 +1168,20 @@ static int fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        }
 
-       error = gfs2_mount_args(sdp, (char *)data, 0);
+       sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
+       sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
+
+       error = gfs2_mount_args(sdp, &sdp->sd_args, data);
        if (error) {
                printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
                goto fail;
        }
 
+       if (sdp->sd_args.ar_spectator)
+                sb->s_flags |= MS_RDONLY;
+       if (sdp->sd_args.ar_posix_acl)
+               sb->s_flags |= MS_POSIXACL;
+
        sb->s_magic = GFS2_MAGIC;
        sb->s_op = &gfs2_super_ops;
        sb->s_export_op = &gfs2_export_ops;
@@ -1199,6 +1259,8 @@ fail_sb:
                dput(sdp->sd_root_dir);
        if (sdp->sd_master_dir)
                dput(sdp->sd_master_dir);
+       if (sb->s_root)
+               dput(sb->s_root);
        sb->s_root = NULL;
 fail_locking:
        init_locking(sdp, &mount_gh, UNDO);
index 49877546beb91477c32ce1362f8f5afdb20ce511..abd5429ae2856a9d275ca75bd9273598994e94f1 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/posix_acl.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/fiemap.h>
 #include <asm/uaccess.h>
 
index 320323d0347933bd45d644a153a0435cdf96daf7..458019569dcb43d4216eccf89b752e80f0e69929 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/delay.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/time.h>
 
 #include "gfs2.h"
@@ -27,7 +26,6 @@
 #include "glock.h"
 #include "inode.h"
 #include "log.h"
-#include "mount.h"
 #include "quota.h"
 #include "recovery.h"
 #include "rgrp.h"
@@ -40,6 +38,8 @@
 #include "bmap.h"
 #include "meta_io.h"
 
+#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
+
 /**
  * gfs2_write_inode - Make sure the inode is stable on the disk
  * @inode: The inode
@@ -435,25 +435,45 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_args args = sdp->sd_args; /* Default to current settings */
        int error;
 
-       error = gfs2_mount_args(sdp, data, 1);
+       error = gfs2_mount_args(sdp, &args, data);
        if (error)
                return error;
 
+       /* Not allowed to change locking details */
+       if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) ||
+           strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) ||
+           strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata))
+               return -EINVAL;
+
+       /* Some flags must not be changed */
+       if (args_neq(&args, &sdp->sd_args, spectator) ||
+           args_neq(&args, &sdp->sd_args, ignore_local_fs) ||
+           args_neq(&args, &sdp->sd_args, localflocks) ||
+           args_neq(&args, &sdp->sd_args, localcaching) ||
+           args_neq(&args, &sdp->sd_args, meta))
+               return -EINVAL;
+
        if (sdp->sd_args.ar_spectator)
                *flags |= MS_RDONLY;
-       else {
-               if (*flags & MS_RDONLY) {
-                       if (!(sb->s_flags & MS_RDONLY))
-                               error = gfs2_make_fs_ro(sdp);
-               } else if (!(*flags & MS_RDONLY) &&
-                          (sb->s_flags & MS_RDONLY)) {
+
+       if ((sb->s_flags ^ *flags) & MS_RDONLY) {
+               if (*flags & MS_RDONLY)
+                       error = gfs2_make_fs_ro(sdp);
+               else
                        error = gfs2_make_fs_rw(sdp);
-               }
+               if (error)
+                       return error;
        }
 
-       return error;
+       sdp->sd_args = args;
+       if (sdp->sd_args.ar_posix_acl)
+               sb->s_flags |= MS_POSIXACL;
+       else
+               sb->s_flags &= ~MS_POSIXACL;
+       return 0;
 }
 
 /**
@@ -588,6 +608,8 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
                }
                seq_printf(s, ",data=%s", state);
        }
+       if (args->ar_discard)
+               seq_printf(s, ",discard");
 
        return 0;
 }
index b08d09696b3e8d92fd8af400cfb819fa196d8229..8d53f66b5bccda2944049b5d4adebe64a9a2efb7 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/fs.h>
 #include <linux/bio.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
@@ -80,6 +79,51 @@ struct gfs2_quota_change_host {
        u32 qc_id;
 };
 
+static LIST_HEAD(qd_lru_list);
+static atomic_t qd_lru_count = ATOMIC_INIT(0);
+static spinlock_t qd_lru_lock = SPIN_LOCK_UNLOCKED;
+
+int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask)
+{
+       struct gfs2_quota_data *qd;
+       struct gfs2_sbd *sdp;
+
+       if (nr == 0)
+               goto out;
+
+       if (!(gfp_mask & __GFP_FS))
+               return -1;
+
+       spin_lock(&qd_lru_lock);
+       while (nr && !list_empty(&qd_lru_list)) {
+               qd = list_entry(qd_lru_list.next,
+                               struct gfs2_quota_data, qd_reclaim);
+               sdp = qd->qd_gl->gl_sbd;
+
+               /* Free from the filesystem-specific list */
+               list_del(&qd->qd_list);
+
+               gfs2_assert_warn(sdp, !qd->qd_change);
+               gfs2_assert_warn(sdp, !qd->qd_slot_count);
+               gfs2_assert_warn(sdp, !qd->qd_bh_count);
+
+               gfs2_glock_put(qd->qd_gl);
+               atomic_dec(&sdp->sd_quota_count);
+
+               /* Delete it from the common reclaim list */
+               list_del_init(&qd->qd_reclaim);
+               atomic_dec(&qd_lru_count);
+               spin_unlock(&qd_lru_lock);
+               kmem_cache_free(gfs2_quotad_cachep, qd);
+               spin_lock(&qd_lru_lock);
+               nr--;
+       }
+       spin_unlock(&qd_lru_lock);
+
+out:
+       return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100;
+}
+
 static u64 qd2offset(struct gfs2_quota_data *qd)
 {
        u64 offset;
@@ -100,22 +144,18 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,
        if (!qd)
                return -ENOMEM;
 
-       qd->qd_count = 1;
+       atomic_set(&qd->qd_count, 1);
        qd->qd_id = id;
        if (user)
                set_bit(QDF_USER, &qd->qd_flags);
        qd->qd_slot = -1;
+       INIT_LIST_HEAD(&qd->qd_reclaim);
 
        error = gfs2_glock_get(sdp, 2 * (u64)id + !user,
                              &gfs2_quota_glops, CREATE, &qd->qd_gl);
        if (error)
                goto fail;
 
-       error = gfs2_lvb_hold(qd->qd_gl);
-       gfs2_glock_put(qd->qd_gl);
-       if (error)
-               goto fail;
-
        *qdp = qd;
 
        return 0;
@@ -135,11 +175,17 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
 
        for (;;) {
                found = 0;
-               spin_lock(&sdp->sd_quota_spin);
+               spin_lock(&qd_lru_lock);
                list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
                        if (qd->qd_id == id &&
                            !test_bit(QDF_USER, &qd->qd_flags) == !user) {
-                               qd->qd_count++;
+                               if (!atomic_read(&qd->qd_count) &&
+                                   !list_empty(&qd->qd_reclaim)) {
+                                       /* Remove it from reclaim list */
+                                       list_del_init(&qd->qd_reclaim);
+                                       atomic_dec(&qd_lru_count);
+                               }
+                               atomic_inc(&qd->qd_count);
                                found = 1;
                                break;
                        }
@@ -155,11 +201,11 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
                        new_qd = NULL;
                }
 
-               spin_unlock(&sdp->sd_quota_spin);
+               spin_unlock(&qd_lru_lock);
 
                if (qd || !create) {
                        if (new_qd) {
-                               gfs2_lvb_unhold(new_qd->qd_gl);
+                               gfs2_glock_put(new_qd->qd_gl);
                                kmem_cache_free(gfs2_quotad_cachep, new_qd);
                        }
                        *qdp = qd;
@@ -175,21 +221,18 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
 static void qd_hold(struct gfs2_quota_data *qd)
 {
        struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
-
-       spin_lock(&sdp->sd_quota_spin);
-       gfs2_assert(sdp, qd->qd_count);
-       qd->qd_count++;
-       spin_unlock(&sdp->sd_quota_spin);
+       gfs2_assert(sdp, atomic_read(&qd->qd_count));
+       atomic_inc(&qd->qd_count);
 }
 
 static void qd_put(struct gfs2_quota_data *qd)
 {
-       struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
-       spin_lock(&sdp->sd_quota_spin);
-       gfs2_assert(sdp, qd->qd_count);
-       if (!--qd->qd_count)
-               qd->qd_last_touched = jiffies;
-       spin_unlock(&sdp->sd_quota_spin);
+       if (atomic_dec_and_lock(&qd->qd_count, &qd_lru_lock)) {
+               /* Add to the reclaim list */
+               list_add_tail(&qd->qd_reclaim, &qd_lru_list);
+               atomic_inc(&qd_lru_count);
+               spin_unlock(&qd_lru_lock);
+       }
 }
 
 static int slot_get(struct gfs2_quota_data *qd)
@@ -198,10 +241,10 @@ static int slot_get(struct gfs2_quota_data *qd)
        unsigned int c, o = 0, b;
        unsigned char byte = 0;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
 
        if (qd->qd_slot_count++) {
-               spin_unlock(&sdp->sd_quota_spin);
+               spin_unlock(&qd_lru_lock);
                return 0;
        }
 
@@ -225,13 +268,13 @@ found:
 
        sdp->sd_quota_bitmap[c][o] |= 1 << b;
 
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        return 0;
 
 fail:
        qd->qd_slot_count--;
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
        return -ENOSPC;
 }
 
@@ -239,23 +282,23 @@ static void slot_hold(struct gfs2_quota_data *qd)
 {
        struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
        gfs2_assert(sdp, qd->qd_slot_count);
        qd->qd_slot_count++;
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 }
 
 static void slot_put(struct gfs2_quota_data *qd)
 {
        struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
        gfs2_assert(sdp, qd->qd_slot_count);
        if (!--qd->qd_slot_count) {
                gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0);
                qd->qd_slot = -1;
        }
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 }
 
 static int bh_get(struct gfs2_quota_data *qd)
@@ -330,7 +373,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
        if (sdp->sd_vfs->s_flags & MS_RDONLY)
                return 0;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
 
        list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
                if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
@@ -341,8 +384,8 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
                list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
 
                set_bit(QDF_LOCKED, &qd->qd_flags);
-               gfs2_assert_warn(sdp, qd->qd_count);
-               qd->qd_count++;
+               gfs2_assert_warn(sdp, atomic_read(&qd->qd_count));
+               atomic_inc(&qd->qd_count);
                qd->qd_change_sync = qd->qd_change;
                gfs2_assert_warn(sdp, qd->qd_slot_count);
                qd->qd_slot_count++;
@@ -354,7 +397,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
        if (!found)
                qd = NULL;
 
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        if (qd) {
                gfs2_assert_warn(sdp, qd->qd_change_sync);
@@ -379,24 +422,24 @@ static int qd_trylock(struct gfs2_quota_data *qd)
        if (sdp->sd_vfs->s_flags & MS_RDONLY)
                return 0;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
 
        if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
            !test_bit(QDF_CHANGE, &qd->qd_flags)) {
-               spin_unlock(&sdp->sd_quota_spin);
+               spin_unlock(&qd_lru_lock);
                return 0;
        }
 
        list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
 
        set_bit(QDF_LOCKED, &qd->qd_flags);
-       gfs2_assert_warn(sdp, qd->qd_count);
-       qd->qd_count++;
+       gfs2_assert_warn(sdp, atomic_read(&qd->qd_count));
+       atomic_inc(&qd->qd_count);
        qd->qd_change_sync = qd->qd_change;
        gfs2_assert_warn(sdp, qd->qd_slot_count);
        qd->qd_slot_count++;
 
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        gfs2_assert_warn(sdp, qd->qd_change_sync);
        if (bh_get(qd)) {
@@ -556,9 +599,9 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
        x = be64_to_cpu(qc->qc_change) + change;
        qc->qc_change = cpu_to_be64(x);
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
        qd->qd_change = x;
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        if (!x) {
                gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags));
@@ -802,8 +845,8 @@ restart:
                loff_t pos;
                gfs2_glock_dq_uninit(q_gh);
                error = gfs2_glock_nq_init(qd->qd_gl,
-                                         LM_ST_EXCLUSIVE, GL_NOCACHE,
-                                         q_gh);
+                                          LM_ST_EXCLUSIVE, GL_NOCACHE,
+                                          q_gh);
                if (error)
                        return error;
 
@@ -820,7 +863,6 @@ restart:
 
                gfs2_glock_dq_uninit(&i_gh);
 
-
                gfs2_quota_in(&q, buf);
                qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
                qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
@@ -890,9 +932,9 @@ static int need_sync(struct gfs2_quota_data *qd)
        if (!qd->qd_qb.qb_limit)
                return 0;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
        value = qd->qd_change;
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        spin_lock(&gt->gt_spin);
        num = gt->gt_quota_scale_num;
@@ -985,9 +1027,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
                        continue;
 
                value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
-               spin_lock(&sdp->sd_quota_spin);
+               spin_lock(&qd_lru_lock);
                value += qd->qd_change;
-               spin_unlock(&sdp->sd_quota_spin);
+               spin_unlock(&qd_lru_lock);
 
                if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
                        print_message(qd, "exceeded");
@@ -1171,13 +1213,12 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
                        qd->qd_change = qc.qc_change;
                        qd->qd_slot = slot;
                        qd->qd_slot_count = 1;
-                       qd->qd_last_touched = jiffies;
 
-                       spin_lock(&sdp->sd_quota_spin);
+                       spin_lock(&qd_lru_lock);
                        gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1);
                        list_add(&qd->qd_list, &sdp->sd_quota_list);
                        atomic_inc(&sdp->sd_quota_count);
-                       spin_unlock(&sdp->sd_quota_spin);
+                       spin_unlock(&qd_lru_lock);
 
                        found++;
                }
@@ -1197,73 +1238,48 @@ fail:
        return error;
 }
 
-static void gfs2_quota_scan(struct gfs2_sbd *sdp)
-{
-       struct gfs2_quota_data *qd, *safe;
-       LIST_HEAD(dead);
-
-       spin_lock(&sdp->sd_quota_spin);
-       list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) {
-               if (!qd->qd_count &&
-                   time_after_eq(jiffies, qd->qd_last_touched +
-                               gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) {
-                       list_move(&qd->qd_list, &dead);
-                       gfs2_assert_warn(sdp,
-                                        atomic_read(&sdp->sd_quota_count) > 0);
-                       atomic_dec(&sdp->sd_quota_count);
-               }
-       }
-       spin_unlock(&sdp->sd_quota_spin);
-
-       while (!list_empty(&dead)) {
-               qd = list_entry(dead.next, struct gfs2_quota_data, qd_list);
-               list_del(&qd->qd_list);
-
-               gfs2_assert_warn(sdp, !qd->qd_change);
-               gfs2_assert_warn(sdp, !qd->qd_slot_count);
-               gfs2_assert_warn(sdp, !qd->qd_bh_count);
-
-               gfs2_lvb_unhold(qd->qd_gl);
-               kmem_cache_free(gfs2_quotad_cachep, qd);
-       }
-}
-
 void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
 {
        struct list_head *head = &sdp->sd_quota_list;
        struct gfs2_quota_data *qd;
        unsigned int x;
 
-       spin_lock(&sdp->sd_quota_spin);
+       spin_lock(&qd_lru_lock);
        while (!list_empty(head)) {
                qd = list_entry(head->prev, struct gfs2_quota_data, qd_list);
 
-               if (qd->qd_count > 1 ||
-                   (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) {
+               if (atomic_read(&qd->qd_count) > 1 ||
+                   (atomic_read(&qd->qd_count) &&
+                    !test_bit(QDF_CHANGE, &qd->qd_flags))) {
                        list_move(&qd->qd_list, head);
-                       spin_unlock(&sdp->sd_quota_spin);
+                       spin_unlock(&qd_lru_lock);
                        schedule();
-                       spin_lock(&sdp->sd_quota_spin);
+                       spin_lock(&qd_lru_lock);
                        continue;
                }
 
                list_del(&qd->qd_list);
+               /* Also remove if this qd exists in the reclaim list */
+               if (!list_empty(&qd->qd_reclaim)) {
+                       list_del_init(&qd->qd_reclaim);
+                       atomic_dec(&qd_lru_count);
+               }
                atomic_dec(&sdp->sd_quota_count);
-               spin_unlock(&sdp->sd_quota_spin);
+               spin_unlock(&qd_lru_lock);
 
-               if (!qd->qd_count) {
+               if (!atomic_read(&qd->qd_count)) {
                        gfs2_assert_warn(sdp, !qd->qd_change);
                        gfs2_assert_warn(sdp, !qd->qd_slot_count);
                } else
                        gfs2_assert_warn(sdp, qd->qd_slot_count == 1);
                gfs2_assert_warn(sdp, !qd->qd_bh_count);
 
-               gfs2_lvb_unhold(qd->qd_gl);
+               gfs2_glock_put(qd->qd_gl);
                kmem_cache_free(gfs2_quotad_cachep, qd);
 
-               spin_lock(&sdp->sd_quota_spin);
+               spin_lock(&qd_lru_lock);
        }
-       spin_unlock(&sdp->sd_quota_spin);
+       spin_unlock(&qd_lru_lock);
 
        gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count));
 
@@ -1341,9 +1357,6 @@ int gfs2_quotad(void *data)
                quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
                                   &quotad_timeo, &tune->gt_quota_quantum);
 
-               /* FIXME: This should be turned into a shrinker */
-               gfs2_quota_scan(sdp);
-
                /* Check for & recover partially truncated inodes */
                quotad_check_trunc_list(sdp);
 
index cec9032be97da0bbcb439249c4c47ec90cf0cd77..0fa5fa63d0e8fce00a37c2ea4cbdc7a476fe5c3e 100644 (file)
@@ -49,4 +49,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
        return ret;
 }
 
+extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask);
+
 #endif /* __QUOTA_DOT_H__ */
index efd09c3d2b26975b5497b323497d2b3d802bd452..247e8f7d6b3d5da3d23a717ae46d1cadf1bc106e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
@@ -427,20 +426,23 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea
 }
 
 
-static void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
-                                 unsigned int message)
+static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
+                               unsigned int message)
 {
-       if (!sdp->sd_lockstruct.ls_ops->lm_recovery_done)
-               return;
-
-       if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               sdp->sd_lockstruct.ls_ops->lm_recovery_done(
-                       sdp->sd_lockstruct.ls_lockspace, jid, message);
+       char env_jid[20];
+       char env_status[20];
+       char *envp[] = { env_jid, env_status, NULL };
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+        ls->ls_recover_jid_done = jid;
+        ls->ls_recover_jid_status = message;
+       sprintf(env_jid, "JID=%d", jid);
+       sprintf(env_status, "RECOVERY=%s",
+               message == LM_RD_SUCCESS ? "Done" : "Failed");
+        kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
-
 /**
- * gfs2_recover_journal - recovery a given journal
+ * gfs2_recover_journal - recover a given journal
  * @jd: the struct gfs2_jdesc describing the journal
  *
  * Acquire the journal's lock, check to see if the journal is clean, and
@@ -561,7 +563,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
        if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
                gfs2_glock_dq_uninit(&ji_gh);
 
-       gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
+       gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
 
        if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
                gfs2_glock_dq_uninit(&j_gh);
@@ -581,7 +583,7 @@ fail_gunlock_j:
        fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
 
 fail:
-       gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+       gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
        return error;
 }
 
index 8b01c635d9250ece1efdc007776287886dd48a41..f03d024038ea2974ffc43ba50daead1fd922bd82 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <linux/prefetch.h>
+#include <linux/blkdev.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -131,82 +131,91 @@ static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
        return cur_state;
 }
 
+/**
+ * gfs2_bit_search
+ * @ptr: Pointer to bitmap data
+ * @mask: Mask to use (normally 0x55555.... but adjusted for search start)
+ * @state: The state we are searching for
+ *
+ * We xor the bitmap data with a patter which is the bitwise opposite
+ * of what we are looking for, this gives rise to a pattern of ones
+ * wherever there is a match. Since we have two bits per entry, we
+ * take this pattern, shift it down by one place and then and it with
+ * the original. All the even bit positions (0,2,4, etc) then represent
+ * successful matches, so we mask with 0x55555..... to remove the unwanted
+ * odd bit positions.
+ *
+ * This allows searching of a whole u64 at once (32 blocks) with a
+ * single test (on 64 bit arches).
+ */
+
+static inline u64 gfs2_bit_search(const __le64 *ptr, u64 mask, u8 state)
+{
+       u64 tmp;
+       static const u64 search[] = {
+               [0] = 0xffffffffffffffffULL,
+               [1] = 0xaaaaaaaaaaaaaaaaULL,
+               [2] = 0x5555555555555555ULL,
+               [3] = 0x0000000000000000ULL,
+       };
+       tmp = le64_to_cpu(*ptr) ^ search[state];
+       tmp &= (tmp >> 1);
+       tmp &= mask;
+       return tmp;
+}
+
 /**
  * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
  *       a block in a given allocation state.
  * @buffer: the buffer that holds the bitmaps
- * @buflen: the length (in bytes) of the buffer
+ * @len: the length (in bytes) of the buffer
  * @goal: start search at this block's bit-pair (within @buffer)
- * @old_state: GFS2_BLKST_XXX the state of the block we're looking for.
+ * @state: GFS2_BLKST_XXX the state of the block we're looking for.
  *
  * Scope of @goal and returned block number is only within this bitmap buffer,
  * not entire rgrp or filesystem.  @buffer will be offset from the actual
- * beginning of a bitmap block buffer, skipping any header structures.
+ * beginning of a bitmap block buffer, skipping any header structures, but
+ * headers are always a multiple of 64 bits long so that the buffer is
+ * always aligned to a 64 bit boundary.
+ *
+ * The size of the buffer is in bytes, but is it assumed that it is
+ * always ok to to read a complete multiple of 64 bits at the end
+ * of the block in case the end is no aligned to a natural boundary.
  *
  * Return: the block number (bitmap buffer scope) that was found
  */
 
-static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal,
-                      u8 old_state)
+static u32 gfs2_bitfit(const u8 *buf, const unsigned int len,
+                      u32 goal, u8 state)
 {
-       const u8 *byte, *start, *end;
-       int bit, startbit;
-       u32 g1, g2, misaligned;
-       unsigned long *plong;
-       unsigned long lskipval;
-
-       lskipval = (old_state & GFS2_BLKST_USED) ? LBITSKIP00 : LBITSKIP55;
-       g1 = (goal / GFS2_NBBY);
-       start = buffer + g1;
-       byte = start;
-        end = buffer + buflen;
-       g2 = ALIGN(g1, sizeof(unsigned long));
-       plong = (unsigned long *)(buffer + g2);
-       startbit = bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
-       misaligned = g2 - g1;
-       if (!misaligned)
-               goto ulong_aligned;
-/* parse the bitmap a byte at a time */
-misaligned:
-       while (byte < end) {
-               if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) {
-                       return goal +
-                               (((byte - start) * GFS2_NBBY) +
-                                ((bit - startbit) >> 1));
-               }
-               bit += GFS2_BIT_SIZE;
-               if (bit >= GFS2_NBBY * GFS2_BIT_SIZE) {
-                       bit = 0;
-                       byte++;
-                       misaligned--;
-                       if (!misaligned) {
-                               plong = (unsigned long *)byte;
-                               goto ulong_aligned;
-                       }
-               }
-       }
-       return BFITNOENT;
-
-/* parse the bitmap a unsigned long at a time */
-ulong_aligned:
-       /* Stop at "end - 1" or else prefetch can go past the end and segfault.
-          We could "if" it but we'd lose some of the performance gained.
-          This way will only slow down searching the very last 4/8 bytes
-          depending on architecture.  I've experimented with several ways
-          of writing this section such as using an else before the goto
-          but this one seems to be the fastest. */
-       while ((unsigned char *)plong < end - sizeof(unsigned long)) {
-               prefetch(plong + 1);
-               if (((*plong) & LBITMASK) != lskipval)
-                       break;
-               plong++;
-       }
-       if ((unsigned char *)plong < end) {
-               byte = (const u8 *)plong;
-               misaligned += sizeof(unsigned long) - 1;
-               goto misaligned;
+       u32 spoint = (goal << 1) & ((8*sizeof(u64)) - 1);
+       const __le64 *ptr = ((__le64 *)buf) + (goal >> 5);
+       const __le64 *end = (__le64 *)(buf + ALIGN(len, sizeof(u64)));
+       u64 tmp;
+       u64 mask = 0x5555555555555555ULL;
+       u32 bit;
+
+       BUG_ON(state > 3);
+
+       /* Mask off bits we don't care about at the start of the search */
+       mask <<= spoint;
+       tmp = gfs2_bit_search(ptr, mask, state);
+       ptr++;
+       while(tmp == 0 && ptr < end) {
+               tmp = gfs2_bit_search(ptr, 0x5555555555555555ULL, state);
+               ptr++;
        }
-       return BFITNOENT;
+       /* Mask off any bits which are more than len bytes from the start */
+       if (ptr == end && (len & (sizeof(u64) - 1)))
+               tmp &= (((u64)~0) >> (64 - 8*(len & (sizeof(u64) - 1))));
+       /* Didn't find anything, so return */
+       if (tmp == 0)
+               return BFITNOENT;
+       ptr--;
+       bit = fls64(tmp);
+       bit--;          /* fls64 always adds one to the bit count */
+       bit /= 2;       /* two bits per entry in the bitmap */
+       return (((const unsigned char *)ptr - buf) * GFS2_NBBY) + bit;
 }
 
 /**
@@ -831,6 +840,58 @@ void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd)
        spin_unlock(&sdp->sd_rindex_spin);
 }
 
+static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+                                   const struct gfs2_bitmap *bi)
+{
+       struct super_block *sb = sdp->sd_vfs;
+       struct block_device *bdev = sb->s_bdev;
+       const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize /
+                                          bdev_hardsect_size(sb->s_bdev);
+       u64 blk;
+       sector_t start = 0;
+       sector_t nr_sects = 0;
+       int rv;
+       unsigned int x;
+
+       for (x = 0; x < bi->bi_len; x++) {
+               const u8 *orig = bi->bi_bh->b_data + bi->bi_offset + x;
+               const u8 *clone = bi->bi_clone + bi->bi_offset + x;
+               u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
+               diff &= 0x55;
+               if (diff == 0)
+                       continue;
+               blk = offset + ((bi->bi_start + x) * GFS2_NBBY);
+               blk *= sects_per_blk; /* convert to sectors */
+               while(diff) {
+                       if (diff & 1) {
+                               if (nr_sects == 0)
+                                       goto start_new_extent;
+                               if ((start + nr_sects) != blk) {
+                                       rv = blkdev_issue_discard(bdev, start,
+                                                           nr_sects, GFP_NOFS);
+                                       if (rv)
+                                               goto fail;
+                                       nr_sects = 0;
+start_new_extent:
+                                       start = blk;
+                               }
+                               nr_sects += sects_per_blk;
+                       }
+                       diff >>= 2;
+                       blk += sects_per_blk;
+               }
+       }
+       if (nr_sects) {
+               rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS);
+               if (rv)
+                       goto fail;
+       }
+       return;
+fail:
+       fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
+       sdp->sd_args.ar_discard = 0;
+}
+
 void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
 {
        struct gfs2_sbd *sdp = rgd->rd_sbd;
@@ -841,6 +902,8 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
                struct gfs2_bitmap *bi = rgd->rd_bits + x;
                if (!bi->bi_clone)
                        continue;
+               if (sdp->sd_args.ar_discard)
+                       gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi);
                memcpy(bi->bi_clone + bi->bi_offset,
                       bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
        }
index 141b781f2fccd10dede6cc27e04ead232af65f28..601913e0a482901099ebb495b230df8f7805cd92 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/crc32.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/bio.h>
-#include <linux/lm_interface.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -339,7 +338,6 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
                                    struct gfs2_holder *t_gh)
 {
        struct gfs2_inode *ip;
-       struct gfs2_holder ji_gh;
        struct gfs2_jdesc *jd;
        struct lfcc *lfcc;
        LIST_HEAD(list);
@@ -387,7 +385,6 @@ out:
                gfs2_glock_dq_uninit(&lfcc->gh);
                kfree(lfcc);
        }
-       gfs2_glock_dq_uninit(&ji_gh);
        return error;
 }
 
index f6b8b00ad8811b6b12c096f7214d563d8afe7e0c..91abdbedcc86e5524efaf8012313d05222a0d303 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/dcache.h>
 #include "incore.h"
 
-void gfs2_lm_unmount(struct gfs2_sbd *sdp);
+extern void gfs2_lm_unmount(struct gfs2_sbd *sdp);
 
 static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
 {
@@ -27,21 +27,23 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
 
 void gfs2_jindex_free(struct gfs2_sbd *sdp);
 
-struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
-int gfs2_jdesc_check(struct gfs2_jdesc *jd);
+extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data);
 
-int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
-                             struct gfs2_inode **ipp);
+extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
+extern int gfs2_jdesc_check(struct gfs2_jdesc *jd);
 
-int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
+extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
+                                    struct gfs2_inode **ipp);
 
-int gfs2_statfs_init(struct gfs2_sbd *sdp);
-void gfs2_statfs_change(struct gfs2_sbd *sdp,
-                       s64 total, s64 free, s64 dinodes);
-int gfs2_statfs_sync(struct gfs2_sbd *sdp);
+extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
 
-int gfs2_freeze_fs(struct gfs2_sbd *sdp);
-void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
+extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
+extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
+                              s64 dinodes);
+extern int gfs2_statfs_sync(struct gfs2_sbd *sdp);
+
+extern int gfs2_freeze_fs(struct gfs2_sbd *sdp);
+extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
 
 extern struct file_system_type gfs2_fs_type;
 extern struct file_system_type gfs2meta_fs_type;
index 26c1fa777a959f66f33755b977fa54f61ee04cfe..7655f5025fec4868e7d00e5790abb5d85394a926 100644 (file)
@@ -14,9 +14,8 @@
 #include <linux/buffer_head.h>
 #include <linux/module.h>
 #include <linux/kobject.h>
-#include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <asm/uaccess.h>
+#include <linux/gfs2_ondisk.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -25,6 +24,7 @@
 #include "glock.h"
 #include "quota.h"
 #include "util.h"
+#include "glops.h"
 
 static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
 {
@@ -37,6 +37,30 @@ static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
        return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname);
 }
 
+static int gfs2_uuid_valid(const u8 *uuid)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               if (uuid[i])
+                       return 1;
+       }
+       return 0;
+}
+
+static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)
+{
+       const u8 *uuid = sdp->sd_sb.sb_uuid;
+       buf[0] = '\0';
+       if (!gfs2_uuid_valid(uuid))
+               return 0;
+       return snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X-%02X%02X-"
+                       "%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
+                       uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
 static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
 {
        unsigned int count;
@@ -148,6 +172,46 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
        return len;
 }
 
+static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       struct gfs2_glock *gl;
+       const struct gfs2_glock_operations *glops;
+       unsigned int glmode;
+       unsigned int gltype;
+       unsigned long long glnum;
+       char mode[16];
+       int rv;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum,
+                   mode);
+       if (rv != 3)
+               return -EINVAL;
+
+       if (strcmp(mode, "EX") == 0)
+               glmode = LM_ST_UNLOCKED;
+       else if ((strcmp(mode, "CW") == 0) || (strcmp(mode, "DF") == 0))
+               glmode = LM_ST_DEFERRED;
+       else if ((strcmp(mode, "PR") == 0) || (strcmp(mode, "SH") == 0))
+               glmode = LM_ST_SHARED;
+       else
+               return -EINVAL;
+
+       if (gltype > LM_TYPE_JOURNAL)
+               return -EINVAL;
+       glops = gfs2_glops_list[gltype];
+       if (glops == NULL)
+               return -EINVAL;
+       rv = gfs2_glock_get(sdp, glnum, glops, 0, &gl);
+       if (rv)
+               return rv;
+       gfs2_glock_cb(gl, glmode);
+       gfs2_glock_put(gl);
+       return len;
+}
+
 struct gfs2_attr {
        struct attribute attr;
        ssize_t (*show)(struct gfs2_sbd *, char *);
@@ -159,22 +223,26 @@ static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store)
 
 GFS2_ATTR(id,                  0444, id_show,       NULL);
 GFS2_ATTR(fsname,              0444, fsname_show,   NULL);
+GFS2_ATTR(uuid,                0444, uuid_show,     NULL);
 GFS2_ATTR(freeze,              0644, freeze_show,   freeze_store);
 GFS2_ATTR(withdraw,            0644, withdraw_show, withdraw_store);
 GFS2_ATTR(statfs_sync,         0200, NULL,          statfs_sync_store);
 GFS2_ATTR(quota_sync,          0200, NULL,          quota_sync_store);
 GFS2_ATTR(quota_refresh_user,  0200, NULL,          quota_refresh_user_store);
 GFS2_ATTR(quota_refresh_group, 0200, NULL,          quota_refresh_group_store);
+GFS2_ATTR(demote_rq,           0200, NULL,         demote_rq_store);
 
 static struct attribute *gfs2_attrs[] = {
        &gfs2_attr_id.attr,
        &gfs2_attr_fsname.attr,
+       &gfs2_attr_uuid.attr,
        &gfs2_attr_freeze.attr,
        &gfs2_attr_withdraw.attr,
        &gfs2_attr_statfs_sync.attr,
        &gfs2_attr_quota_sync.attr,
        &gfs2_attr_quota_refresh_user.attr,
        &gfs2_attr_quota_refresh_group.attr,
+       &gfs2_attr_demote_rq.attr,
        NULL,
 };
 
@@ -224,14 +292,145 @@ static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name)
 
 LOCKSTRUCT_ATTR(jid,      "%u\n");
 LOCKSTRUCT_ATTR(first,    "%u\n");
-LOCKSTRUCT_ATTR(lvb_size, "%u\n");
-LOCKSTRUCT_ATTR(flags,    "%d\n");
 
 static struct attribute *lockstruct_attrs[] = {
        &lockstruct_attr_jid.attr,
        &lockstruct_attr_first.attr,
-       &lockstruct_attr_lvb_size.attr,
-       &lockstruct_attr_flags.attr,
+       NULL,
+};
+
+/*
+ * lock_module. Originally from lock_dlm
+ */
+
+static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf)
+{
+       const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops;
+       return sprintf(buf, "%s\n", ops->lm_proto_name);
+}
+
+static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       ssize_t ret;
+       int val = 0;
+
+       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))
+               val = 1;
+       ret = sprintf(buf, "%d\n", val);
+       return ret;
+}
+
+static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       ssize_t ret = len;
+       int val;
+
+       val = simple_strtol(buf, NULL, 0);
+
+       if (val == 1)
+               set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+       else if (val == 0) {
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+               smp_mb__after_clear_bit();
+               gfs2_glock_thaw(sdp);
+       } else {
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static ssize_t lkid_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%u\n", ls->ls_id);
+}
+
+static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%d\n", ls->ls_first);
+}
+
+static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%d\n", ls->ls_first_done);
+}
+
+static ssize_t recover_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%d\n", ls->ls_recover_jid);
+}
+
+static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
+{
+       struct gfs2_jdesc *jd;
+
+       spin_lock(&sdp->sd_jindex_spin);
+       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+               if (jd->jd_jid != jid)
+                       continue;
+               jd->jd_dirty = 1;
+               break;
+       }
+       spin_unlock(&sdp->sd_jindex_spin);
+}
+
+static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       ls->ls_recover_jid = simple_strtol(buf, NULL, 0);
+       gfs2_jdesc_make_dirty(sdp, ls->ls_recover_jid);
+       if (sdp->sd_recoverd_process)
+               wake_up_process(sdp->sd_recoverd_process);
+       return len;
+}
+
+static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%d\n", ls->ls_recover_jid_done);
+}
+
+static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sprintf(buf, "%d\n", ls->ls_recover_jid_status);
+}
+
+struct gdlm_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct gfs2_sbd *sdp, char *);
+       ssize_t (*store)(struct gfs2_sbd *sdp, const char *, size_t);
+};
+
+#define GDLM_ATTR(_name,_mode,_show,_store) \
+static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+GDLM_ATTR(proto_name,     0444, proto_name_show,     NULL);
+GDLM_ATTR(block,          0644, block_show,          block_store);
+GDLM_ATTR(withdraw,       0644, withdraw_show,       withdraw_store);
+GDLM_ATTR(id,             0444, lkid_show,           NULL);
+GDLM_ATTR(first,          0444, lkfirst_show,        NULL);
+GDLM_ATTR(first_done,     0444, first_done_show,     NULL);
+GDLM_ATTR(recover,        0644, recover_show,        recover_store);
+GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
+GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+
+static struct attribute *lock_module_attrs[] = {
+       &gdlm_attr_proto_name.attr,
+       &gdlm_attr_block.attr,
+       &gdlm_attr_withdraw.attr,
+       &gdlm_attr_id.attr,
+       &lockstruct_attr_jid.attr,
+       &gdlm_attr_first.attr,
+       &gdlm_attr_first_done.attr,
+       &gdlm_attr_recover.attr,
+       &gdlm_attr_recover_done.attr,
+       &gdlm_attr_recover_status.attr,
        NULL,
 };
 
@@ -373,7 +572,6 @@ TUNE_ATTR(complain_secs, 0);
 TUNE_ATTR(statfs_slow, 0);
 TUNE_ATTR(new_files_jdata, 0);
 TUNE_ATTR(quota_simul_sync, 1);
-TUNE_ATTR(quota_cache_secs, 1);
 TUNE_ATTR(stall_secs, 1);
 TUNE_ATTR(statfs_quantum, 1);
 TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
@@ -389,7 +587,6 @@ static struct attribute *tune_attrs[] = {
        &tune_attr_complain_secs.attr,
        &tune_attr_statfs_slow.attr,
        &tune_attr_quota_simul_sync.attr,
-       &tune_attr_quota_cache_secs.attr,
        &tune_attr_stall_secs.attr,
        &tune_attr_statfs_quantum.attr,
        &tune_attr_recoverd_secs.attr,
@@ -414,6 +611,11 @@ static struct attribute_group tune_group = {
        .attrs = tune_attrs,
 };
 
+static struct attribute_group lock_module_group = {
+       .name = "lock_module",
+       .attrs = lock_module_attrs,
+};
+
 int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 {
        int error;
@@ -436,9 +638,15 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
        if (error)
                goto fail_args;
 
+       error = sysfs_create_group(&sdp->sd_kobj, &lock_module_group);
+       if (error)
+               goto fail_tune;
+
        kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
        return 0;
 
+fail_tune:
+       sysfs_remove_group(&sdp->sd_kobj, &tune_group);
 fail_args:
        sysfs_remove_group(&sdp->sd_kobj, &args_group);
 fail_lockstruct:
@@ -455,15 +663,27 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
        sysfs_remove_group(&sdp->sd_kobj, &tune_group);
        sysfs_remove_group(&sdp->sd_kobj, &args_group);
        sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+       sysfs_remove_group(&sdp->sd_kobj, &lock_module_group);
        kobject_put(&sdp->sd_kobj);
 }
 
+
 static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
                       struct kobj_uevent_env *env)
 {
        struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+       const u8 *uuid = sdp->sd_sb.sb_uuid;
+
        add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
        add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
+       if (gfs2_uuid_valid(uuid)) {
+               add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+                              "%02X%02X-%02X%02X%02X%02X%02X%02X",
+                              uuid[0], uuid[1], uuid[2], uuid[3], uuid[4],
+                              uuid[5], uuid[6], uuid[7], uuid[8], uuid[9],
+                              uuid[10], uuid[11], uuid[12], uuid[13],
+                              uuid[14], uuid[15]);
+       }
        return 0;
 }
 
index f677b8a83f0cc2d0d3cb7c1ebbee47908620a440..053752d4b27f0c3dc52578c5066245e0fb793c69 100644 (file)
@@ -12,9 +12,8 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
-#include <linux/gfs2_ondisk.h>
 #include <linux/kallsyms.h>
-#include <linux/lm_interface.h>
+#include <linux/gfs2_ondisk.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -88,9 +87,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 
        if (!tr->tr_touched) {
                gfs2_log_release(sdp, tr->tr_reserved);
-               gfs2_glock_dq(&tr->tr_t_gh);
-               gfs2_holder_uninit(&tr->tr_t_gh);
-               kfree(tr);
+               if (tr->tr_t_gh.gh_gl) {
+                       gfs2_glock_dq(&tr->tr_t_gh);
+                       gfs2_holder_uninit(&tr->tr_t_gh);
+                       kfree(tr);
+               }
                return;
        }
 
@@ -106,9 +107,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
        }
 
        gfs2_log_commit(sdp, tr);
-        gfs2_glock_dq(&tr->tr_t_gh);
-        gfs2_holder_uninit(&tr->tr_t_gh);
-        kfree(tr);
+       if (tr->tr_t_gh.gh_gl) {
+               gfs2_glock_dq(&tr->tr_t_gh);
+               gfs2_holder_uninit(&tr->tr_t_gh);
+               kfree(tr);
+       }
 
        if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
                gfs2_log_flush(sdp, NULL);
index 374f50e954967a147e56dffe2eec590c9fc087bc..9d12b1118ba0311b35362124b959cd966054a614 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/buffer_head.h>
 #include <linux/crc32.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
@@ -35,6 +34,8 @@ void gfs2_assert_i(struct gfs2_sbd *sdp)
 
 int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
 {
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       const struct lm_lockops *lm = ls->ls_ops;
        va_list args;
 
        if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
@@ -47,8 +48,12 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
        fs_err(sdp, "about to withdraw this file system\n");
        BUG_ON(sdp->sd_args.ar_debug);
 
-       fs_err(sdp, "telling LM to withdraw\n");
-       gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
+       kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
+
+       if (lm->lm_unmount) {
+               fs_err(sdp, "telling LM to unmount\n");
+               lm->lm_unmount(sdp);
+       }
        fs_err(sdp, "withdrawn\n");
        dump_stack();
 
index 826fb0b9d1c38f4dbe4ad16c6ec938a7e31cdc88..643ac43e5a5c7d6f43fe938fd4c0df6c91e2e0ce 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
@@ -147,13 +148,13 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_cdev = NULL;
        inode->i_rdev = 0;
        inode->dirtied_when = 0;
-       if (security_inode_alloc(inode)) {
-               if (inode->i_sb->s_op->destroy_inode)
-                       inode->i_sb->s_op->destroy_inode(inode);
-               else
-                       kmem_cache_free(inode_cachep, (inode));
-               return NULL;
-       }
+
+       if (security_inode_alloc(inode))
+               goto out_free_inode;
+
+       /* allocate and initialize an i_integrity */
+       if (ima_inode_alloc(inode))
+               goto out_free_security;
 
        spin_lock_init(&inode->i_lock);
        lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -189,6 +190,15 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_mapping = mapping;
 
        return inode;
+
+out_free_security:
+       security_inode_free(inode);
+out_free_inode:
+       if (inode->i_sb->s_op->destroy_inode)
+               inode->i_sb->s_op->destroy_inode(inode);
+       else
+               kmem_cache_free(inode_cachep, (inode));
+       return NULL;
 }
 EXPORT_SYMBOL(inode_init_always);
 
@@ -1290,6 +1300,40 @@ sector_t bmap(struct inode * inode, sector_t block)
 }
 EXPORT_SYMBOL(bmap);
 
+/*
+ * With relative atime, only update atime if the previous atime is
+ * earlier than either the ctime or mtime or if at least a day has
+ * passed since the last atime update.
+ */
+static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
+                            struct timespec now)
+{
+
+       if (!(mnt->mnt_flags & MNT_RELATIME))
+               return 1;
+       /*
+        * Is mtime younger than atime? If yes, update atime:
+        */
+       if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0)
+               return 1;
+       /*
+        * Is ctime younger than atime? If yes, update atime:
+        */
+       if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0)
+               return 1;
+
+       /*
+        * Is the previous atime value older than a day? If yes,
+        * update atime:
+        */
+       if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60)
+               return 1;
+       /*
+        * Good, we can skip the atime update:
+        */
+       return 0;
+}
+
 /**
  *     touch_atime     -       update the access time
  *     @mnt: mount the inode is accessed on
@@ -1317,17 +1361,12 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
                goto out;
        if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
                goto out;
-       if (mnt->mnt_flags & MNT_RELATIME) {
-               /*
-                * With relative atime, only update atime if the previous
-                * atime is earlier than either the ctime or mtime.
-                */
-               if (timespec_compare(&inode->i_mtime, &inode->i_atime) < 0 &&
-                   timespec_compare(&inode->i_ctime, &inode->i_atime) < 0)
-                       goto out;
-       }
 
        now = current_fs_time(inode->i_sb);
+
+       if (!relatime_need_update(mnt, inode, now))
+               goto out;
+
        if (timespec_equal(&inode->i_atime, &now))
                goto out;
 
index bbc15c237558f82c7fbe2b661e55ee8fa1b9849d..199317642ad6d731f47dd61693a2374145f99337 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fsnotify.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/syscalls.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
@@ -850,6 +851,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
                if (err == -EAGAIN)
                        err = inode_permission(nd->path.dentry->d_inode,
                                               MAY_EXEC);
+               if (!err)
+                       err = ima_path_check(&nd->path, MAY_EXEC);
                if (err)
                        break;
 
@@ -1509,6 +1512,11 @@ int may_open(struct path *path, int acc_mode, int flag)
        error = inode_permission(inode, acc_mode);
        if (error)
                return error;
+
+       error = ima_path_check(path,
+                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
+       if (error)
+               return error;
        /*
         * An append-only file must be opened in append mode for writing.
         */
index 06f8e63f6cb1dc929e0ad9c0627320066db57cb1..f0e753097353b93f581d1ea6e1646df99dcf630a 100644 (file)
@@ -780,6 +780,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
                { MNT_NOATIME, ",noatime" },
                { MNT_NODIRATIME, ",nodiratime" },
                { MNT_RELATIME, ",relatime" },
+               { MNT_STRICTATIME, ",strictatime" },
                { 0, NULL }
        };
        const struct proc_fs_info *fs_infop;
@@ -1919,6 +1920,9 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
        if (data_page)
                ((char *)data_page)[PAGE_SIZE - 1] = 0;
 
+       /* Default to relatime */
+       mnt_flags |= MNT_RELATIME;
+
        /* Separate the per-mountpoint flags */
        if (flags & MS_NOSUID)
                mnt_flags |= MNT_NOSUID;
@@ -1930,13 +1934,14 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
                mnt_flags |= MNT_NOATIME;
        if (flags & MS_NODIRATIME)
                mnt_flags |= MNT_NODIRATIME;
-       if (flags & MS_RELATIME)
-               mnt_flags |= MNT_RELATIME;
+       if (flags & MS_STRICTATIME)
+               mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
        if (flags & MS_RDONLY)
                mnt_flags |= MNT_READONLY;
 
        flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
-                  MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT);
+                  MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
+                  MS_STRICTATIME);
 
        /* ... and get the mountpoint */
        retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
index 6d720243f5f4a29a43a7b50dd005bbff32a7b0aa..38e337d51ced527842a1b86c8193f7983be260b0 100644 (file)
@@ -400,7 +400,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        pdev->devt = devt;
 
        /* delay uevent until 'holders' subdir is created */
-       pdev->uevent_suppress = 1;
+       dev_set_uevent_suppress(pdev, 1);
        err = device_add(pdev);
        if (err)
                goto out_put;
@@ -410,7 +410,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        if (!p->holder_dir)
                goto out_del;
 
-       pdev->uevent_suppress = 0;
+       dev_set_uevent_suppress(pdev, 0);
        if (flags & ADDPART_FLAG_WHOLEDISK) {
                err = device_create_file(pdev, &dev_attr_whole_disk);
                if (err)
@@ -422,7 +422,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        rcu_assign_pointer(ptbl->part[partno], p);
 
        /* suppress uevent if the disk supresses it */
-       if (!ddev->uevent_suppress)
+       if (!dev_get_uevent_suppress(pdev))
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
        return p;
@@ -455,7 +455,7 @@ void register_disk(struct gendisk *disk)
        dev_set_name(ddev, disk->disk_name);
 
        /* delay uevents, until we scanned partition table */
-       ddev->uevent_suppress = 1;
+       dev_set_uevent_suppress(ddev, 1);
 
        if (device_add(ddev))
                return;
@@ -490,7 +490,7 @@ void register_disk(struct gendisk *disk)
 
 exit:
        /* announce disk after possible partitions are created */
-       ddev->uevent_suppress = 0;
+       dev_set_uevent_suppress(ddev, 0);
        kobject_uevent(&ddev->kobj, KOBJ_ADD);
 
        /* announce possible partitions */
index f2c478c3424e6f40096049206c4b3e181f37d211..07703d3ff4a1ebdb8729bfcbfd7d759a7afbc06a 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 
 #include "sysfs.h"
 
+/*
+ * There's one bin_buffer for each open file.
+ *
+ * filp->private_data points to bin_buffer and
+ * sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s
+ * sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock
+ */
+static DEFINE_MUTEX(sysfs_bin_lock);
+
 struct bin_buffer {
-       struct mutex    mutex;
-       void            *buffer;
-       int             mmapped;
+       struct mutex                    mutex;
+       void                            *buffer;
+       int                             mmapped;
+       struct vm_operations_struct     *vm_ops;
+       struct file                     *file;
+       struct hlist_node               list;
 };
 
 static int
@@ -168,6 +181,175 @@ out_free:
        return count;
 }
 
+static void bin_vma_open(struct vm_area_struct *vma)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+
+       if (!bb->vm_ops || !bb->vm_ops->open)
+               return;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return;
+
+       bb->vm_ops->open(vma);
+
+       sysfs_put_active_two(attr_sd);
+}
+
+static void bin_vma_close(struct vm_area_struct *vma)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+
+       if (!bb->vm_ops || !bb->vm_ops->close)
+               return;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return;
+
+       bb->vm_ops->close(vma);
+
+       sysfs_put_active_two(attr_sd);
+}
+
+static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       int ret;
+
+       if (!bb->vm_ops || !bb->vm_ops->fault)
+               return VM_FAULT_SIGBUS;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return VM_FAULT_SIGBUS;
+
+       ret = bb->vm_ops->fault(vma, vmf);
+
+       sysfs_put_active_two(attr_sd);
+       return ret;
+}
+
+static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       int ret;
+
+       if (!bb->vm_ops)
+               return -EINVAL;
+
+       if (!bb->vm_ops->page_mkwrite)
+               return 0;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return -EINVAL;
+
+       ret = bb->vm_ops->page_mkwrite(vma, page);
+
+       sysfs_put_active_two(attr_sd);
+       return ret;
+}
+
+static int bin_access(struct vm_area_struct *vma, unsigned long addr,
+                 void *buf, int len, int write)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       int ret;
+
+       if (!bb->vm_ops || !bb->vm_ops->access)
+               return -EINVAL;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return -EINVAL;
+
+       ret = bb->vm_ops->access(vma, addr, buf, len, write);
+
+       sysfs_put_active_two(attr_sd);
+       return ret;
+}
+
+#ifdef CONFIG_NUMA
+static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       int ret;
+
+       if (!bb->vm_ops || !bb->vm_ops->set_policy)
+               return 0;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return -EINVAL;
+
+       ret = bb->vm_ops->set_policy(vma, new);
+
+       sysfs_put_active_two(attr_sd);
+       return ret;
+}
+
+static struct mempolicy *bin_get_policy(struct vm_area_struct *vma,
+                                       unsigned long addr)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       struct mempolicy *pol;
+
+       if (!bb->vm_ops || !bb->vm_ops->get_policy)
+               return vma->vm_policy;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return vma->vm_policy;
+
+       pol = bb->vm_ops->get_policy(vma, addr);
+
+       sysfs_put_active_two(attr_sd);
+       return pol;
+}
+
+static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from,
+                       const nodemask_t *to, unsigned long flags)
+{
+       struct file *file = vma->vm_file;
+       struct bin_buffer *bb = file->private_data;
+       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+       int ret;
+
+       if (!bb->vm_ops || !bb->vm_ops->migrate)
+               return 0;
+
+       if (!sysfs_get_active_two(attr_sd))
+               return 0;
+
+       ret = bb->vm_ops->migrate(vma, from, to, flags);
+
+       sysfs_put_active_two(attr_sd);
+       return ret;
+}
+#endif
+
+static struct vm_operations_struct bin_vm_ops = {
+       .open           = bin_vma_open,
+       .close          = bin_vma_close,
+       .fault          = bin_fault,
+       .page_mkwrite   = bin_page_mkwrite,
+       .access         = bin_access,
+#ifdef CONFIG_NUMA
+       .set_policy     = bin_set_policy,
+       .get_policy     = bin_get_policy,
+       .migrate        = bin_migrate,
+#endif
+};
+
 static int mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct bin_buffer *bb = file->private_data;
@@ -179,18 +361,37 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
        mutex_lock(&bb->mutex);
 
        /* need attr_sd for attr, its parent for kobj */
+       rc = -ENODEV;
        if (!sysfs_get_active_two(attr_sd))
-               return -ENODEV;
+               goto out_unlock;
 
        rc = -EINVAL;
-       if (attr->mmap)
-               rc = attr->mmap(kobj, attr, vma);
+       if (!attr->mmap)
+               goto out_put;
+
+       rc = attr->mmap(kobj, attr, vma);
+       if (rc)
+               goto out_put;
 
-       if (rc == 0 && !bb->mmapped)
-               bb->mmapped = 1;
-       else
-               sysfs_put_active_two(attr_sd);
+       /*
+        * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup()
+        * to satisfy versions of X which crash if the mmap fails: that
+        * substitutes a new vm_file, and we don't then want bin_vm_ops.
+        */
+       if (vma->vm_file != file)
+               goto out_put;
 
+       rc = -EINVAL;
+       if (bb->mmapped && bb->vm_ops != vma->vm_ops)
+               goto out_put;
+
+       rc = 0;
+       bb->mmapped = 1;
+       bb->vm_ops = vma->vm_ops;
+       vma->vm_ops = &bin_vm_ops;
+out_put:
+       sysfs_put_active_two(attr_sd);
+out_unlock:
        mutex_unlock(&bb->mutex);
 
        return rc;
@@ -223,8 +424,13 @@ static int open(struct inode * inode, struct file * file)
                goto err_out;
 
        mutex_init(&bb->mutex);
+       bb->file = file;
        file->private_data = bb;
 
+       mutex_lock(&sysfs_bin_lock);
+       hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers);
+       mutex_unlock(&sysfs_bin_lock);
+
        /* open succeeded, put active references */
        sysfs_put_active_two(attr_sd);
        return 0;
@@ -237,11 +443,12 @@ static int open(struct inode * inode, struct file * file)
 
 static int release(struct inode * inode, struct file * file)
 {
-       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
        struct bin_buffer *bb = file->private_data;
 
-       if (bb->mmapped)
-               sysfs_put_active_two(attr_sd);
+       mutex_lock(&sysfs_bin_lock);
+       hlist_del(&bb->list);
+       mutex_unlock(&sysfs_bin_lock);
+
        kfree(bb->buffer);
        kfree(bb);
        return 0;
@@ -256,6 +463,26 @@ const struct file_operations bin_fops = {
        .release        = release,
 };
 
+
+void unmap_bin_file(struct sysfs_dirent *attr_sd)
+{
+       struct bin_buffer *bb;
+       struct hlist_node *tmp;
+
+       if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR)
+               return;
+
+       mutex_lock(&sysfs_bin_lock);
+
+       hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) {
+               struct inode *inode = bb->file->f_path.dentry->d_inode;
+
+               unmap_mapping_range(inode->i_mapping, 0, 0, 1);
+       }
+
+       mutex_unlock(&sysfs_bin_lock);
+}
+
 /**
  *     sysfs_create_bin_file - create binary file for object.
  *     @kobj:  object.
index 82d3b79d0e080765fb3ceb43fae1549ffe7df96d..66aeb4fff0c32372968cfe3ac63f0ad0a5f00765 100644 (file)
@@ -433,6 +433,26 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
        return 0;
 }
 
+/**
+ *     sysfs_pathname - return full path to sysfs dirent
+ *     @sd: sysfs_dirent whose path we want
+ *     @path: caller allocated buffer
+ *
+ *     Gives the name "/" to the sysfs_root entry; any path returned
+ *     is relative to wherever sysfs is mounted.
+ *
+ *     XXX: does no error checking on @path size
+ */
+static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)
+{
+       if (sd->s_parent) {
+               sysfs_pathname(sd->s_parent, path);
+               strcat(path, "/");
+       }
+       strcat(path, sd->s_name);
+       return path;
+}
+
 /**
  *     sysfs_add_one - add sysfs_dirent to parent
  *     @acxt: addrm context to use
@@ -458,8 +478,16 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
        int ret;
 
        ret = __sysfs_add_one(acxt, sd);
-       WARN(ret == -EEXIST, KERN_WARNING "sysfs: duplicate filename '%s' "
-                      "can not be created\n", sd->s_name);
+       if (ret == -EEXIST) {
+               char *path = kzalloc(PATH_MAX, GFP_KERNEL);
+               WARN(1, KERN_WARNING
+                    "sysfs: cannot create duplicate filename '%s'\n",
+                    (path == NULL) ? sd->s_name :
+                    strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),
+                           sd->s_name));
+               kfree(path);
+       }
+
        return ret;
 }
 
@@ -581,6 +609,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
 
                sysfs_drop_dentry(sd);
                sysfs_deactivate(sd);
+               unmap_bin_file(sd);
                sysfs_put(sd);
        }
 }
index 1f4a3f877262f5f6fbf34085f688e50b42471c8e..289c43a472634e5863c356502adeea451c0da882 100644 (file)
@@ -659,13 +659,16 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
 
 struct sysfs_schedule_callback_struct {
-       struct kobject          *kobj;
+       struct list_head        workq_list;
+       struct kobject          *kobj;
        void                    (*func)(void *);
        void                    *data;
        struct module           *owner;
        struct work_struct      work;
 };
 
+static DEFINE_MUTEX(sysfs_workq_mutex);
+static LIST_HEAD(sysfs_workq);
 static void sysfs_schedule_callback_work(struct work_struct *work)
 {
        struct sysfs_schedule_callback_struct *ss = container_of(work,
@@ -674,6 +677,9 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
        (ss->func)(ss->data);
        kobject_put(ss->kobj);
        module_put(ss->owner);
+       mutex_lock(&sysfs_workq_mutex);
+       list_del(&ss->workq_list);
+       mutex_unlock(&sysfs_workq_mutex);
        kfree(ss);
 }
 
@@ -695,15 +701,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
  * until @func returns.
  *
  * Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated, -ENODEV if a reference to @owner isn't available.
+ * be allocated, -ENODEV if a reference to @owner isn't available,
+ * -EAGAIN if a callback has already been scheduled for @kobj.
  */
 int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
                void *data, struct module *owner)
 {
-       struct sysfs_schedule_callback_struct *ss;
+       struct sysfs_schedule_callback_struct *ss, *tmp;
 
        if (!try_module_get(owner))
                return -ENODEV;
+
+       mutex_lock(&sysfs_workq_mutex);
+       list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list)
+               if (ss->kobj == kobj) {
+                       mutex_unlock(&sysfs_workq_mutex);
+                       return -EAGAIN;
+               }
+       mutex_unlock(&sysfs_workq_mutex);
+
        ss = kmalloc(sizeof(*ss), GFP_KERNEL);
        if (!ss) {
                module_put(owner);
@@ -715,6 +731,10 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
        ss->data = data;
        ss->owner = owner;
        INIT_WORK(&ss->work, sysfs_schedule_callback_work);
+       INIT_LIST_HEAD(&ss->workq_list);
+       mutex_lock(&sysfs_workq_mutex);
+       list_add_tail(&ss->workq_list, &sysfs_workq);
+       mutex_unlock(&sysfs_workq_mutex);
        schedule_work(&ss->work);
        return 0;
 }
index dfa3d94cfc74a33b5bf342ea1a5e7c9ad346109c..555f0ff988df1379638d0372ebced2349db25848 100644 (file)
@@ -147,6 +147,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
        struct bin_attribute *bin_attr;
 
+       inode->i_private = sysfs_get(sd);
        inode->i_mapping->a_ops = &sysfs_aops;
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
        inode->i_op = &sysfs_inode_operations;
@@ -214,6 +215,22 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
        return inode;
 }
 
+/*
+ * The sysfs_dirent serves as both an inode and a directory entry for sysfs.
+ * To prevent the sysfs inode numbers from being freed prematurely we take a
+ * reference to sysfs_dirent from the sysfs inode.  A
+ * super_operations.delete_inode() implementation is needed to drop that
+ * reference upon inode destruction.
+ */
+void sysfs_delete_inode(struct inode *inode)
+{
+       struct sysfs_dirent *sd  = inode->i_private;
+
+       truncate_inode_pages(&inode->i_data, 0);
+       clear_inode(inode);
+       sysfs_put(sd);
+}
+
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 {
        struct sysfs_addrm_cxt acxt;
index ab343e371d64682f678646ed02615171e73b2d31..49749955ccafe8b9f4b6dd4393ed5a3a2f92037e 100644 (file)
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/magic.h>
 
 #include "sysfs.h"
 
-/* Random magic number */
-#define SYSFS_MAGIC 0x62656572
 
 static struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
@@ -30,6 +29,7 @@ struct kmem_cache *sysfs_dir_cachep;
 static const struct super_operations sysfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
+       .delete_inode   = sysfs_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
@@ -53,7 +53,9 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
        sysfs_sb = sb;
 
        /* get root inode, initialize and unlock it */
+       mutex_lock(&sysfs_mutex);
        inode = sysfs_get_inode(&sysfs_root);
+       mutex_unlock(&sysfs_mutex);
        if (!inode) {
                pr_debug("sysfs: could not get root inode\n");
                return -ENOMEM;
index 93c6d6b27c4ded5596c783ac1bdbe4e4b2590bbd..3fa0d98481e2253bd444c1656a50f96d35a150a7 100644 (file)
@@ -28,6 +28,7 @@ struct sysfs_elem_attr {
 
 struct sysfs_elem_bin_attr {
        struct bin_attribute    *bin_attr;
+       struct hlist_head       buffers;
 };
 
 /*
@@ -145,6 +146,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
  * inode.c
  */
 struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
+void sysfs_delete_inode(struct inode *inode);
 int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
 int sysfs_inode_init(void);
@@ -163,6 +165,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
  * bin.c
  */
 extern const struct file_operations bin_fops;
+void unmap_bin_file(struct sysfs_dirent *attr_sd);
 
 /*
  * symlink.c
diff --git a/include/asm-frv/ide.h b/include/asm-frv/ide.h
deleted file mode 100644 (file)
index 3610766..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* ide.h: FRV IDE declarations
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _ASM_IDE_H
-#define _ASM_IDE_H
-
-#ifdef __KERNEL__
-
-#include <asm/setup.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <asm-generic/ide_iops.h>
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_IDE_H */
index c61fab1dd2f82cbde0df850274a595d4c79aa450..aca40b93bd28f604f12d9f04d8443277a6f3dba0 100644 (file)
        VMLINUX_SYMBOL(__start___tracepoints) = .;                      \
        *(__tracepoints)                                                \
        VMLINUX_SYMBOL(__stop___tracepoints) = .;                       \
+       /* implement dynamic printk debug */                            \
+       . = ALIGN(8);                                                   \
+       VMLINUX_SYMBOL(__start___verbose) = .;                          \
+       *(__verbose)                                                    \
+       VMLINUX_SYMBOL(__stop___verbose) = .;                           \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()
 
        CPU_DISCARD(init.data)                                          \
        CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.data)                                          \
-       MEM_DISCARD(init.rodata)                                        \
-       /* implement dynamic printk debug */                            \
-       VMLINUX_SYMBOL(__start___verbose_strings) = .;                  \
-       *(__verbose_strings)                                            \
-       VMLINUX_SYMBOL(__stop___verbose_strings) = .;                   \
-       . = ALIGN(8);                                                   \
-       VMLINUX_SYMBOL(__start___verbose) = .;                          \
-       *(__verbose)                                                    \
-       VMLINUX_SYMBOL(__stop___verbose) = .;
+       MEM_DISCARD(init.rodata)
 
 #define INIT_TEXT                                                      \
        *(.init.text)                                                   \
diff --git a/include/asm-mn10300/ide.h b/include/asm-mn10300/ide.h
deleted file mode 100644 (file)
index 6adcdd9..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* MN10300 Arch-specific IDE code
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- * - Derived from include/asm-i386/ide.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _ASM_IDE_H
-#define _ASM_IDE_H
-
-#ifdef __KERNEL__
-
-#include <asm/intctl-regs.h>
-
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS 0
-
-#undef SUPPORT_VLB_SYNC
-#define SUPPORT_VLB_SYNC 0
-
-/*
- * some bits needed for parts of the IDE subsystem to compile
- */
-#define __ide_mm_insw(port, addr, n) \
-       insw((unsigned long) (port), (addr), (n))
-#define __ide_mm_insl(port, addr, n) \
-       insl((unsigned long) (port), (addr), (n))
-#define __ide_mm_outsw(port, addr, n) \
-       outsw((unsigned long) (port), (addr), (n))
-#define __ide_mm_outsl(port, addr, n) \
-       outsl((unsigned long) (port), (addr), (n))
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_IDE_H */
index cd9cc5c89cea9f524c5d1b4db02f45daff950231..0517b45313d862e9107367d84d87233554389611 100644 (file)
@@ -121,4 +121,9 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 
 #define pcibios_scan_all_fns(a, b)     0
 
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+       return channel ? 15 : 14;
+}
+
 #endif /* _ASM_PCI_H */
index 656a4c66a568f39cf769210bbfaab6d7dc6c7a07..7524ba3b6f3c8f2c028215e926afd960297a3728 100644 (file)
 #define AES_MAX_KEYLENGTH      (15 * 16)
 #define AES_MAX_KEYLENGTH_U32  (AES_MAX_KEYLENGTH / sizeof(u32))
 
+/*
+ * Please ensure that the first two fields are 16-byte aligned
+ * relative to the start of the structure, i.e., don't move them!
+ */
 struct crypto_aes_ctx {
-       u32 key_length;
        u32 key_enc[AES_MAX_KEYLENGTH_U32];
        u32 key_dec[AES_MAX_KEYLENGTH_U32];
+       u32 key_length;
 };
 
 extern const u32 crypto_ft_tab[4][256];
diff --git a/include/crypto/compress.h b/include/crypto/compress.h
new file mode 100644 (file)
index 0000000..86163ef
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Compress: Compression algorithms under the cryptographic API.
+ *
+ * Copyright 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CRYPTO_COMPRESS_H
+#define _CRYPTO_COMPRESS_H
+
+#include <linux/crypto.h>
+
+
+struct comp_request {
+       const void *next_in;            /* next input byte */
+       void *next_out;                 /* next output byte */
+       unsigned int avail_in;          /* bytes available at next_in */
+       unsigned int avail_out;         /* bytes available at next_out */
+};
+
+enum zlib_comp_params {
+       ZLIB_COMP_LEVEL = 1,            /* e.g. Z_DEFAULT_COMPRESSION */
+       ZLIB_COMP_METHOD,               /* e.g. Z_DEFLATED */
+       ZLIB_COMP_WINDOWBITS,           /* e.g. MAX_WBITS */
+       ZLIB_COMP_MEMLEVEL,             /* e.g. DEF_MEM_LEVEL */
+       ZLIB_COMP_STRATEGY,             /* e.g. Z_DEFAULT_STRATEGY */
+       __ZLIB_COMP_MAX,
+};
+
+#define ZLIB_COMP_MAX  (__ZLIB_COMP_MAX - 1)
+
+
+enum zlib_decomp_params {
+       ZLIB_DECOMP_WINDOWBITS = 1,     /* e.g. DEF_WBITS */
+       __ZLIB_DECOMP_MAX,
+};
+
+#define ZLIB_DECOMP_MAX        (__ZLIB_DECOMP_MAX - 1)
+
+
+struct crypto_pcomp {
+       struct crypto_tfm base;
+};
+
+struct pcomp_alg {
+       int (*compress_setup)(struct crypto_pcomp *tfm, void *params,
+                             unsigned int len);
+       int (*compress_init)(struct crypto_pcomp *tfm);
+       int (*compress_update)(struct crypto_pcomp *tfm,
+                              struct comp_request *req);
+       int (*compress_final)(struct crypto_pcomp *tfm,
+                             struct comp_request *req);
+       int (*decompress_setup)(struct crypto_pcomp *tfm, void *params,
+                               unsigned int len);
+       int (*decompress_init)(struct crypto_pcomp *tfm);
+       int (*decompress_update)(struct crypto_pcomp *tfm,
+                                struct comp_request *req);
+       int (*decompress_final)(struct crypto_pcomp *tfm,
+                               struct comp_request *req);
+
+       struct crypto_alg base;
+};
+
+extern struct crypto_pcomp *crypto_alloc_pcomp(const char *alg_name, u32 type,
+                                              u32 mask);
+
+static inline struct crypto_tfm *crypto_pcomp_tfm(struct crypto_pcomp *tfm)
+{
+       return &tfm->base;
+}
+
+static inline void crypto_free_pcomp(struct crypto_pcomp *tfm)
+{
+       crypto_destroy_tfm(tfm, crypto_pcomp_tfm(tfm));
+}
+
+static inline struct pcomp_alg *__crypto_pcomp_alg(struct crypto_alg *alg)
+{
+       return container_of(alg, struct pcomp_alg, base);
+}
+
+static inline struct pcomp_alg *crypto_pcomp_alg(struct crypto_pcomp *tfm)
+{
+       return __crypto_pcomp_alg(crypto_pcomp_tfm(tfm)->__crt_alg);
+}
+
+static inline int crypto_compress_setup(struct crypto_pcomp *tfm,
+                                       void *params, unsigned int len)
+{
+       return crypto_pcomp_alg(tfm)->compress_setup(tfm, params, len);
+}
+
+static inline int crypto_compress_init(struct crypto_pcomp *tfm)
+{
+       return crypto_pcomp_alg(tfm)->compress_init(tfm);
+}
+
+static inline int crypto_compress_update(struct crypto_pcomp *tfm,
+                                        struct comp_request *req)
+{
+       return crypto_pcomp_alg(tfm)->compress_update(tfm, req);
+}
+
+static inline int crypto_compress_final(struct crypto_pcomp *tfm,
+                                       struct comp_request *req)
+{
+       return crypto_pcomp_alg(tfm)->compress_final(tfm, req);
+}
+
+static inline int crypto_decompress_setup(struct crypto_pcomp *tfm,
+                                         void *params, unsigned int len)
+{
+       return crypto_pcomp_alg(tfm)->decompress_setup(tfm, params, len);
+}
+
+static inline int crypto_decompress_init(struct crypto_pcomp *tfm)
+{
+       return crypto_pcomp_alg(tfm)->decompress_init(tfm);
+}
+
+static inline int crypto_decompress_update(struct crypto_pcomp *tfm,
+                                          struct comp_request *req)
+{
+       return crypto_pcomp_alg(tfm)->decompress_update(tfm, req);
+}
+
+static inline int crypto_decompress_final(struct crypto_pcomp *tfm,
+                                         struct comp_request *req)
+{
+       return crypto_pcomp_alg(tfm)->decompress_final(tfm, req);
+}
+
+#endif /* _CRYPTO_COMPRESS_H */
diff --git a/include/crypto/cryptd.h b/include/crypto/cryptd.h
new file mode 100644 (file)
index 0000000..55fa7bb
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Software async crypto daemon
+ */
+
+#ifndef _CRYPTO_CRYPT_H
+#define _CRYPTO_CRYPT_H
+
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+
+struct cryptd_ablkcipher {
+       struct crypto_ablkcipher base;
+};
+
+static inline struct cryptd_ablkcipher *__cryptd_ablkcipher_cast(
+       struct crypto_ablkcipher *tfm)
+{
+       return (struct cryptd_ablkcipher *)tfm;
+}
+
+/* alg_name should be algorithm to be cryptd-ed */
+struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask);
+struct crypto_blkcipher *cryptd_ablkcipher_child(struct cryptd_ablkcipher *tfm);
+void cryptd_free_ablkcipher(struct cryptd_ablkcipher *tfm);
+
+#endif
diff --git a/include/crypto/crypto_wq.h b/include/crypto/crypto_wq.h
new file mode 100644 (file)
index 0000000..a7d252d
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef CRYPTO_WQ_H
+#define CRYPTO_WQ_H
+
+#include <linux/workqueue.h>
+
+extern struct workqueue_struct *kcrypto_wq;
+#endif
index d797e119e3d5e9677a60457670ed097982916691..d56bb71617c315e5cf13505f1ddc32c0cf698377 100644 (file)
@@ -231,6 +231,11 @@ static inline unsigned int crypto_shash_alignmask(
        return crypto_tfm_alg_alignmask(crypto_shash_tfm(tfm));
 }
 
+static inline unsigned int crypto_shash_blocksize(struct crypto_shash *tfm)
+{
+       return crypto_tfm_alg_blocksize(crypto_shash_tfm(tfm));
+}
+
 static inline struct shash_alg *__crypto_shash_alg(struct crypto_alg *alg)
 {
        return container_of(alg, struct shash_alg, base);
diff --git a/include/crypto/internal/compress.h b/include/crypto/internal/compress.h
new file mode 100644 (file)
index 0000000..178a888
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Compress: Compression algorithms under the cryptographic API.
+ *
+ * Copyright 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CRYPTO_INTERNAL_COMPRESS_H
+#define _CRYPTO_INTERNAL_COMPRESS_H
+
+#include <crypto/compress.h>
+
+extern int crypto_register_pcomp(struct pcomp_alg *alg);
+extern int crypto_unregister_pcomp(struct pcomp_alg *alg);
+
+#endif /* _CRYPTO_INTERNAL_COMPRESS_H */
index 9a061accd8b8de95f7dcb282d2488f0613418c9e..68132c4a0e91cff1ed909a56d808a0a3b9f670bc 100644 (file)
@@ -244,8 +244,6 @@ enum {
        ATA_CMD_MEDIA_UNLOCK    = 0xDF,
        /* marked obsolete in the ATA/ATAPI-7 spec */
        ATA_CMD_RESTORE         = 0x10,
-       /* EXABYTE specific */
-       ATA_EXABYTE_ENABLE_NEST = 0xF0,
 
        /* READ_LOG_EXT pages */
        ATA_LOG_SATA_NCQ        = 0x10,
index 67e5dbfc296140fe4825490ac952773921516c3b..4fa2810b675e6a157293a0aa431e1af95d71d99b 100644 (file)
@@ -36,7 +36,8 @@
  * 1500 - 1599 kernel LSPP events
  * 1600 - 1699 kernel crypto events
  * 1700 - 1799 kernel anomaly records
- * 1800 - 1999 future kernel use (maybe integrity labels and related events)
+ * 1800 - 1899 kernel integrity events
+ * 1900 - 1999 future kernel use
  * 2000 is for otherwise unclassified kernel audit messages (legacy)
  * 2001 - 2099 unused (kernel)
  * 2100 - 2199 user space anomaly records
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous mode */
 #define AUDIT_ANOM_ABEND            1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA       1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA    1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS     1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH       1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR        1804 /* PCR invalidation msgs */
+#define AUDIT_INTEGRITY_RULE       1805 /* policy rule */
 
 #define AUDIT_KERNEL           2000    /* Asynchronous audit record. NOT A REQUEST. */
 
index a67a90cf826882bb6ad47c119de04abac49cd91d..dcca5339ceb3c65711d9fce57d27bec70153029f 100644 (file)
@@ -137,8 +137,8 @@ extern void resume_console(void);
 int mda_console_init(void);
 void prom_con_init(void);
 
-void vcs_make_sysfs(struct tty_struct *tty);
-void vcs_remove_sysfs(struct tty_struct *tty);
+void vcs_make_sysfs(int index);
+void vcs_remove_sysfs(int index);
 
 /* Some debug stub to catch some of the obvious races in the VT code */
 #if 1
index 1f2e9020acc667d5f0dd0f2e501e6f85f0fff140..ec29fa268b94e278e5125380f8e2b1faa20c10c9 100644 (file)
@@ -40,6 +40,7 @@
 #define CRYPTO_ALG_TYPE_SHASH          0x00000009
 #define CRYPTO_ALG_TYPE_AHASH          0x0000000a
 #define CRYPTO_ALG_TYPE_RNG            0x0000000c
+#define CRYPTO_ALG_TYPE_PCOMPRESS      0x0000000f
 
 #define CRYPTO_ALG_TYPE_HASH_MASK      0x0000000e
 #define CRYPTO_ALG_TYPE_AHASH_MASK     0x0000000c
@@ -548,9 +549,6 @@ struct crypto_attr_u32 {
  * Transform user interface.
  */
  
-struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
-                                   const struct crypto_type *frontend,
-                                   u32 type, u32 mask);
 struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
 void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm);
 
index 47f343c7bddaaca551c8fb2114160fb5f362c4e1..2918c0e8fdfdeed78d032b7218bd2194b627706e 100644 (file)
@@ -28,6 +28,7 @@
 #define BUS_ID_SIZE            20
 
 struct device;
+struct device_private;
 struct device_driver;
 struct driver_private;
 struct class;
@@ -147,7 +148,7 @@ extern void put_driver(struct device_driver *drv);
 extern struct device_driver *driver_find(const char *name,
                                         struct bus_type *bus);
 extern int driver_probe_done(void);
-extern int wait_for_device_probe(void);
+extern void wait_for_device_probe(void);
 
 
 /* sysfs interface for exporting driver attributes */
@@ -367,15 +368,11 @@ struct device_dma_parameters {
 };
 
 struct device {
-       struct klist            klist_children;
-       struct klist_node       knode_parent;   /* node in sibling list */
-       struct klist_node       knode_driver;
-       struct klist_node       knode_bus;
        struct device           *parent;
 
+       struct device_private   *p;
+
        struct kobject kobj;
-       char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
-       unsigned                uevent_suppress:1;
        const char              *init_name; /* initial name of the device */
        struct device_type      *type;
 
@@ -387,8 +384,13 @@ struct device {
        struct device_driver *driver;   /* which driver has allocated this
                                           device */
        void            *driver_data;   /* data private to the driver */
-       void            *platform_data; /* Platform specific data, device
-                                          core doesn't touch it */
+
+       void            *platform_data; /* We will remove platform_data
+                                          field if all platform devices
+                                          pass its platform specific data
+                                          from platform_device->platform_data,
+                                          other kind of devices should not
+                                          use platform_data. */
        struct dev_pm_info      power;
 
 #ifdef CONFIG_NUMA
@@ -427,8 +429,7 @@ struct device {
 
 static inline const char *dev_name(const struct device *dev)
 {
-       /* will be changed into kobject_name(&dev->kobj) in the near future */
-       return dev->bus_id;
+       return kobject_name(&dev->kobj);
 }
 
 extern int dev_set_name(struct device *dev, const char *name, ...)
@@ -463,6 +464,16 @@ static inline void dev_set_drvdata(struct device *dev, void *data)
        dev->driver_data = data;
 }
 
+static inline unsigned int dev_get_uevent_suppress(const struct device *dev)
+{
+       return dev->kobj.uevent_suppress;
+}
+
+static inline void dev_set_uevent_suppress(struct device *dev, int val)
+{
+       dev->kobj.uevent_suppress = val;
+}
+
 static inline int device_is_registered(struct device *dev)
 {
        return dev->kobj.state_in_sysfs;
@@ -483,7 +494,8 @@ extern int device_for_each_child(struct device *dev, void *data,
 extern struct device *device_find_child(struct device *dev, void *data,
                                int (*match)(struct device *dev, void *data));
 extern int device_rename(struct device *dev, char *new_name);
-extern int device_move(struct device *dev, struct device *new_parent);
+extern int device_move(struct device *dev, struct device *new_parent,
+                      enum dpm_order dpm_order);
 
 /*
  * Root device objects for grouping under /sys/devices
@@ -570,7 +582,7 @@ extern const char *dev_driver_string(const struct device *dev);
 #if defined(DEBUG)
 #define dev_dbg(dev, format, arg...)           \
        dev_printk(KERN_DEBUG , dev , format , ## arg)
-#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
 #define dev_dbg(dev, format, ...) do { \
        dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
        } while (0)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
new file mode 100644 (file)
index 0000000..baabf33
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef _DYNAMIC_DEBUG_H
+#define _DYNAMIC_DEBUG_H
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+extern long long dynamic_debug_enabled;
+extern long long dynamic_debug_enabled2;
+
+/*
+ * An instance of this structure is created in a special
+ * ELF section at every dynamic debug callsite.  At runtime,
+ * the special section is treated as an array of these.
+ */
+struct _ddebug {
+       /*
+        * These fields are used to drive the user interface
+        * for selecting and displaying debug callsites.
+        */
+       const char *modname;
+       const char *function;
+       const char *filename;
+       const char *format;
+       char primary_hash;
+       char secondary_hash;
+       unsigned int lineno:24;
+       /*
+        * The flags field controls the behaviour at the callsite.
+        * The bits here are changed dynamically when the user
+        * writes commands to <debugfs>/dynamic_debug/ddebug
+        */
+#define _DPRINTK_FLAGS_PRINT   (1<<0)  /* printk() a message using the format */
+#define _DPRINTK_FLAGS_DEFAULT 0
+       unsigned int flags:8;
+} __attribute__((aligned(8)));
+
+
+int ddebug_add_module(struct _ddebug *tab, unsigned int n,
+                               const char *modname);
+
+#if defined(CONFIG_DYNAMIC_DEBUG)
+extern int ddebug_remove_module(char *mod_name);
+
+#define __dynamic_dbg_enabled(dd)  ({       \
+       int __ret = 0;                                                       \
+       if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) &&        \
+                       (dynamic_debug_enabled2 & (1LL << DEBUG_HASH2))))   \
+                               if (unlikely(dd.flags))                      \
+                                       __ret = 1;                           \
+       __ret; })
+
+#define dynamic_pr_debug(fmt, ...) do {                                        \
+       static struct _ddebug descriptor                                \
+       __used                                                          \
+       __attribute__((section("__verbose"), aligned(8))) =             \
+       { KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH,  \
+               DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT };        \
+       if (__dynamic_dbg_enabled(descriptor))                          \
+               printk(KERN_DEBUG KBUILD_MODNAME ":" pr_fmt(fmt),       \
+                               ##__VA_ARGS__);                         \
+       } while (0)
+
+
+#define dynamic_dev_dbg(dev, fmt, ...) do {                            \
+       static struct _ddebug descriptor                                \
+       __used                                                          \
+       __attribute__((section("__verbose"), aligned(8))) =             \
+       { KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH,  \
+               DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT };        \
+       if (__dynamic_dbg_enabled(descriptor))                          \
+                       dev_printk(KERN_DEBUG, dev,                     \
+                                       KBUILD_MODNAME ": " pr_fmt(fmt),\
+                                       ##__VA_ARGS__);                 \
+       } while (0)
+
+#else
+
+static inline int ddebug_remove_module(char *mod)
+{
+       return 0;
+}
+
+#define dynamic_pr_debug(fmt, ...)  do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...)  do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/dynamic_printk.h b/include/linux/dynamic_printk.h
deleted file mode 100644 (file)
index 2d528d0..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef _DYNAMIC_PRINTK_H
-#define _DYNAMIC_PRINTK_H
-
-#define DYNAMIC_DEBUG_HASH_BITS 6
-#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
-
-#define TYPE_BOOLEAN 1
-
-#define DYNAMIC_ENABLED_ALL 0
-#define DYNAMIC_ENABLED_NONE 1
-#define DYNAMIC_ENABLED_SOME 2
-
-extern int dynamic_enabled;
-
-/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
- * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
- * use independent hash functions, to reduce the chance of false positives.
- */
-extern long long dynamic_printk_enabled;
-extern long long dynamic_printk_enabled2;
-
-struct mod_debug {
-       char *modname;
-       char *logical_modname;
-       char *flag_names;
-       int type;
-       int hash;
-       int hash2;
-} __attribute__((aligned(8)));
-
-int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
-                                       char *flags, int hash, int hash2);
-
-#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
-extern int unregister_dynamic_debug_module(char *mod_name);
-extern int __dynamic_dbg_enabled_helper(char *modname, int type,
-                                       int value, int hash);
-
-#define __dynamic_dbg_enabled(module, type, value, level, hash)  ({         \
-       int __ret = 0;                                                       \
-       if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) &&       \
-                       (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2))))   \
-                       __ret = __dynamic_dbg_enabled_helper(module, type,   \
-                                                               value, hash);\
-       __ret; })
-
-#define dynamic_pr_debug(fmt, ...) do {                                            \
-       static char mod_name[]                                              \
-       __attribute__((section("__verbose_strings")))                       \
-        = KBUILD_MODNAME;                                                  \
-       static struct mod_debug descriptor                                  \
-       __used                                                              \
-       __attribute__((section("__verbose"), aligned(8))) =                 \
-       { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
-       if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN,             \
-                                               0, 0, DEBUG_HASH))          \
-               printk(KERN_DEBUG KBUILD_MODNAME ":" fmt,                   \
-                               ##__VA_ARGS__);                             \
-       } while (0)
-
-#define dynamic_dev_dbg(dev, format, ...) do {                             \
-       static char mod_name[]                                              \
-       __attribute__((section("__verbose_strings")))                       \
-        = KBUILD_MODNAME;                                                  \
-       static struct mod_debug descriptor                                  \
-       __used                                                              \
-       __attribute__((section("__verbose"), aligned(8))) =                 \
-       { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
-       if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN,             \
-                                               0, 0, DEBUG_HASH))          \
-                       dev_printk(KERN_DEBUG, dev,                         \
-                                       KBUILD_MODNAME ": " format,         \
-                                       ##__VA_ARGS__);                     \
-       } while (0)
-
-#else
-
-static inline int unregister_dynamic_debug_module(const char *mod_name)
-{
-       return 0;
-}
-static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
-                                               int value, int hash)
-{
-       return 0;
-}
-
-#define __dynamic_dbg_enabled(module, type, value, level, hash)  ({ 0; })
-#define dynamic_pr_debug(fmt, ...)  do { } while (0)
-#define dynamic_dev_dbg(dev, format, ...)  do { } while (0)
-#endif
-
-#endif
index 92734c0012e679cb3326ba25be08f52dce81fbc8..5bc81c4a98c1913cb0e15adf8d70e9c083956bb8 100644 (file)
@@ -141,6 +141,7 @@ struct inodes_stat_t {
 #define MS_RELATIME    (1<<21) /* Update atime relative to mtime/ctime. */
 #define MS_KERNMOUNT   (1<<22) /* this is a kern_mount call */
 #define MS_I_VERSION   (1<<23) /* Update inode I_version field */
+#define MS_STRICTATIME (1<<24) /* Always perform atime updates */
 #define MS_ACTIVE      (1<<30)
 #define MS_NOUSER      (1<<31)
 
index 25087aead65768401a8b32b582fd42780401fde1..854eba8b2ba33f9c375d88e28fb80ef4e28b1a17 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/io.h>
 #include <asm/mutex.h>
 
-#if defined(CONFIG_CRIS) || defined(CONFIG_FRV)
+#if defined(CONFIG_CRIS) || defined(CONFIG_FRV) || defined(CONFIG_MN10300)
 # define SUPPORT_VLB_SYNC 0
 #else
 # define SUPPORT_VLB_SYNC 1
@@ -193,24 +193,8 @@ static inline void ide_std_init_ports(hw_regs_t *hw,
        hw->io_ports.ctl_addr = ctl_addr;
 }
 
-/* for IDE PCI controllers in legacy mode, temporary */
-static inline int __ide_default_irq(unsigned long base)
-{
-       switch (base) {
-#ifdef CONFIG_IA64
-       case 0x1f0: return isa_irq_to_vector(14);
-       case 0x170: return isa_irq_to_vector(15);
-#else
-       case 0x1f0: return 14;
-       case 0x170: return 15;
-#endif
-       }
-       return 0;
-}
-
-#if defined(CONFIG_ARM) || defined(CONFIG_FRV) || defined(CONFIG_M68K) || \
-    defined(CONFIG_MIPS) || defined(CONFIG_MN10300) || defined(CONFIG_PARISC) \
-    || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
+#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
+    defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
 #include <asm/ide.h>
 #else
 #include <asm-generic/ide_iops.h>
@@ -866,7 +850,7 @@ struct ide_host {
        ide_hwif_t      *ports[MAX_HOST_PORTS + 1];
        unsigned int    n_ports;
        struct device   *dev[2];
-       unsigned int    (*init_chipset)(struct pci_dev *);
+       int             (*init_chipset)(struct pci_dev *);
        irq_handler_t   irq_handler;
        unsigned long   host_flags;
        void            *host_priv;
@@ -1146,11 +1130,14 @@ int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned l
 extern int ide_vlb_clk;
 extern int ide_pci_clk;
 
-extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
-int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
-                            int uptodate, int nr_sectors);
+int ide_end_request(ide_drive_t *, int, int);
+int ide_end_dequeued_request(ide_drive_t *, struct request *, int, int);
+void ide_kill_rq(ide_drive_t *, struct request *);
 
-extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
+void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int,
+                      ide_expiry_t *);
+void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int,
+                    ide_expiry_t *);
 
 void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
                         ide_expiry_t *);
@@ -1169,13 +1156,14 @@ int ide_busy_sleep(ide_hwif_t *, unsigned long, int);
 
 int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
+ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *);
+ide_startstop_t ide_do_devset(ide_drive_t *, struct request *);
+
 extern ide_startstop_t ide_do_reset (ide_drive_t *);
 
 extern int ide_devset_execute(ide_drive_t *drive,
                              const struct ide_devset *setting, int arg);
 
-extern void ide_do_drive_cmd(ide_drive_t *, struct request *);
-
 extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
 void ide_tf_dump(const char *, struct ide_taskfile *);
@@ -1200,10 +1188,6 @@ void SELECT_MASK(ide_drive_t *, int);
 u8 ide_read_error(ide_drive_t *);
 void ide_read_bcount_and_ireason(ide_drive_t *, u16 *, u8 *);
 
-extern int drive_is_ready(ide_drive_t *);
-
-void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8);
-
 int ide_check_atapi_device(ide_drive_t *, const char *);
 
 void ide_init_pc(struct ide_atapi_pc *);
@@ -1251,6 +1235,8 @@ int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
 
+int ide_dev_read_id(ide_drive_t *, u8, u16 *);
+
 extern int ide_driveid_update(ide_drive_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);
 extern u8 eighty_ninty_three (ide_drive_t *);
@@ -1280,7 +1266,7 @@ static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev)
        return 0;
 }
 
-void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int,
+void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *,
                         hw_regs_t *, hw_regs_t **);
 void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
 
@@ -1349,10 +1335,6 @@ enum {
        IDE_HFLAG_ERROR_STOPS_FIFO      = (1 << 19),
        /* serialize ports */
        IDE_HFLAG_SERIALIZE             = (1 << 20),
-       /* use legacy IRQs */
-       IDE_HFLAG_LEGACY_IRQS           = (1 << 21),
-       /* force use of legacy IRQs */
-       IDE_HFLAG_FORCE_LEGACY_IRQS     = (1 << 22),
        /* host is TRM290 */
        IDE_HFLAG_TRM290                = (1 << 23),
        /* use 32-bit I/O ops */
@@ -1380,7 +1362,7 @@ enum {
 
 struct ide_port_info {
        char                    *name;
-       unsigned int            (*init_chipset)(struct pci_dev *);
+       int                     (*init_chipset)(struct pci_dev *);
        void                    (*init_iops)(ide_hwif_t *);
        void                    (*init_hwif)(ide_hwif_t *);
        int                     (*init_dma)(ide_hwif_t *,
@@ -1471,6 +1453,7 @@ static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 
 void ide_dma_lost_irq(ide_drive_t *);
 void ide_dma_timeout(ide_drive_t *);
+ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
 
 #else
 static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
@@ -1482,21 +1465,24 @@ static inline void ide_dma_on(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
 static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
+static inline ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { return ide_stopped; }
 static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_acpi_init(void);
 extern int ide_acpi_exec_tfs(ide_drive_t *drive);
 extern void ide_acpi_get_timing(ide_hwif_t *hwif);
 extern void ide_acpi_push_timing(ide_hwif_t *hwif);
-extern void ide_acpi_init(ide_hwif_t *hwif);
+void ide_acpi_init_port(ide_hwif_t *);
 void ide_acpi_port_init_devices(ide_hwif_t *);
 extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
 #else
+static inline int ide_acpi_init(void) { return 0; }
 static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
 static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
-static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_init_port(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_port_init_devices(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
 #endif
@@ -1530,9 +1516,7 @@ static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
        hwif->hwif_data = data;
 }
 
-const char *ide_xfer_verbose(u8 mode);
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
-extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
 
 u64 ide_get_lba_addr(struct ide_taskfile *, int);
 u8 ide_dump_status(ide_drive_t *, const char *, u8);
@@ -1571,14 +1555,18 @@ void ide_timing_merge(struct ide_timing *, struct ide_timing *,
                      struct ide_timing *, unsigned int);
 int ide_timing_compute(ide_drive_t *, u8, struct ide_timing *, int, int);
 
+#ifdef CONFIG_IDE_XFER_MODE
 int ide_scan_pio_blacklist(char *);
-
+const char *ide_xfer_verbose(u8);
 u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8);
-
 int ide_set_pio_mode(ide_drive_t *, u8);
 int ide_set_dma_mode(ide_drive_t *, u8);
-
 void ide_set_pio(ide_drive_t *, u8);
+int ide_set_xfer_rate(ide_drive_t *, u8);
+#else
+static inline void ide_set_pio(ide_drive_t *drive, u8 pio) { ; }
+static inline int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { return -1; }
+#endif
 
 static inline void ide_set_max_pio(ide_drive_t *drive)
 {
@@ -1611,6 +1599,10 @@ static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive)
 #define ide_port_for_each_dev(i, dev, port) \
        for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++)
 
+#define ide_port_for_each_present_dev(i, dev, port) \
+       for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++) \
+               if ((dev)->dev_flags & IDE_DFLAG_PRESENT)
+
 #define ide_host_for_each_port(i, port, host) \
        for ((i) = 0; ((port) = (host)->ports[i]) || (i) < MAX_HOST_PORTS; (i)++)
 
diff --git a/include/linux/ima.h b/include/linux/ima.h
new file mode 100644 (file)
index 0000000..0e2aa45
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_IMA_H
+#define _LINUX_IMA_H
+
+#include <linux/fs.h>
+struct linux_binprm;
+
+#ifdef CONFIG_IMA
+extern int ima_bprm_check(struct linux_binprm *bprm);
+extern int ima_inode_alloc(struct inode *inode);
+extern void ima_inode_free(struct inode *inode);
+extern int ima_path_check(struct path *path, int mask);
+extern void ima_file_free(struct file *file);
+extern int ima_file_mmap(struct file *file, unsigned long prot);
+extern void ima_shm_check(struct file *file);
+
+#else
+static inline int ima_bprm_check(struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static inline int ima_inode_alloc(struct inode *inode)
+{
+       return 0;
+}
+
+static inline void ima_inode_free(struct inode *inode)
+{
+       return;
+}
+
+static inline int ima_path_check(struct path *path, int mask)
+{
+       return 0;
+}
+
+static inline void ima_file_free(struct file *file)
+{
+       return;
+}
+
+static inline int ima_file_mmap(struct file *file, unsigned long prot)
+{
+       return 0;
+}
+
+static inline void ima_shm_check(struct file *file)
+{
+       return;
+}
+#endif /* CONFIG_IMA_H */
+#endif /* _LINUX_IMA_H */
index 1249a0c20a38258f7cf3064ece21f6e54dcbf254..6b28048fc56820152a1f95074b2721e285bab762 100644 (file)
@@ -661,6 +661,7 @@ struct input_absinfo {
 #define SW_DOCK                        0x05  /* set = plugged into dock */
 #define SW_LINEOUT_INSERT      0x06  /* set = inserted */
 #define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
+#define SW_VIDEOOUT_INSERT     0x08  /* set = inserted */
 #define SW_MAX                 0x0f
 #define SW_CNT                 (SW_MAX+1)
 
index 7fa371898e3e76d8e1af870f049844ff71bea931..914918abfdd122a5bf9a6c564fd7c41693917c9b 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/log2.h>
 #include <linux/typecheck.h>
 #include <linux/ratelimit.h>
-#include <linux/dynamic_printk.h>
+#include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
 #include <asm/bug.h>
 
@@ -358,9 +358,10 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
 #if defined(DEBUG)
 #define pr_debug(fmt, ...) \
        printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
+/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
 #define pr_debug(fmt, ...) do { \
-       dynamic_pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
+       dynamic_pr_debug(fmt, ##__VA_ARGS__); \
        } while (0)
 #else
 #define pr_debug(fmt, ...) \
index 5437ac0276e232d259a886e7b644f4b4e2e44935..58ae8e00fcddd067b9815b8831c5c92986187584 100644 (file)
@@ -68,10 +68,13 @@ struct kobject {
        unsigned int state_in_sysfs:1;
        unsigned int state_add_uevent_sent:1;
        unsigned int state_remove_uevent_sent:1;
+       unsigned int uevent_suppress:1;
 };
 
 extern int kobject_set_name(struct kobject *kobj, const char *name, ...)
                            __attribute__((format(printf, 2, 3)));
+extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+                                 va_list vargs);
 
 static inline const char *kobject_name(const struct kobject *kobj)
 {
diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h
deleted file mode 100644 (file)
index 2ed8fa1..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef __LM_INTERFACE_DOT_H__
-#define __LM_INTERFACE_DOT_H__
-
-
-typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
-
-/*
- * lm_mount() flags
- *
- * LM_MFLAG_SPECTATOR
- * GFS is asking to join the filesystem's lockspace, but it doesn't want to
- * modify the filesystem.  The lock module shouldn't assign a journal to the FS
- * mount.  It shouldn't send recovery callbacks to the FS mount.  If the node
- * dies or withdraws, all locks can be wiped immediately.
- *
- * LM_MFLAG_CONV_NODROP
- * Do not allow the dlm to internally resolve conversion deadlocks by demoting
- * the lock to unlocked and then reacquiring it in the requested mode. Instead,
- * it should cancel the request and return LM_OUT_CONV_DEADLK.
- */
-
-#define LM_MFLAG_SPECTATOR     0x00000001
-#define LM_MFLAG_CONV_NODROP   0x00000002
-
-/*
- * lm_lockstruct flags
- *
- * LM_LSFLAG_LOCAL
- * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS
- * can make single-node optimizations.
- */
-
-#define LM_LSFLAG_LOCAL                0x00000001
-
-/*
- * lm_lockname types
- */
-
-#define LM_TYPE_RESERVED       0x00
-#define LM_TYPE_NONDISK                0x01
-#define LM_TYPE_INODE          0x02
-#define LM_TYPE_RGRP           0x03
-#define LM_TYPE_META           0x04
-#define LM_TYPE_IOPEN          0x05
-#define LM_TYPE_FLOCK          0x06
-#define LM_TYPE_PLOCK          0x07
-#define LM_TYPE_QUOTA          0x08
-#define LM_TYPE_JOURNAL                0x09
-
-/*
- * lm_lock() states
- *
- * SHARED is compatible with SHARED, not with DEFERRED or EX.
- * DEFERRED is compatible with DEFERRED, not with SHARED or EX.
- */
-
-#define LM_ST_UNLOCKED         0
-#define LM_ST_EXCLUSIVE                1
-#define LM_ST_DEFERRED         2
-#define LM_ST_SHARED           3
-
-/*
- * lm_lock() flags
- *
- * LM_FLAG_TRY
- * Don't wait to acquire the lock if it can't be granted immediately.
- *
- * LM_FLAG_TRY_1CB
- * Send one blocking callback if TRY is set and the lock is not granted.
- *
- * LM_FLAG_NOEXP
- * GFS sets this flag on lock requests it makes while doing journal recovery.
- * These special requests should not be blocked due to the recovery like
- * ordinary locks would be.
- *
- * LM_FLAG_ANY
- * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
- * also be granted in SHARED.  The preferred state is whichever is compatible
- * with other granted locks, or the specified state if no other locks exist.
- *
- * LM_FLAG_PRIORITY
- * Override fairness considerations.  Suppose a lock is held in a shared state
- * and there is a pending request for the deferred state.  A shared lock
- * request with the priority flag would be allowed to bypass the deferred
- * request and directly join the other shared lock.  A shared lock request
- * without the priority flag might be forced to wait until the deferred
- * requested had acquired and released the lock.
- */
-
-#define LM_FLAG_TRY            0x00000001
-#define LM_FLAG_TRY_1CB                0x00000002
-#define LM_FLAG_NOEXP          0x00000004
-#define LM_FLAG_ANY            0x00000008
-#define LM_FLAG_PRIORITY       0x00000010
-
-/*
- * lm_lock() and lm_async_cb return flags
- *
- * LM_OUT_ST_MASK
- * Masks the lower two bits of lock state in the returned value.
- *
- * LM_OUT_CACHEABLE
- * The lock hasn't been released so GFS can continue to cache data for it.
- *
- * LM_OUT_CANCELED
- * The lock request was canceled.
- *
- * LM_OUT_ASYNC
- * The result of the request will be returned in an LM_CB_ASYNC callback.
- *
- * LM_OUT_CONV_DEADLK
- * The lock request was canceled do to a conversion deadlock.
- */
-
-#define LM_OUT_ST_MASK         0x00000003
-#define LM_OUT_CANCELED                0x00000008
-#define LM_OUT_ASYNC           0x00000080
-#define LM_OUT_ERROR           0x00000100
-
-/*
- * lm_callback_t types
- *
- * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S
- * Blocking callback, a remote node is requesting the given lock in
- * EXCLUSIVE, DEFERRED, or SHARED.
- *
- * LM_CB_NEED_RECOVERY
- * The given journal needs to be recovered.
- *
- * LM_CB_ASYNC
- * The given lock has been granted.
- */
-
-#define LM_CB_NEED_E           257
-#define LM_CB_NEED_D           258
-#define LM_CB_NEED_S           259
-#define LM_CB_NEED_RECOVERY    260
-#define LM_CB_ASYNC            262
-
-/*
- * lm_recovery_done() messages
- */
-
-#define LM_RD_GAVEUP           308
-#define LM_RD_SUCCESS          309
-
-
-struct lm_lockname {
-       u64 ln_number;
-       unsigned int ln_type;
-};
-
-#define lm_name_equal(name1, name2) \
-       (((name1)->ln_number == (name2)->ln_number) && \
-        ((name1)->ln_type == (name2)->ln_type)) \
-
-struct lm_async_cb {
-       struct lm_lockname lc_name;
-       int lc_ret;
-};
-
-struct lm_lockstruct;
-
-struct lm_lockops {
-       const char *lm_proto_name;
-
-       /*
-        * Mount/Unmount
-        */
-
-       int (*lm_mount) (char *table_name, char *host_data,
-                        lm_callback_t cb, void *cb_data,
-                        unsigned int min_lvb_size, int flags,
-                        struct lm_lockstruct *lockstruct,
-                        struct kobject *fskobj);
-
-       void (*lm_others_may_mount) (void *lockspace);
-
-       void (*lm_unmount) (void *lockspace);
-
-       void (*lm_withdraw) (void *lockspace);
-
-       /*
-        * Lock oriented operations
-        */
-
-       int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp);
-
-       void (*lm_put_lock) (void *lock);
-
-       unsigned int (*lm_lock) (void *lock, unsigned int cur_state,
-                                unsigned int req_state, unsigned int flags);
-
-       unsigned int (*lm_unlock) (void *lock, unsigned int cur_state);
-
-       void (*lm_cancel) (void *lock);
-
-       int (*lm_hold_lvb) (void *lock, char **lvbp);
-       void (*lm_unhold_lvb) (void *lock, char *lvb);
-
-       /*
-        * Posix Lock oriented operations
-        */
-
-       int (*lm_plock_get) (void *lockspace, struct lm_lockname *name,
-                            struct file *file, struct file_lock *fl);
-
-       int (*lm_plock) (void *lockspace, struct lm_lockname *name,
-                        struct file *file, int cmd, struct file_lock *fl);
-
-       int (*lm_punlock) (void *lockspace, struct lm_lockname *name,
-                          struct file *file, struct file_lock *fl);
-
-       /*
-        * Client oriented operations
-        */
-
-       void (*lm_recovery_done) (void *lockspace, unsigned int jid,
-                                 unsigned int message);
-
-       struct module *lm_owner;
-};
-
-/*
- * lm_mount() return values
- *
- * ls_jid - the journal ID this node should use
- * ls_first - this node is the first to mount the file system
- * ls_lvb_size - size in bytes of lock value blocks
- * ls_lockspace - lock module's context for this file system
- * ls_ops - lock module's functions
- * ls_flags - lock module features
- */
-
-struct lm_lockstruct {
-       unsigned int ls_jid;
-       unsigned int ls_first;
-       unsigned int ls_lvb_size;
-       void *ls_lockspace;
-       const struct lm_lockops *ls_ops;
-       int ls_flags;
-};
-
-/*
- * Lock module bottom interface.  A lock module makes itself available to GFS
- * with these functions.
- */
-
-int gfs2_register_lockproto(const struct lm_lockops *proto);
-void gfs2_unregister_lockproto(const struct lm_lockops *proto);
-
-/*
- * Lock module top interface.  GFS calls these functions when mounting or
- * unmounting a file system.
- */
-
-int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
-                        lm_callback_t cb, void *cb_data,
-                        unsigned int min_lvb_size, int flags,
-                        struct lm_lockstruct *lockstruct,
-                        struct kobject *fskobj);
-
-void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct);
-
-void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct);
-
-#endif /* __LM_INTERFACE_DOT_H__ */
-
index c23d3f51ba4090ec2aa9c99a734e50216e9bcca5..d9a51b9b3300a784f12536ec1670338248cf9b8a 100644 (file)
@@ -8,33 +8,49 @@ extern struct bus_type maple_bus_type;
 
 /* Maple Bus command and response codes */
 enum maple_code {
-       MAPLE_RESPONSE_FILEERR = -5,
-       MAPLE_RESPONSE_AGAIN = -4,      /* request should be retransmitted */
-       MAPLE_RESPONSE_BADCMD = -3,
-       MAPLE_RESPONSE_BADFUNC = -2,
-       MAPLE_RESPONSE_NONE = -1,       /* unit didn't respond at all */
-       MAPLE_COMMAND_DEVINFO = 1,
-       MAPLE_COMMAND_ALLINFO = 2,
-       MAPLE_COMMAND_RESET = 3,
-       MAPLE_COMMAND_KILL = 4,
-       MAPLE_RESPONSE_DEVINFO = 5,
-       MAPLE_RESPONSE_ALLINFO = 6,
-       MAPLE_RESPONSE_OK = 7,
-       MAPLE_RESPONSE_DATATRF = 8,
-       MAPLE_COMMAND_GETCOND = 9,
-       MAPLE_COMMAND_GETMINFO = 10,
-       MAPLE_COMMAND_BREAD = 11,
-       MAPLE_COMMAND_BWRITE = 12,
-       MAPLE_COMMAND_SETCOND = 14
+       MAPLE_RESPONSE_FILEERR =        -5,
+       MAPLE_RESPONSE_AGAIN,   /* retransmit */
+       MAPLE_RESPONSE_BADCMD,
+       MAPLE_RESPONSE_BADFUNC,
+       MAPLE_RESPONSE_NONE,    /* unit didn't respond*/
+       MAPLE_COMMAND_DEVINFO =         1,
+       MAPLE_COMMAND_ALLINFO,
+       MAPLE_COMMAND_RESET,
+       MAPLE_COMMAND_KILL,
+       MAPLE_RESPONSE_DEVINFO,
+       MAPLE_RESPONSE_ALLINFO,
+       MAPLE_RESPONSE_OK,
+       MAPLE_RESPONSE_DATATRF,
+       MAPLE_COMMAND_GETCOND,
+       MAPLE_COMMAND_GETMINFO,
+       MAPLE_COMMAND_BREAD,
+       MAPLE_COMMAND_BWRITE,
+       MAPLE_COMMAND_BSYNC,
+       MAPLE_COMMAND_SETCOND,
+       MAPLE_COMMAND_MICCONTROL
+};
+
+enum maple_file_errors {
+       MAPLE_FILEERR_INVALID_PARTITION =       0x01000000,
+       MAPLE_FILEERR_PHASE_ERROR =             0x02000000,
+       MAPLE_FILEERR_INVALID_BLOCK =           0x04000000,
+       MAPLE_FILEERR_WRITE_ERROR =             0x08000000,
+       MAPLE_FILEERR_INVALID_WRITE_LENGTH =    0x10000000,
+       MAPLE_FILEERR_BAD_CRC =                 0x20000000
+};
+
+struct maple_buffer {
+       char bufx[0x400];
+       void *buf;
 };
 
 struct mapleq {
        struct list_head list;
        struct maple_device *dev;
-       void *sendbuf, *recvbuf, *recvbufdcsp;
+       struct maple_buffer *recvbuf;
+       void *sendbuf, *recvbuf_p2;
        unsigned char length;
        enum maple_code command;
-       struct mutex mutex;
 };
 
 struct maple_devinfo {
@@ -52,11 +68,15 @@ struct maple_device {
        struct maple_driver *driver;
        struct mapleq *mq;
        void (*callback) (struct mapleq * mq);
+       void (*fileerr_handler)(struct maple_device *mdev, void *recvbuf);
+       int (*can_unload)(struct maple_device *mdev);
        unsigned long when, interval, function;
        struct maple_devinfo devinfo;
        unsigned char port, unit;
        char product_name[32];
        char product_licence[64];
+       atomic_t busy;
+       wait_queue_head_t maple_wait;
        struct device dev;
 };
 
@@ -72,7 +92,7 @@ void maple_getcond_callback(struct maple_device *dev,
 int maple_driver_register(struct maple_driver *);
 void maple_driver_unregister(struct maple_driver *);
 
-int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
+int maple_add_packet(struct maple_device *mdev, u32 function,
        u32 command, u32 length, void *data);
 void maple_clear_dev(struct maple_device *mdev);
 
index af95a1d2f3a11e333fbe6a00fcb2354f16657a2a..d899dc0223ba642b41757bd6d85ffa5c20aae292 100644 (file)
 /*
  * R231 (0xE7) - Jack Status
  */
+#define WM8350_JACK_L_LVL                      0x0800
 #define WM8350_JACK_R_LVL                       0x0400
 
 /*
index b6640e018046a4cdf629dcbaa25cb9715b9a9ba2..e06ed3eb1d0a7e90c252c5d6adf9d204c8f78c0b 100644 (file)
 #define WM8400_FLL_OUTDIV_SHIFT                      0  /* FLL_OUTDIV - [2:0] */
 #define WM8400_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [2:0] */
 
+struct wm8400;
 void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400);
 
 #endif
index fde86671f48f380ed6205eb0c66dcf7aec17fd2c..1bf5900ffe434232c61ba9d71a9ee7e061e37a41 100644 (file)
@@ -454,4 +454,13 @@ struct dmi_system_id {
 
 #define DMI_MATCH(a, b)        { a, b }
 
+#define PLATFORM_NAME_SIZE     20
+#define PLATFORM_MODULE_PREFIX "platform:"
+
+struct platform_device_id {
+       char name[PLATFORM_NAME_SIZE];
+       kernel_ulong_t driver_data
+                       __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index cab2a85e2ee82f556cf1515eb14bd6d88ad344b0..51f55f903aff5140b9cda4ca104df8d3e2cb4426 100644 (file)
@@ -27,6 +27,7 @@ struct mnt_namespace;
 #define MNT_NODIRATIME 0x10
 #define MNT_RELATIME   0x20
 #define MNT_READONLY   0x40    /* does the user want this to be r/o? */
+#define MNT_STRICTATIME 0x80
 
 #define MNT_SHRINKABLE 0x100
 #define MNT_IMBALANCED_WRITE_COUNT     0x200 /* just for debugging */
index aca8c458aa8a7a23e87198ce8a9cb9eba8f3d87b..02c18b903986b3e3168fba80098425deaf046c78 100644 (file)
 #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
 #define PCI_DEVICE_ID_MELLANOX_SINAI   0x6274
 
+#define PCI_VENDOR_ID_DFI              0x15bd
+
 #define PCI_VENDOR_ID_QUICKNET         0x15e2
 #define PCI_DEVICE_ID_QUICKNET_XJ      0x0500
 
index 9a342699c6075a946f947bea3298cd8e86f65b37..76e470a299bfb9365078574e9ca3b1f438eae1d7 100644 (file)
@@ -12,6 +12,7 @@
 #define _PLATFORM_DEVICE_H_
 
 #include <linux/device.h>
+#include <linux/mod_devicetable.h>
 
 struct platform_device {
        const char      * name;
@@ -19,8 +20,13 @@ struct platform_device {
        struct device   dev;
        u32             num_resources;
        struct resource * resource;
+       void            *platform_data;
+
+       struct platform_device_id       *id_entry;
 };
 
+#define platform_get_device_id(pdev)   ((pdev)->id_entry)
+
 #define to_platform_device(x) container_of((x), struct platform_device, dev)
 
 extern int platform_device_register(struct platform_device *);
@@ -56,6 +62,7 @@ struct platform_driver {
        int (*resume_early)(struct platform_device *);
        int (*resume)(struct platform_device *);
        struct device_driver driver;
+       struct platform_device_id *id_table;
 };
 
 extern int platform_driver_register(struct platform_driver *);
index 24ba5f67b3a3a590480b6ad32b62326be2156c9f..1d4e2d289821d1d74f9e203dc966ed0ed1e5e0ef 100644 (file)
@@ -400,6 +400,9 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
 
 #else /* !CONFIG_PM_SLEEP */
 
+#define device_pm_lock() do {} while (0)
+#define device_pm_unlock() do {} while (0)
+
 static inline int device_suspend(pm_message_t state)
 {
        return 0;
@@ -409,6 +412,14 @@ static inline int device_suspend(pm_message_t state)
 
 #endif /* !CONFIG_PM_SLEEP */
 
+/* How to reorder dpm_list after device_move() */
+enum dpm_order {
+       DPM_ORDER_NONE,
+       DPM_ORDER_DEV_AFTER_PARENT,
+       DPM_ORDER_PARENT_BEFORE_DEV,
+       DPM_ORDER_DEV_LAST,
+};
+
 /*
  * Global Power Management flags
  * Used to keep APM and ACPI from both being active
index 011db2f4c94c056595625d19b452adf7c6f65625..2c36f62e754441901e06600ae89cd3de1c4cd4c6 100644 (file)
@@ -1175,6 +1175,8 @@ struct task_struct {
        /* ??? */
        unsigned int personality;
        unsigned did_exec:1;
+       unsigned in_execve:1;   /* Tell the LSMs that the process is doing an
+                                * execve */
        pid_t pid;
        pid_t tgid;
 
diff --git a/include/linux/sh_cmt.h b/include/linux/sh_cmt.h
new file mode 100644 (file)
index 0000000..68cacde
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __SH_CMT_H__
+#define __SH_CMT_H__
+
+struct sh_cmt_config {
+       char *name;
+       unsigned long channel_offset;
+       int timer_bit;
+       char *clk;
+       unsigned long clockevent_rating;
+       unsigned long clocksource_rating;
+};
+
+#endif /* __SH_CMT_H__ */
index 68e212ff9dde57aa9141076881cd15b8302b5a4a..eb1423a0078d45f340af21ab325d8a93d9916139 100644 (file)
@@ -85,6 +85,7 @@ struct intc_desc symbol __initdata = {                                        \
 }
 #endif
 
+unsigned int intc_evt2irq(unsigned int vector);
 void __init register_intc_controller(struct intc_desc *desc);
 int intc_set_priority(unsigned int irq, unsigned int prio);
 
diff --git a/include/linux/timeriomem-rng.h b/include/linux/timeriomem-rng.h
new file mode 100644 (file)
index 0000000..dd25317
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * linux/include/linux/timeriomem-rng.h
+ *
+ * Copyright (c) 2009 Alexander Clouter <alex@digriz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/completion.h>
+
+struct timeriomem_rng_data {
+       struct completion       completion;
+       unsigned int            present:1;
+
+       u32 __iomem             *address;
+
+       /* measures in usecs */
+       unsigned int            period;
+};
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
new file mode 100644 (file)
index 0000000..3338b3f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Debora Velarde <dvelarde@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+#ifndef __LINUX_TPM_H__
+#define __LINUX_TPM_H__
+
+/*
+ * Chip num is this value or a valid tpm idx
+ */
+#define        TPM_ANY_NUM 0xFFFF
+
+#if defined(CONFIG_TCG_TPM)
+
+extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
+extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
+#endif
+#endif
index a0bb6bd2e5c1795bfdbebe75f672c5c439b5be53..5dcc9ff72f6954874faa92c13a351ee548a51962 100644 (file)
@@ -22,6 +22,7 @@ struct uio_map;
 
 /**
  * struct uio_mem - description of a UIO memory region
+ * @name:              name of the memory region for identification
  * @addr:              address of the device's memory
  * @size:              size of IO
  * @memtype:           type of memory addr points to
@@ -29,6 +30,7 @@ struct uio_map;
  * @map:               for use by the UIO core only.
  */
 struct uio_mem {
+       const char              *name;
        unsigned long           addr;
        unsigned long           size;
        int                     memtype;
@@ -42,12 +44,14 @@ struct uio_portio;
 
 /**
  * struct uio_port - description of a UIO port region
+ * @name:              name of the port region for identification
  * @start:             start of port region
  * @size:              size of port region
  * @porttype:          type of port (see UIO_PORT_* below)
  * @portio:            for use by the UIO core only.
  */
 struct uio_port {
+       const char              *name;
        unsigned long           start;
        unsigned long           size;
        int                     porttype;
index ba0c49399a8345ce2b82c0583d462d46f66fb797..c703e034042371732ad3591bc9800fe4b213e1f5 100644 (file)
@@ -178,7 +178,7 @@ void __d_head(char *head, size_t head_size,
                WARN_ON(1);
        } else
                snprintf(head, head_size, "%s %s: ",
-                        dev_driver_string(dev), dev->bus_id);
+                        dev_driver_string(dev), dev_name(dev));
 }
 
 
index b3aa62ee3c8d4ebf2cc1d29ccbc0f5ba7ddbc5a3..d010858c33c2f975d3ed606c0102e1e8888287d4 100644 (file)
@@ -169,5 +169,7 @@ extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
 
 extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
 extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
+extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
+                            struct snd_timer **rtimer);
 
 #endif /* __SOUND_AD1816A_H */
index 1c02ed1d7c4aab6f49dcb8616437d4d24da25db9..fad3e0c7b932942827801d0f457fc3d8dfa0a736 100644 (file)
@@ -126,12 +126,10 @@ struct snd_hwdep_dsp_image {
        unsigned long driver_data;      /* W: driver-specific data */
 };
 
-enum {
-       SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
-       SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct snd_hwdep_info),
-       SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct snd_hwdep_dsp_status),
-       SNDRV_HWDEP_IOCTL_DSP_LOAD   = _IOW('H', 0x03, struct snd_hwdep_dsp_image)
-};
+#define SNDRV_HWDEP_IOCTL_PVERSION     _IOR ('H', 0x00, int)
+#define SNDRV_HWDEP_IOCTL_INFO         _IOR ('H', 0x01, struct snd_hwdep_info)
+#define SNDRV_HWDEP_IOCTL_DSP_STATUS   _IOR('H', 0x02, struct snd_hwdep_dsp_status)
+#define SNDRV_HWDEP_IOCTL_DSP_LOAD     _IOW('H', 0x03, struct snd_hwdep_dsp_image)
 
 /*****************************************************************************
  *                                                                           *
@@ -451,40 +449,35 @@ enum {
        SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
 };
 
-enum {
-       SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
-       SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct snd_pcm_info),
-       SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
-       SNDRV_PCM_IOCTL_TTSTAMP = _IOW('A', 0x03, int),
-       SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct snd_pcm_hw_params),
-       SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct snd_pcm_hw_params),
-       SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12),
-       SNDRV_PCM_IOCTL_SW_PARAMS = _IOWR('A', 0x13, struct snd_pcm_sw_params),
-       SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct snd_pcm_status),
-       SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, snd_pcm_sframes_t),
-       SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22),
-       SNDRV_PCM_IOCTL_SYNC_PTR = _IOWR('A', 0x23, struct snd_pcm_sync_ptr),
-       SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct snd_pcm_channel_info),
-       SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40),
-       SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41),
-       SNDRV_PCM_IOCTL_START = _IO('A', 0x42),
-       SNDRV_PCM_IOCTL_DROP = _IO('A', 0x43),
-       SNDRV_PCM_IOCTL_DRAIN = _IO('A', 0x44),
-       SNDRV_PCM_IOCTL_PAUSE = _IOW('A', 0x45, int),
-       SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, snd_pcm_uframes_t),
-       SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
-       SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48),
-       SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, snd_pcm_uframes_t),
-       SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct snd_xferi),
-       SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct snd_xferi),
-       SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct snd_xfern),
-       SNDRV_PCM_IOCTL_READN_FRAMES = _IOR('A', 0x53, struct snd_xfern),
-       SNDRV_PCM_IOCTL_LINK = _IOW('A', 0x60, int),
-       SNDRV_PCM_IOCTL_UNLINK = _IO('A', 0x61),
-};
-
-/* Trick to make alsa-lib/acinclude.m4 happy */
-#define SNDRV_PCM_IOCTL_REWIND SNDRV_PCM_IOCTL_REWIND
+#define SNDRV_PCM_IOCTL_PVERSION       _IOR('A', 0x00, int)
+#define SNDRV_PCM_IOCTL_INFO           _IOR('A', 0x01, struct snd_pcm_info)
+#define SNDRV_PCM_IOCTL_TSTAMP         _IOW('A', 0x02, int)
+#define SNDRV_PCM_IOCTL_TTSTAMP                _IOW('A', 0x03, int)
+#define SNDRV_PCM_IOCTL_HW_REFINE      _IOWR('A', 0x10, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_PARAMS      _IOWR('A', 0x11, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_FREE                _IO('A', 0x12)
+#define SNDRV_PCM_IOCTL_SW_PARAMS      _IOWR('A', 0x13, struct snd_pcm_sw_params)
+#define SNDRV_PCM_IOCTL_STATUS         _IOR('A', 0x20, struct snd_pcm_status)
+#define SNDRV_PCM_IOCTL_DELAY          _IOR('A', 0x21, snd_pcm_sframes_t)
+#define SNDRV_PCM_IOCTL_HWSYNC         _IO('A', 0x22)
+#define SNDRV_PCM_IOCTL_SYNC_PTR       _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_CHANNEL_INFO   _IOR('A', 0x32, struct snd_pcm_channel_info)
+#define SNDRV_PCM_IOCTL_PREPARE                _IO('A', 0x40)
+#define SNDRV_PCM_IOCTL_RESET          _IO('A', 0x41)
+#define SNDRV_PCM_IOCTL_START          _IO('A', 0x42)
+#define SNDRV_PCM_IOCTL_DROP           _IO('A', 0x43)
+#define SNDRV_PCM_IOCTL_DRAIN          _IO('A', 0x44)
+#define SNDRV_PCM_IOCTL_PAUSE          _IOW('A', 0x45, int)
+#define SNDRV_PCM_IOCTL_REWIND         _IOW('A', 0x46, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_RESUME         _IO('A', 0x47)
+#define SNDRV_PCM_IOCTL_XRUN           _IO('A', 0x48)
+#define SNDRV_PCM_IOCTL_FORWARD                _IOW('A', 0x49, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_WRITEI_FRAMES  _IOW('A', 0x50, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_READI_FRAMES   _IOR('A', 0x51, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_WRITEN_FRAMES  _IOW('A', 0x52, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_READN_FRAMES   _IOR('A', 0x53, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_LINK           _IOW('A', 0x60, int)
+#define SNDRV_PCM_IOCTL_UNLINK         _IO('A', 0x61)
 
 /*****************************************************************************
  *                                                                           *
@@ -538,14 +531,12 @@ struct snd_rawmidi_status {
        unsigned char reserved[16];     /* reserved for future use */
 };
 
-enum {
-       SNDRV_RAWMIDI_IOCTL_PVERSION = _IOR('W', 0x00, int),
-       SNDRV_RAWMIDI_IOCTL_INFO = _IOR('W', 0x01, struct snd_rawmidi_info),
-       SNDRV_RAWMIDI_IOCTL_PARAMS = _IOWR('W', 0x10, struct snd_rawmidi_params),
-       SNDRV_RAWMIDI_IOCTL_STATUS = _IOWR('W', 0x20, struct snd_rawmidi_status),
-       SNDRV_RAWMIDI_IOCTL_DROP = _IOW('W', 0x30, int),
-       SNDRV_RAWMIDI_IOCTL_DRAIN = _IOW('W', 0x31, int),
-};
+#define SNDRV_RAWMIDI_IOCTL_PVERSION   _IOR('W', 0x00, int)
+#define SNDRV_RAWMIDI_IOCTL_INFO       _IOR('W', 0x01, struct snd_rawmidi_info)
+#define SNDRV_RAWMIDI_IOCTL_PARAMS     _IOWR('W', 0x10, struct snd_rawmidi_params)
+#define SNDRV_RAWMIDI_IOCTL_STATUS     _IOWR('W', 0x20, struct snd_rawmidi_status)
+#define SNDRV_RAWMIDI_IOCTL_DROP       _IOW('W', 0x30, int)
+#define SNDRV_RAWMIDI_IOCTL_DRAIN      _IOW('W', 0x31, int)
 
 /*
  *  Timer section - /dev/snd/timer
@@ -654,23 +645,21 @@ struct snd_timer_status {
        unsigned char reserved[64];     /* reserved */
 };
 
-enum {
-       SNDRV_TIMER_IOCTL_PVERSION = _IOR('T', 0x00, int),
-       SNDRV_TIMER_IOCTL_NEXT_DEVICE = _IOWR('T', 0x01, struct snd_timer_id),
-       SNDRV_TIMER_IOCTL_TREAD = _IOW('T', 0x02, int),
-       SNDRV_TIMER_IOCTL_GINFO = _IOWR('T', 0x03, struct snd_timer_ginfo),
-       SNDRV_TIMER_IOCTL_GPARAMS = _IOW('T', 0x04, struct snd_timer_gparams),
-       SNDRV_TIMER_IOCTL_GSTATUS = _IOWR('T', 0x05, struct snd_timer_gstatus),
-       SNDRV_TIMER_IOCTL_SELECT = _IOW('T', 0x10, struct snd_timer_select),
-       SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct snd_timer_info),
-       SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct snd_timer_params),
-       SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct snd_timer_status),
-       /* The following four ioctls are changed since 1.0.9 due to confliction */
-       SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0),
-       SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1),
-       SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2),
-       SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3),
-};
+#define SNDRV_TIMER_IOCTL_PVERSION     _IOR('T', 0x00, int)
+#define SNDRV_TIMER_IOCTL_NEXT_DEVICE  _IOWR('T', 0x01, struct snd_timer_id)
+#define SNDRV_TIMER_IOCTL_TREAD                _IOW('T', 0x02, int)
+#define SNDRV_TIMER_IOCTL_GINFO                _IOWR('T', 0x03, struct snd_timer_ginfo)
+#define SNDRV_TIMER_IOCTL_GPARAMS      _IOW('T', 0x04, struct snd_timer_gparams)
+#define SNDRV_TIMER_IOCTL_GSTATUS      _IOWR('T', 0x05, struct snd_timer_gstatus)
+#define SNDRV_TIMER_IOCTL_SELECT       _IOW('T', 0x10, struct snd_timer_select)
+#define SNDRV_TIMER_IOCTL_INFO         _IOR('T', 0x11, struct snd_timer_info)
+#define SNDRV_TIMER_IOCTL_PARAMS       _IOW('T', 0x12, struct snd_timer_params)
+#define SNDRV_TIMER_IOCTL_STATUS       _IOR('T', 0x14, struct snd_timer_status)
+/* The following four ioctls are changed since 1.0.9 due to confliction */
+#define SNDRV_TIMER_IOCTL_START                _IO('T', 0xa0)
+#define SNDRV_TIMER_IOCTL_STOP         _IO('T', 0xa1)
+#define SNDRV_TIMER_IOCTL_CONTINUE     _IO('T', 0xa2)
+#define SNDRV_TIMER_IOCTL_PAUSE                _IO('T', 0xa3)
 
 struct snd_timer_read {
        unsigned int resolution;
@@ -847,33 +836,31 @@ struct snd_ctl_tlv {
         unsigned int tlv[0];   /* first TLV */
 };
 
-enum {
-       SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
-       SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
-       SNDRV_CTL_IOCTL_ELEM_LIST = _IOWR('U', 0x10, struct snd_ctl_elem_list),
-       SNDRV_CTL_IOCTL_ELEM_INFO = _IOWR('U', 0x11, struct snd_ctl_elem_info),
-       SNDRV_CTL_IOCTL_ELEM_READ = _IOWR('U', 0x12, struct snd_ctl_elem_value),
-       SNDRV_CTL_IOCTL_ELEM_WRITE = _IOWR('U', 0x13, struct snd_ctl_elem_value),
-       SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct snd_ctl_elem_id),
-       SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct snd_ctl_elem_id),
-       SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int),
-       SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
-       SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
-       SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
-       SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
-       SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
-       SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv),
-       SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
-       SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
-       SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
-       SNDRV_CTL_IOCTL_PCM_INFO = _IOWR('U', 0x31, struct snd_pcm_info),
-       SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE = _IOW('U', 0x32, int),
-       SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE = _IOWR('U', 0x40, int),
-       SNDRV_CTL_IOCTL_RAWMIDI_INFO = _IOWR('U', 0x41, struct snd_rawmidi_info),
-       SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE = _IOW('U', 0x42, int),
-       SNDRV_CTL_IOCTL_POWER = _IOWR('U', 0xd0, int),
-       SNDRV_CTL_IOCTL_POWER_STATE = _IOR('U', 0xd1, int),
-};
+#define SNDRV_CTL_IOCTL_PVERSION       _IOR('U', 0x00, int)
+#define SNDRV_CTL_IOCTL_CARD_INFO      _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_ELEM_LIST      _IOWR('U', 0x10, struct snd_ctl_elem_list)
+#define SNDRV_CTL_IOCTL_ELEM_INFO      _IOWR('U', 0x11, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_READ      _IOWR('U', 0x12, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_WRITE     _IOWR('U', 0x13, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_LOCK      _IOW('U', 0x14, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_ELEM_UNLOCK    _IOW('U', 0x15, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
+#define SNDRV_CTL_IOCTL_ELEM_ADD       _IOWR('U', 0x17, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REPLACE   _IOWR('U', 0x18, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REMOVE    _IOWR('U', 0x19, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_TLV_READ       _IOWR('U', 0x1a, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_WRITE      _IOWR('U', 0x1b, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_COMMAND    _IOWR('U', 0x1c, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
+#define SNDRV_CTL_IOCTL_HWDEP_INFO     _IOR('U', 0x21, struct snd_hwdep_info)
+#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE        _IOR('U', 0x30, int)
+#define SNDRV_CTL_IOCTL_PCM_INFO       _IOWR('U', 0x31, struct snd_pcm_info)
+#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_INFO   _IOWR('U', 0x41, struct snd_rawmidi_info)
+#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
+#define SNDRV_CTL_IOCTL_POWER          _IOWR('U', 0xd0, int)
+#define SNDRV_CTL_IOCTL_POWER_STATE    _IOR('U', 0xd1, int)
 
 /*
  *  Read interface.
@@ -919,18 +906,4 @@ struct snd_ctl_event {
 #define SNDRV_CTL_NAME_IEC958_PCM_STREAM               "PCM Stream"
 #define SNDRV_CTL_NAME_IEC958(expl,direction,what)     "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
 
-/*
- *
- */
-
-struct snd_xferv {
-       const struct iovec *vector;
-       unsigned long count;
-};
-
-enum {
-       SNDRV_IOCTL_READV = _IOW('K', 0x00, struct snd_xferv),
-       SNDRV_IOCTL_WRITEV = _IOW('K', 0x01, struct snd_xferv),
-};
-
 #endif /* __SOUND_ASOUND_H */
diff --git a/include/sound/atmel-abdac.h b/include/sound/atmel-abdac.h
new file mode 100644 (file)
index 0000000..edff6a8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Driver for the Atmel Audio Bitstream DAC (ABDAC)
+ *
+ * Copyright (C) 2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __INCLUDE_SOUND_ATMEL_ABDAC_H
+#define __INCLUDE_SOUND_ATMEL_ABDAC_H
+
+#include <linux/dw_dmac.h>
+
+/**
+ * struct atmel_abdac_pdata - board specific ABDAC configuration
+ * @dws: DMA slave interface to use for sound playback.
+ */
+struct atmel_abdac_pdata {
+       struct dw_dma_slave     dws;
+};
+
+#endif /* __INCLUDE_SOUND_ATMEL_ABDAC_H */
diff --git a/include/sound/atmel-ac97c.h b/include/sound/atmel-ac97c.h
new file mode 100644 (file)
index 0000000..e6aabdb
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Driver for the Atmel AC97C controller
+ *
+ * Copyright (C) 2005-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __INCLUDE_SOUND_ATMEL_AC97C_H
+#define __INCLUDE_SOUND_ATMEL_AC97C_H
+
+#include <linux/dw_dmac.h>
+
+#define AC97C_CAPTURE  0x01
+#define AC97C_PLAYBACK 0x02
+#define AC97C_BOTH     (AC97C_CAPTURE | AC97C_PLAYBACK)
+
+/**
+ * struct atmel_ac97c_pdata - board specific AC97C configuration
+ * @rx_dws: DMA slave interface to use for sound capture.
+ * @tx_dws: DMA slave interface to use for sound playback.
+ * @reset_pin: GPIO pin wired to the reset input on the external AC97 codec,
+ *             optional to use, set to -ENODEV if not in use. AC97 layer will
+ *             try to do a software reset of the external codec anyway.
+ * @flags: Flags for which directions should be enabled.
+ *
+ * If the user do not want to use a DMA channel for playback or capture, i.e.
+ * only one feature is required on the board. The slave for playback or capture
+ * can be set to NULL. The AC97C driver will take use of this when setting up
+ * the sound streams.
+ */
+struct ac97c_platform_data {
+       struct dw_dma_slave     rx_dws;
+       struct dw_dma_slave     tx_dws;
+       unsigned int            flags;
+       int                     reset_pin;
+};
+
+#endif /* __INCLUDE_SOUND_ATMEL_AC97C_H */
index 4721b4bba0538360cd808db6c6cc0f13db9a3c7a..ef96f07aa03b112352235f735b7277b0d8d58f9a 100644 (file)
@@ -171,6 +171,54 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
  */
 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
                                                 const unsigned int *tlv);
-int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
-                     
+int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
+                      unsigned int flags);
+/* optional flags for slave */
+#define SND_CTL_SLAVE_NEED_UPDATE      (1 << 0)
+
+/**
+ * snd_ctl_add_slave - Add a virtual slave control
+ * @master: vmaster element
+ * @slave: slave element to add
+ *
+ * Add a virtual slave control to the given master element created via
+ * snd_ctl_create_virtual_master() beforehand.
+ * Returns zero if successful or a negative error code.
+ *
+ * All slaves must be the same type (returning the same information
+ * via info callback).  The fucntion doesn't check it, so it's your
+ * responsibility.
+ *
+ * Also, some additional limitations:
+ * at most two channels,
+ * logarithmic volume control (dB level) thus no linear volume,
+ * master can only attenuate the volume without gain
+ */
+static inline int
+snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
+{
+       return _snd_ctl_add_slave(master, slave, 0);
+}
+
+/**
+ * snd_ctl_add_slave_uncached - Add a virtual slave control
+ * @master: vmaster element
+ * @slave: slave element to add
+ *
+ * Add a virtual slave control to the given master.
+ * Unlike snd_ctl_add_slave(), the element added via this function
+ * is supposed to have volatile values, and get callback is called
+ * at each time quried from the master.
+ *
+ * When the control peeks the hardware values directly and the value
+ * can be changed by other means than the put callback of the element,
+ * this function should be used to keep the value always up-to-date.
+ */
+static inline int
+snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
+                          struct snd_kcontrol *slave)
+{
+       return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
+}
+
 #endif /* __SOUND_CONTROL_H */
index f632484bc7439171d1b682788305981b66e074f4..3dea79829acc0c53673533d421aa9ca15f3b9c06 100644 (file)
@@ -97,9 +97,9 @@ struct snd_device {
 
 struct snd_monitor_file {
        struct file *file;
-       struct snd_monitor_file *next;
        const struct file_operations *disconnected_f_op;
-       struct list_head shutdown_list;
+       struct list_head shutdown_list; /* still need to shutdown */
+       struct list_head list;  /* link of monitor files */
 };
 
 /* main structure for soundcard */
@@ -134,7 +134,7 @@ struct snd_card {
        struct snd_info_entry *proc_id; /* the card id */
        struct proc_dir_entry *proc_root_link;  /* number link to real id */
 
-       struct snd_monitor_file *files; /* all files associated to this card */
+       struct list_head files_list;    /* all files associated to this card */
        struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown
                                                                state */
        spinlock_t files_lock;          /* lock the files for this card */
@@ -296,8 +296,20 @@ int snd_card_locked(int card);
 extern int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int cmd);
 #endif
 
+int snd_card_create(int idx, const char *id,
+                   struct module *module, int extra_size,
+                   struct snd_card **card_ret);
+
+static inline __deprecated
 struct snd_card *snd_card_new(int idx, const char *id,
-                        struct module *module, int extra_size);
+                             struct module *module, int extra_size)
+{
+       struct snd_card *card;
+       if (snd_card_create(idx, id, module, extra_size, &card) < 0)
+               return NULL;
+       return card;
+}
+
 int snd_card_disconnect(struct snd_card *card);
 int snd_card_free(struct snd_card *card);
 int snd_card_free_when_closed(struct snd_card *card);
@@ -446,21 +458,33 @@ static inline int __snd_bug_on(int cond)
 struct snd_pci_quirk {
        unsigned short subvendor;       /* PCI subvendor ID */
        unsigned short subdevice;       /* PCI subdevice ID */
+       unsigned short subdevice_mask;  /* bitmask to match */
        int value;                      /* value */
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        const char *name;               /* name of the device (optional) */
 #endif
 };
 
-#define _SND_PCI_QUIRK_ID(vend,dev) \
-       .subvendor = (vend), .subdevice = (dev)
+#define _SND_PCI_QUIRK_ID_MASK(vend, mask, dev)        \
+       .subvendor = (vend), .subdevice = (dev), .subdevice_mask = (mask)
+#define _SND_PCI_QUIRK_ID(vend, dev) \
+       _SND_PCI_QUIRK_ID_MASK(vend, 0xffff, dev)
 #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 #define SND_PCI_QUIRK(vend,dev,xname,val) \
        {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
+#define SND_PCI_QUIRK_VENDOR(vend, xname, val)                 \
+       {_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val), .name = (xname)}
+#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val)                        \
+       {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev),                       \
+                       .value = (val), .name = (xname)}
 #else
 #define SND_PCI_QUIRK(vend,dev,xname,val) \
        {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
+#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val)                        \
+       {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), .value = (val)}
+#define SND_PCI_QUIRK_VENDOR(vend, xname, val)                 \
+       {_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val)}
 #endif
 
 const struct snd_pci_quirk *
index d9eea013c753209a4dcb90f9bfc69eb95b697559..8c05e47a409053c69ddec36b60aee44b84907330 100644 (file)
 
 struct snd_hwdep;
 
+/* hwdep file ops; all ops can be NULL */
 struct snd_hwdep_ops {
-       long long (*llseek) (struct snd_hwdep *hw, struct file * file, long long offset, int orig);
-       long (*read) (struct snd_hwdep *hw, char __user *buf, long count, loff_t *offset);
-       long (*write) (struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset);
-       int (*open) (struct snd_hwdep * hw, struct file * file);
-       int (*release) (struct snd_hwdep *hw, struct file * file);
-       unsigned int (*poll) (struct snd_hwdep *hw, struct file * file, poll_table * wait);
-       int (*ioctl) (struct snd_hwdep *hw, struct file * file, unsigned int cmd, unsigned long arg);
-       int (*ioctl_compat) (struct snd_hwdep *hw, struct file * file, unsigned int cmd, unsigned long arg);
-       int (*mmap) (struct snd_hwdep *hw, struct file * file, struct vm_area_struct * vma);
-       int (*dsp_status) (struct snd_hwdep *hw, struct snd_hwdep_dsp_status *status);
-       int (*dsp_load) (struct snd_hwdep *hw, struct snd_hwdep_dsp_image *image);
+       long long (*llseek)(struct snd_hwdep *hw, struct file *file,
+                           long long offset, int orig);
+       long (*read)(struct snd_hwdep *hw, char __user *buf,
+                    long count, loff_t *offset);
+       long (*write)(struct snd_hwdep *hw, const char __user *buf,
+                     long count, loff_t *offset);
+       int (*open)(struct snd_hwdep *hw, struct file * file);
+       int (*release)(struct snd_hwdep *hw, struct file * file);
+       unsigned int (*poll)(struct snd_hwdep *hw, struct file *file,
+                            poll_table *wait);
+       int (*ioctl)(struct snd_hwdep *hw, struct file *file,
+                    unsigned int cmd, unsigned long arg);
+       int (*ioctl_compat)(struct snd_hwdep *hw, struct file *file,
+                           unsigned int cmd, unsigned long arg);
+       int (*mmap)(struct snd_hwdep *hw, struct file *file,
+                   struct vm_area_struct *vma);
+       int (*dsp_status)(struct snd_hwdep *hw,
+                         struct snd_hwdep_dsp_status *status);
+       int (*dsp_load)(struct snd_hwdep *hw,
+                       struct snd_hwdep_dsp_image *image);
 };
 
 struct snd_hwdep {
@@ -61,9 +71,9 @@ struct snd_hwdep {
        void (*private_free) (struct snd_hwdep *hwdep);
 
        struct mutex open_mutex;
-       int used;
-       unsigned int dsp_loaded;
-       unsigned int exclusive: 1;
+       int used;                       /* reference counter */
+       unsigned int dsp_loaded;        /* bit fields of loaded dsp indices */
+       unsigned int exclusive:1;       /* exclusive access mode */
 };
 
 extern int snd_hwdep_new(struct snd_card *card, char *id, int device,
index 2e0315cdd0d6780636d25dce4304dba14702238c..6b013c6f6a049b980c6b6de1f7ac4f094597ef24 100644 (file)
@@ -30,6 +30,9 @@ struct input_dev;
 /**
  * Jack types which can be reported.  These values are used as a
  * bitmask.
+ *
+ * Note that this must be kept in sync with the lookup table in
+ * sound/core/jack.c.
  */
 enum snd_jack_types {
        SND_JACK_HEADPHONE      = 0x0001,
@@ -37,6 +40,8 @@ enum snd_jack_types {
        SND_JACK_HEADSET        = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
        SND_JACK_LINEOUT        = 0x0004,
        SND_JACK_MECHANICAL     = 0x0008, /* If detected separately */
+       SND_JACK_VIDEOOUT       = 0x0010,
+       SND_JACK_AVOUT          = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
 };
 
 struct snd_jack {
index 40c5a6fa6bcd3635334f0405ee0d53f37c3944c7..8904b1900d7ffa7969bf82603a9142dc8d2f7807 100644 (file)
@@ -364,7 +364,6 @@ struct snd_pcm_substream {
         /* -- timer section -- */
        struct snd_timer *timer;                /* timer */
        unsigned timer_running: 1;      /* time is running */
-       spinlock_t timer_lock;
        /* -- next substream -- */
        struct snd_pcm_substream *next;
        /* -- linked substreams -- */
@@ -451,7 +450,7 @@ struct snd_pcm_notify {
 
 extern const struct file_operations snd_pcm_f_ops[2];
 
-int snd_pcm_new(struct snd_card *card, char *id, int device,
+int snd_pcm_new(struct snd_card *card, const char *id, int device,
                int playback_count, int capture_count,
                struct snd_pcm **rpcm);
 int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count);
index 2fd3d251d9a54e4896453508fcd3bcd86ebfbf26..2c894b600e5b972ac3dcbaa617c9e1596f8056e3 100644 (file)
@@ -42,4 +42,19 @@ extern int pxa2xx_ac97_hw_resume(void);
 extern int pxa2xx_ac97_hw_probe(struct platform_device *dev);
 extern void pxa2xx_ac97_hw_remove(struct platform_device *dev);
 
+/* AC97 platform_data */
+/**
+ * struct pxa2xx_ac97_platform_data - pxa ac97 platform data
+ * @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95)
+ *              a -1 value means no gpio will be used for reset
+ *
+ * Platform data should only be specified for pxa27x CPUs where a silicon bug
+ * prevents correct operation of the reset line. If not specified, the default
+ * behaviour is to consider gpio 113 as the AC97 reset line, which is the
+ * default on most boards.
+ */
+struct pxa2xx_ac97_platform_data {
+       int reset_gpio;
+};
+
 #endif
index b550a416d075b9d0cefbdd684c24d953a46fd936..c23c26585700a91dc58eaa80d6cb44a6e5cb1248 100644 (file)
@@ -42,7 +42,6 @@
 #define SNDRV_RAWMIDI_LFLG_INPUT       (1<<1)
 #define SNDRV_RAWMIDI_LFLG_OPEN                (3<<0)
 #define SNDRV_RAWMIDI_LFLG_APPEND      (1<<2)
-#define        SNDRV_RAWMIDI_LFLG_NOOPENLOCK   (1<<3)
 
 struct snd_rawmidi;
 struct snd_rawmidi_substream;
index 85f93c5fe1e4030b297a1381819db5aafa82c235..4e62ee1e4115222ad42c1fb52beea6c03b27da52 100644 (file)
@@ -249,6 +249,7 @@ struct snd_sb {
 #define SB_ALS4000_3D_AUTO_MUTE        0x52
 #define SB_ALS4000_ANALOG_BLOCK_CTRL 0x53
 #define SB_ALS4000_3D_DELAYLINE_PATTERN 0x54
+#define SB_ALS4000_CR3_CONFIGURATION   0xc3 /* bit 7 is Digital Loop Enable */
 #define SB_ALS4000_QSOUND      0xdb
 
 /* IRQ setting bitmap */
@@ -330,7 +331,8 @@ enum {
        SB_MIX_DOUBLE,
        SB_MIX_INPUT_SW,
        SB_MIX_CAPTURE_PRO,
-       SB_MIX_CAPTURE_DT019X
+       SB_MIX_CAPTURE_DT019X,
+       SB_MIX_MONO_CAPTURE_ALS4K
 };
 
 #define SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) \
index 5d1ab9c4950ffae3b370551a4aa30ed7667a10d8..1bce7fd1725f6b4d5a0237fd2410173d6da46344 100644 (file)
@@ -202,13 +202,11 @@ struct snd_emux_misc_mode {
        int value2;     /* reserved */
 };
 
-enum {
-       SNDRV_EMUX_IOCTL_VERSION = _IOR('H', 0x80, unsigned int),
-       SNDRV_EMUX_IOCTL_LOAD_PATCH = _IOWR('H', 0x81, struct soundfont_patch_info),
-       SNDRV_EMUX_IOCTL_RESET_SAMPLES = _IO('H', 0x82),
-       SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES = _IO('H', 0x83),
-       SNDRV_EMUX_IOCTL_MEM_AVAIL = _IOW('H', 0x84, int),
-       SNDRV_EMUX_IOCTL_MISC_MODE = _IOWR('H', 0x84, struct snd_emux_misc_mode),
-};
+#define SNDRV_EMUX_IOCTL_VERSION       _IOR('H', 0x80, unsigned int)
+#define SNDRV_EMUX_IOCTL_LOAD_PATCH    _IOWR('H', 0x81, struct soundfont_patch_info)
+#define SNDRV_EMUX_IOCTL_RESET_SAMPLES _IO('H', 0x82)
+#define SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES _IO('H', 0x83)
+#define SNDRV_EMUX_IOCTL_MEM_AVAIL     _IOW('H', 0x84, int)
+#define SNDRV_EMUX_IOCTL_MISC_MODE     _IOWR('H', 0x84, struct snd_emux_misc_mode)
 
 #endif /* __SOUND_SFNT_INFO_H */
index 24247f763608d7c5b654a0c87f7af5ac6ec7016d..13676472ddfcca7ace85a4bc407c66d40a746b79 100644 (file)
@@ -203,7 +203,7 @@ struct snd_soc_dai {
        int (*resume)(struct snd_soc_dai *dai);
 
        /* ops */
-       struct snd_soc_dai_ops ops;
+       struct snd_soc_dai_ops *ops;
 
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
index dfa804958820d631f52422f55ff2390e477eea9b..a7def6a9a030e00671cb40ea6da2498ffca9caa2 100644 (file)
         wcontrols, wncontrols)\
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
+        wcontrols, wncontrols)\
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
+       .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+       .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
+       wcontrols, wncontrols, wevent, wflags) \
+{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, \
+       .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
 {      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
        .get = snd_soc_dapm_get_value_enum_double, \
        .put = snd_soc_dapm_put_value_enum_double, \
        .private_value = (unsigned long)&xenum }
+#define SOC_DAPM_PIN_SWITCH(xname) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
+       .info = snd_soc_dapm_info_pin_switch, \
+       .get = snd_soc_dapm_get_pin_switch, \
+       .put = snd_soc_dapm_put_pin_switch, \
+       .private_value = (unsigned long)xname }
 
 /* dapm stream operations */
 #define SND_SOC_DAPM_STREAM_NOP                        0x0
@@ -228,6 +244,12 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *uncontrol);
+int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *uncontrol);
 int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
        const struct snd_soc_dapm_widget *widget);
 int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
@@ -250,10 +272,10 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
 int snd_soc_dapm_sys_add(struct device *dev);
 
 /* dapm audio pin control and status */
-int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
-int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
-int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
-int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 
 /* dapm widget types */
@@ -263,6 +285,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
        snd_soc_dapm_value_mux,                 /* selects 1 analog signal from many inputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
+       snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
        snd_soc_dapm_adc,                       /* analog to digital converter */
        snd_soc_dapm_dac,                       /* digital to analog converter */
index 24593ac3ea19528749da10d77aeb0ca1e00c3f94..a40bc6f316fc668b6328374315aded850a40262d 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -154,6 +156,8 @@ enum snd_soc_bias_level {
        SND_SOC_BIAS_OFF,
 };
 
+struct snd_jack;
+struct snd_soc_card;
 struct snd_soc_device;
 struct snd_soc_pcm_stream;
 struct snd_soc_ops;
@@ -164,6 +168,11 @@ struct snd_soc_platform;
 struct snd_soc_codec;
 struct soc_enum;
 struct snd_soc_ac97_ops;
+struct snd_soc_jack;
+struct snd_soc_jack_pin;
+#ifdef CONFIG_GPIOLIB
+struct snd_soc_jack_gpio;
+#endif
 
 typedef int (*hw_write_t)(void *,const char* ,int);
 typedef int (*hw_read_t)(void *,char* ,int);
@@ -184,6 +193,19 @@ int snd_soc_init_card(struct snd_soc_device *socdev);
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
        const struct snd_pcm_hardware *hw);
 
+/* Jack reporting */
+int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+                    struct snd_soc_jack *jack);
+void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
+int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
+                         struct snd_soc_jack_pin *pins);
+#ifdef CONFIG_GPIOLIB
+int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+                       struct snd_soc_jack_gpio *gpios);
+void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+                       struct snd_soc_jack_gpio *gpios);
+#endif
+
 /* codec IO */
 #define snd_soc_read(codec, reg) codec->read(codec, reg)
 #define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
@@ -203,6 +225,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
  */
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
        void *data, char *long_name);
+int snd_soc_add_controls(struct snd_soc_codec *codec,
+       const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
@@ -237,6 +261,48 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 
+/**
+ * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
+ *
+ * @pin:    name of the pin to update
+ * @mask:   bits to check for in reported jack status
+ * @invert: if non-zero then pin is enabled when status is not reported
+ */
+struct snd_soc_jack_pin {
+       struct list_head list;
+       const char *pin;
+       int mask;
+       bool invert;
+};
+
+/**
+ * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
+ *
+ * @gpio:         gpio number
+ * @name:         gpio name
+ * @report:       value to report when jack detected
+ * @invert:       report presence in low state
+ * @debouce_time: debouce time in ms
+ */
+#ifdef CONFIG_GPIOLIB
+struct snd_soc_jack_gpio {
+       unsigned int gpio;
+       const char *name;
+       int report;
+       int invert;
+       int debounce_time;
+       struct snd_soc_jack *jack;
+       struct work_struct work;
+};
+#endif
+
+struct snd_soc_jack {
+       struct snd_jack *jack;
+       struct snd_soc_card *card;
+       struct list_head pins;
+       int status;
+};
+
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
        char *stream_name;
@@ -384,6 +450,8 @@ struct snd_soc_card {
 
        struct snd_soc_device *socdev;
 
+       struct snd_soc_codec *codec;
+
        struct snd_soc_platform *platform;
        struct delayed_work delayed_work;
        struct work_struct deferred_resume_work;
@@ -393,7 +461,6 @@ struct snd_soc_card {
 struct snd_soc_device {
        struct device *dev;
        struct snd_soc_card *card;
-       struct snd_soc_codec *codec;
        struct snd_soc_codec_device *codec_dev;
        void *codec_data;
 };
diff --git a/include/sound/uda1341.h b/include/sound/uda1341.h
deleted file mode 100644 (file)
index 110d5dc..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *  linux/include/linux/l3/uda1341.h
- *
- * Philips UDA1341 mixer device driver for ALSA
- *
- * Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License.
- *
- * History:
- *
- * 2002-03-13 Tomas Kasparek Initial release - based on uda1341.h from OSS
- * 2002-03-30 Tomas Kasparek Proc filesystem support, complete mixer and DSP
- *                           features support
- */
-
-#define UDA1341_ALSA_NAME "snd-uda1341"
-
-/*
- * Default rate set after inicialization
- */
-#define AUDIO_RATE_DEFAULT     44100
-
-/*
- * UDA1341 L3 address and command types
- */
-#define UDA1341_L3ADDR         5
-#define UDA1341_DATA0          (UDA1341_L3ADDR << 2 | 0)
-#define UDA1341_DATA1          (UDA1341_L3ADDR << 2 | 1)
-#define UDA1341_STATUS         (UDA1341_L3ADDR << 2 | 2)
-
-enum uda1341_onoff {
-       OFF=0,
-       ON,
-};
-
-enum uda1341_format {
-       I2S=0,
-       LSB16,
-       LSB18,
-       LSB20,
-       MSB,
-       LSB16MSB,
-       LSB18MSB,
-       LSB20MSB,        
-};
-
-enum uda1341_fs {
-       F512=0,
-       F384,
-       F256,
-       Funused,
-};
-
-enum uda1341_peak {
-       BEFORE=0,
-       AFTER,
-};
-
-enum uda1341_filter {
-       FLAT=0,
-       MIN,
-       MIN2,
-       MAX,
-};
-
-enum uda1341_mixer {
-       DOUBLE,
-       LINE,
-       MIC,
-       MIXER,
-};
-
-enum uda1341_deemp {
-       NONE,
-       D32,
-       D44,
-       D48,
-};
-
-enum uda1341_config {
-       CMD_READ_REG = 0,
-       CMD_RESET,
-       CMD_FS,
-       CMD_FORMAT,
-       CMD_OGAIN,
-       CMD_IGAIN,
-       CMD_DAC,
-       CMD_ADC,
-       CMD_VOLUME,
-       CMD_BASS,
-       CMD_TREBBLE,
-       CMD_PEAK,
-       CMD_DEEMP,
-       CMD_MUTE,        
-       CMD_FILTER,
-       CMD_CH1,
-       CMD_CH2,
-       CMD_MIC,       
-       CMD_MIXER,
-       CMD_AGC,
-       CMD_IG,
-       CMD_AGC_TIME,
-       CMD_AGC_LEVEL,
-#ifdef CONFIG_PM
-       CMD_SUSPEND,
-       CMD_RESUME,
-#endif
-       CMD_LAST,
-};
-
-enum write_through {
-       //used in update_bits (write_cfg) to avoid l3_write - just update local copy of regs.
-       REGS_ONLY=0,
-       //update local regs and write value to uda1341 - do l3_write
-       FLUSH,
-};
-
-int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **clnt);
-
-/*
- * Local variables:
- * indent-tabs-mode: t
- * End:
- */
index 2b48237e23bfae6ac9a432059933a2c3555b5a8f..a7e74e23ad2ee92255530f011ad1df12de03e73c 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.18a"
+#define CONFIG_SND_VERSION "1.0.19"
 #define CONFIG_SND_DATE ""
index fd01f22825cdda88235ee4c05aa0a834af309258..6d65f322f1d556f7e5d50af18cd24c153bb2bfe7 100644 (file)
@@ -154,6 +154,7 @@ int snd_wss_create(struct snd_card *card,
                      unsigned short hardware,
                      unsigned short hwshare,
                      struct snd_wss **rchip);
+int snd_wss_free(struct snd_wss *chip);
 int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
 int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
 int snd_wss_mixer(struct snd_wss *chip);
index 05d51d2a792c116630f8d4d1cd28bbdcf754c81f..f239d87e0d37eea4a83106804035432f6c91c331 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -39,6 +39,7 @@
 #include <linux/nsproxy.h>
 #include <linux/mount.h>
 #include <linux/ipc_namespace.h>
+#include <linux/ima.h>
 
 #include <asm/uaccess.h>
 
@@ -383,6 +384,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto no_file;
+       ima_shm_check(file);
 
        id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
        if (id < 0) {
@@ -887,6 +889,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
        if (!file)
                goto out_free;
+       ima_shm_check(file);
 
        file->private_data = sfd;
        file->f_mapping = shp->shm_file->f_mapping;
index 1196f5d117002face7e8424f87024e94df9e8add..77672233387ffc095b746435a90cb0689cabcbf6 100644 (file)
@@ -822,7 +822,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        mutex_lock(&module_mutex);
        /* Store the name of the last unloaded module for diagnostic purposes */
        strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
-       unregister_dynamic_debug_module(mod->name);
+       ddebug_remove_module(mod->name);
        free_module(mod);
 
  out:
@@ -1827,19 +1827,13 @@ static inline void add_kallsyms(struct module *mod,
 }
 #endif /* CONFIG_KALLSYMS */
 
-static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num)
+static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)
 {
-#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
-       unsigned int i;
-
-       for (i = 0; i < num; i++) {
-               register_dynamic_debug_module(debug[i].modname,
-                                             debug[i].type,
-                                             debug[i].logical_modname,
-                                             debug[i].flag_names,
-                                             debug[i].hash, debug[i].hash2);
-       }
-#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */
+#ifdef CONFIG_DYNAMIC_DEBUG
+       if (ddebug_add_module(debug, num, debug->modname))
+               printk(KERN_ERR "dynamic debug error adding module: %s\n",
+                                       debug->modname);
+#endif
 }
 
 static void *module_alloc_update_bounds(unsigned long size)
@@ -2213,12 +2207,13 @@ static noinline struct module *load_module(void __user *umod,
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
        if (!mod->taints) {
-               struct mod_debug *debug;
+               struct _ddebug *debug;
                unsigned int num_debug;
 
                debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
                                     sizeof(*debug), &num_debug);
-               dynamic_printk_setup(debug, num_debug);
+               if (debug)
+                       dynamic_debug_setup(debug, num_debug);
        }
 
        /* sechdrs[0].sh_size is always zero */
index fbb300e6191f09d376ed26abb330265fe51bf0a7..850e0ba41c1e60f7983f2c3e7890bee4b2bec53c 100644 (file)
@@ -20,7 +20,7 @@
 
 struct user_namespace init_user_ns = {
        .kref = {
-               .refcount       = ATOMIC_INIT(1),
+               .refcount       = ATOMIC_INIT(2),
        },
        .creator = &root_user,
 };
index 03c2c24b9083c17aff9372224ec2b22912691ffb..cea9e30a88ff2b26f5b2535f31f227c91ac5625a 100644 (file)
@@ -174,4 +174,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
        bool "Disable obsolete cpumask functions" if DEBUG_PER_CPU_MAPS
        depends on EXPERIMENTAL && BROKEN
 
+#
+# Netlink attribute parsing support is select'ed if needed
+#
+config NLATTR
+       bool
+
 endmenu
index 1bcf9cd4baa08a85633e5758721b7ef21f4df787..8fee0a13ac589a9484b89472274e1d77c44f5f0b 100644 (file)
@@ -847,60 +847,70 @@ config BUILD_DOCSRC
 
          Say N if you are unsure.
 
-config DYNAMIC_PRINTK_DEBUG
-       bool "Enable dynamic printk() call support"
+config DYNAMIC_DEBUG
+       bool "Enable dynamic printk() support"
        default n
        depends on PRINTK
+       depends on DEBUG_FS
        select PRINTK_DEBUG
        help
 
          Compiles debug level messages into the kernel, which would not
          otherwise be available at runtime. These messages can then be
-         enabled/disabled on a per module basis. This mechanism implicitly
-         enables all pr_debug() and dev_dbg() calls. The impact of this
-         compile option is a larger kernel text size of about 2%.
+         enabled/disabled based on various levels of scope - per source file,
+         function, module, format string, and line number. This mechanism
+         implicitly enables all pr_debug() and dev_dbg() calls. The impact of
+         this compile option is a larger kernel text size of about 2%.
 
          Usage:
 
-         Dynamic debugging is controlled by the debugfs file,
-         dynamic_printk/modules. This file contains a list of the modules that
-         can be enabled. The format of the file is the module name, followed
-         by a set of flags that can be enabled. The first flag is always the
-         'enabled' flag. For example:
+         Dynamic debugging is controlled via the 'dynamic_debug/ddebug' file,
+         which is contained in the 'debugfs' filesystem. Thus, the debugfs
+         filesystem must first be mounted before making use of this feature.
+         We refer the control file as: <debugfs>/dynamic_debug/ddebug. This
+         file contains a list of the debug statements that can be enabled. The
+         format for each line of the file is:
 
-               <module_name> <enabled=0/1>
-                               .
-                               .
-                               .
+               filename:lineno [module]function flags format
 
-         <module_name> : Name of the module in which the debug call resides
-         <enabled=0/1> : whether the messages are enabled or not
+         filename : source file of the debug statement
+         lineno : line number of the debug statement
+         module : module that contains the debug statement
+         function : function that contains the debug statement
+          flags : 'p' means the line is turned 'on' for printing
+          format : the format used for the debug statement
 
          From a live system:
 
-               snd_hda_intel enabled=0
-               fixup enabled=0
-               driver enabled=0
+               nullarbor:~ # cat <debugfs>/dynamic_debug/ddebug
+               # filename:lineno [module]function flags format
+               fs/aio.c:222 [aio]__put_ioctx - "__put_ioctx:\040freeing\040%p\012"
+               fs/aio.c:248 [aio]ioctx_alloc - "ENOMEM:\040nr_events\040too\040high\012"
+               fs/aio.c:1770 [aio]sys_io_cancel - "calling\040cancel\012"
 
-         Enable a module:
+         Example usage:
 
-               $echo "set enabled=1 <module_name>" > dynamic_printk/modules
+               // enable the message at line 1603 of file svcsock.c
+               nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
+                                               <debugfs>/dynamic_debug/ddebug
 
-         Disable a module:
+               // enable all the messages in file svcsock.c
+               nullarbor:~ # echo -n 'file svcsock.c +p' >
+                                               <debugfs>/dynamic_debug/ddebug
 
-               $echo "set enabled=0 <module_name>" > dynamic_printk/modules
+               // enable all the messages in the NFS server module
+               nullarbor:~ # echo -n 'module nfsd +p' >
+                                               <debugfs>/dynamic_debug/ddebug
 
-         Enable all modules:
+               // enable all 12 messages in the function svc_process()
+               nullarbor:~ # echo -n 'func svc_process +p' >
+                                               <debugfs>/dynamic_debug/ddebug
 
-               $echo "set enabled=1 all" > dynamic_printk/modules
+               // disable all 12 messages in the function svc_process()
+               nullarbor:~ # echo -n 'func svc_process -p' >
+                                               <debugfs>/dynamic_debug/ddebug
 
-         Disable all modules:
-
-               $echo "set enabled=0 all" > dynamic_printk/modules
-
-         Finally, passing "dynamic_printk" at the command line enables
-         debugging for all modules. This mode can be turned off via the above
-         disable command.
+         See Documentation/dynamic-debug-howto.txt for additional information.
 
 source "samples/Kconfig"
 
index 32b0e64ded27d7c1f614fdc974d0857abfc19bbc..0dd9229fab7ebf914598558f7d79b36f89aecd66 100644 (file)
@@ -82,7 +82,9 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o
 
 obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
 
-obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
+
+obj-$(CONFIG_NLATTR) += nlattr.o
 
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
new file mode 100644 (file)
index 0000000..833139c
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * lib/dynamic_debug.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * source module.
+ *
+ * Copyright (C) 2008 Jason Baron <jbaron@redhat.com>
+ * By Greg Banks <gnb@melbourne.sgi.com>
+ * Copyright (c) 2008 Silicon Graphics Inc.  All Rights Reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kallsyms.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
+#include <linux/sysctl.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/dynamic_debug.h>
+#include <linux/debugfs.h>
+
+extern struct _ddebug __start___verbose[];
+extern struct _ddebug __stop___verbose[];
+
+/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+long long dynamic_debug_enabled;
+EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
+long long dynamic_debug_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
+
+struct ddebug_table {
+       struct list_head link;
+       char *mod_name;
+       unsigned int num_ddebugs;
+       unsigned int num_enabled;
+       struct _ddebug *ddebugs;
+};
+
+struct ddebug_query {
+       const char *filename;
+       const char *module;
+       const char *function;
+       const char *format;
+       unsigned int first_lineno, last_lineno;
+};
+
+struct ddebug_iter {
+       struct ddebug_table *table;
+       unsigned int idx;
+};
+
+static DEFINE_MUTEX(ddebug_lock);
+static LIST_HEAD(ddebug_tables);
+static int verbose = 0;
+
+/* Return the last part of a pathname */
+static inline const char *basename(const char *path)
+{
+       const char *tail = strrchr(path, '/');
+       return tail ? tail+1 : path;
+}
+
+/* format a string into buf[] which describes the _ddebug's flags */
+static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
+                                   size_t maxlen)
+{
+       char *p = buf;
+
+       BUG_ON(maxlen < 4);
+       if (dp->flags & _DPRINTK_FLAGS_PRINT)
+               *p++ = 'p';
+       if (p == buf)
+               *p++ = '-';
+       *p = '\0';
+
+       return buf;
+}
+
+/*
+ * must be called with ddebug_lock held
+ */
+
+static int disabled_hash(char hash, bool first_table)
+{
+       struct ddebug_table *dt;
+       char table_hash_value;
+
+       list_for_each_entry(dt, &ddebug_tables, link) {
+               if (first_table)
+                       table_hash_value = dt->ddebugs->primary_hash;
+               else
+                       table_hash_value = dt->ddebugs->secondary_hash;
+               if (dt->num_enabled && (hash == table_hash_value))
+                       return 0;
+       }
+       return 1;
+}
+
+/*
+ * Search the tables for _ddebug's which match the given
+ * `query' and apply the `flags' and `mask' to them.  Tells
+ * the user which ddebug's were changed, or whether none
+ * were matched.
+ */
+static void ddebug_change(const struct ddebug_query *query,
+                          unsigned int flags, unsigned int mask)
+{
+       int i;
+       struct ddebug_table *dt;
+       unsigned int newflags;
+       unsigned int nfound = 0;
+       char flagbuf[8];
+
+       /* search for matching ddebugs */
+       mutex_lock(&ddebug_lock);
+       list_for_each_entry(dt, &ddebug_tables, link) {
+
+               /* match against the module name */
+               if (query->module != NULL &&
+                   strcmp(query->module, dt->mod_name))
+                       continue;
+
+               for (i = 0 ; i < dt->num_ddebugs ; i++) {
+                       struct _ddebug *dp = &dt->ddebugs[i];
+
+                       /* match against the source filename */
+                       if (query->filename != NULL &&
+                           strcmp(query->filename, dp->filename) &&
+                           strcmp(query->filename, basename(dp->filename)))
+                               continue;
+
+                       /* match against the function */
+                       if (query->function != NULL &&
+                           strcmp(query->function, dp->function))
+                               continue;
+
+                       /* match against the format */
+                       if (query->format != NULL &&
+                           strstr(dp->format, query->format) == NULL)
+                               continue;
+
+                       /* match against the line number range */
+                       if (query->first_lineno &&
+                           dp->lineno < query->first_lineno)
+                               continue;
+                       if (query->last_lineno &&
+                           dp->lineno > query->last_lineno)
+                               continue;
+
+                       nfound++;
+
+                       newflags = (dp->flags & mask) | flags;
+                       if (newflags == dp->flags)
+                               continue;
+
+                       if (!newflags)
+                               dt->num_enabled--;
+                       else if (!dp-flags)
+                               dt->num_enabled++;
+                       dp->flags = newflags;
+                       if (newflags) {
+                               dynamic_debug_enabled |=
+                                               (1LL << dp->primary_hash);
+                               dynamic_debug_enabled2 |=
+                                               (1LL << dp->secondary_hash);
+                       } else {
+                               if (disabled_hash(dp->primary_hash, true))
+                                       dynamic_debug_enabled &=
+                                               ~(1LL << dp->primary_hash);
+                               if (disabled_hash(dp->secondary_hash, false))
+                                       dynamic_debug_enabled2 &=
+                                               ~(1LL << dp->secondary_hash);
+                       }
+                       if (verbose)
+                               printk(KERN_INFO
+                                       "ddebug: changed %s:%d [%s]%s %s\n",
+                                       dp->filename, dp->lineno,
+                                       dt->mod_name, dp->function,
+                                       ddebug_describe_flags(dp, flagbuf,
+                                                       sizeof(flagbuf)));
+               }
+       }
+       mutex_unlock(&ddebug_lock);
+
+       if (!nfound && verbose)
+               printk(KERN_INFO "ddebug: no matches for query\n");
+}
+
+/*
+ * Split the buffer `buf' into space-separated words.
+ * Handles simple " and ' quoting, i.e. without nested,
+ * embedded or escaped \".  Return the number of words
+ * or <0 on error.
+ */
+static int ddebug_tokenize(char *buf, char *words[], int maxwords)
+{
+       int nwords = 0;
+
+       while (*buf) {
+               char *end;
+
+               /* Skip leading whitespace */
+               while (*buf && isspace(*buf))
+                       buf++;
+               if (!*buf)
+                       break;  /* oh, it was trailing whitespace */
+
+               /* Run `end' over a word, either whitespace separated or quoted */
+               if (*buf == '"' || *buf == '\'') {
+                       int quote = *buf++;
+                       for (end = buf ; *end && *end != quote ; end++)
+                               ;
+                       if (!*end)
+                               return -EINVAL; /* unclosed quote */
+               } else {
+                       for (end = buf ; *end && !isspace(*end) ; end++)
+                               ;
+                       BUG_ON(end == buf);
+               }
+               /* Here `buf' is the start of the word, `end' is one past the end */
+
+               if (nwords == maxwords)
+                       return -EINVAL; /* ran out of words[] before bytes */
+               if (*end)
+                       *end++ = '\0';  /* terminate the word */
+               words[nwords++] = buf;
+               buf = end;
+       }
+
+       if (verbose) {
+               int i;
+               printk(KERN_INFO "%s: split into words:", __func__);
+               for (i = 0 ; i < nwords ; i++)
+                       printk(" \"%s\"", words[i]);
+               printk("\n");
+       }
+
+       return nwords;
+}
+
+/*
+ * Parse a single line number.  Note that the empty string ""
+ * is treated as a special case and converted to zero, which
+ * is later treated as a "don't care" value.
+ */
+static inline int parse_lineno(const char *str, unsigned int *val)
+{
+       char *end = NULL;
+       BUG_ON(str == NULL);
+       if (*str == '\0') {
+               *val = 0;
+               return 0;
+       }
+       *val = simple_strtoul(str, &end, 10);
+       return end == NULL || end == str || *end != '\0' ? -EINVAL : 0;
+}
+
+/*
+ * Undo octal escaping in a string, inplace.  This is useful to
+ * allow the user to express a query which matches a format
+ * containing embedded spaces.
+ */
+#define isodigit(c)            ((c) >= '0' && (c) <= '7')
+static char *unescape(char *str)
+{
+       char *in = str;
+       char *out = str;
+
+       while (*in) {
+               if (*in == '\\') {
+                       if (in[1] == '\\') {
+                               *out++ = '\\';
+                               in += 2;
+                               continue;
+                       } else if (in[1] == 't') {
+                               *out++ = '\t';
+                               in += 2;
+                               continue;
+                       } else if (in[1] == 'n') {
+                               *out++ = '\n';
+                               in += 2;
+                               continue;
+                       } else if (isodigit(in[1]) &&
+                                isodigit(in[2]) &&
+                                isodigit(in[3])) {
+                               *out++ = ((in[1] - '0')<<6) |
+                                         ((in[2] - '0')<<3) |
+                                         (in[3] - '0');
+                               in += 4;
+                               continue;
+                       }
+               }
+               *out++ = *in++;
+       }
+       *out = '\0';
+
+       return str;
+}
+
+/*
+ * Parse words[] as a ddebug query specification, which is a series
+ * of (keyword, value) pairs chosen from these possibilities:
+ *
+ * func <function-name>
+ * file <full-pathname>
+ * file <base-filename>
+ * module <module-name>
+ * format <escaped-string-to-find-in-format>
+ * line <lineno>
+ * line <first-lineno>-<last-lineno> // where either may be empty
+ */
+static int ddebug_parse_query(char *words[], int nwords,
+                              struct ddebug_query *query)
+{
+       unsigned int i;
+
+       /* check we have an even number of words */
+       if (nwords % 2 != 0)
+               return -EINVAL;
+       memset(query, 0, sizeof(*query));
+
+       for (i = 0 ; i < nwords ; i += 2) {
+               if (!strcmp(words[i], "func"))
+                       query->function = words[i+1];
+               else if (!strcmp(words[i], "file"))
+                       query->filename = words[i+1];
+               else if (!strcmp(words[i], "module"))
+                       query->module = words[i+1];
+               else if (!strcmp(words[i], "format"))
+                       query->format = unescape(words[i+1]);
+               else if (!strcmp(words[i], "line")) {
+                       char *first = words[i+1];
+                       char *last = strchr(first, '-');
+                       if (last)
+                               *last++ = '\0';
+                       if (parse_lineno(first, &query->first_lineno) < 0)
+                               return -EINVAL;
+                       if (last != NULL) {
+                               /* range <first>-<last> */
+                               if (parse_lineno(last, &query->last_lineno) < 0)
+                                       return -EINVAL;
+                       } else {
+                               query->last_lineno = query->first_lineno;
+                       }
+               } else {
+                       if (verbose)
+                               printk(KERN_ERR "%s: unknown keyword \"%s\"\n",
+                                       __func__, words[i]);
+                       return -EINVAL;
+               }
+       }
+
+       if (verbose)
+               printk(KERN_INFO "%s: q->function=\"%s\" q->filename=\"%s\" "
+                      "q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
+                       __func__, query->function, query->filename,
+                       query->module, query->format, query->first_lineno,
+                       query->last_lineno);
+
+       return 0;
+}
+
+/*
+ * Parse `str' as a flags specification, format [-+=][p]+.
+ * Sets up *maskp and *flagsp to be used when changing the
+ * flags fields of matched _ddebug's.  Returns 0 on success
+ * or <0 on error.
+ */
+static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
+                              unsigned int *maskp)
+{
+       unsigned flags = 0;
+       int op = '=';
+
+       switch (*str) {
+       case '+':
+       case '-':
+       case '=':
+               op = *str++;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (verbose)
+               printk(KERN_INFO "%s: op='%c'\n", __func__, op);
+
+       for ( ; *str ; ++str) {
+               switch (*str) {
+               case 'p':
+                       flags |= _DPRINTK_FLAGS_PRINT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       if (flags == 0)
+               return -EINVAL;
+       if (verbose)
+               printk(KERN_INFO "%s: flags=0x%x\n", __func__, flags);
+
+       /* calculate final *flagsp, *maskp according to mask and op */
+       switch (op) {
+       case '=':
+               *maskp = 0;
+               *flagsp = flags;
+               break;
+       case '+':
+               *maskp = ~0U;
+               *flagsp = flags;
+               break;
+       case '-':
+               *maskp = ~flags;
+               *flagsp = 0;
+               break;
+       }
+       if (verbose)
+               printk(KERN_INFO "%s: *flagsp=0x%x *maskp=0x%x\n",
+                       __func__, *flagsp, *maskp);
+       return 0;
+}
+
+/*
+ * File_ops->write method for <debugfs>/dynamic_debug/conrol.  Gathers the
+ * command text from userspace, parses and executes it.
+ */
+static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
+                                 size_t len, loff_t *offp)
+{
+       unsigned int flags = 0, mask = 0;
+       struct ddebug_query query;
+#define MAXWORDS 9
+       int nwords;
+       char *words[MAXWORDS];
+       char tmpbuf[256];
+
+       if (len == 0)
+               return 0;
+       /* we don't check *offp -- multiple writes() are allowed */
+       if (len > sizeof(tmpbuf)-1)
+               return -E2BIG;
+       if (copy_from_user(tmpbuf, ubuf, len))
+               return -EFAULT;
+       tmpbuf[len] = '\0';
+       if (verbose)
+               printk(KERN_INFO "%s: read %d bytes from userspace\n",
+                       __func__, (int)len);
+
+       nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS);
+       if (nwords < 0)
+               return -EINVAL;
+       if (ddebug_parse_query(words, nwords-1, &query))
+               return -EINVAL;
+       if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
+               return -EINVAL;
+
+       /* actually go and implement the change */
+       ddebug_change(&query, flags, mask);
+
+       *offp += len;
+       return len;
+}
+
+/*
+ * Set the iterator to point to the first _ddebug object
+ * and return a pointer to that first object.  Returns
+ * NULL if there are no _ddebugs at all.
+ */
+static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
+{
+       if (list_empty(&ddebug_tables)) {
+               iter->table = NULL;
+               iter->idx = 0;
+               return NULL;
+       }
+       iter->table = list_entry(ddebug_tables.next,
+                                struct ddebug_table, link);
+       iter->idx = 0;
+       return &iter->table->ddebugs[iter->idx];
+}
+
+/*
+ * Advance the iterator to point to the next _ddebug
+ * object from the one the iterator currently points at,
+ * and returns a pointer to the new _ddebug.  Returns
+ * NULL if the iterator has seen all the _ddebugs.
+ */
+static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
+{
+       if (iter->table == NULL)
+               return NULL;
+       if (++iter->idx == iter->table->num_ddebugs) {
+               /* iterate to next table */
+               iter->idx = 0;
+               if (list_is_last(&iter->table->link, &ddebug_tables)) {
+                       iter->table = NULL;
+                       return NULL;
+               }
+               iter->table = list_entry(iter->table->link.next,
+                                        struct ddebug_table, link);
+       }
+       return &iter->table->ddebugs[iter->idx];
+}
+
+/*
+ * Seq_ops start method.  Called at the start of every
+ * read() call from userspace.  Takes the ddebug_lock and
+ * seeks the seq_file's iterator to the given position.
+ */
+static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
+{
+       struct ddebug_iter *iter = m->private;
+       struct _ddebug *dp;
+       int n = *pos;
+
+       if (verbose)
+               printk(KERN_INFO "%s: called m=%p *pos=%lld\n",
+                       __func__, m, (unsigned long long)*pos);
+
+       mutex_lock(&ddebug_lock);
+
+       if (!n)
+               return SEQ_START_TOKEN;
+       if (n < 0)
+               return NULL;
+       dp = ddebug_iter_first(iter);
+       while (dp != NULL && --n > 0)
+               dp = ddebug_iter_next(iter);
+       return dp;
+}
+
+/*
+ * Seq_ops next method.  Called several times within a read()
+ * call from userspace, with ddebug_lock held.  Walks to the
+ * next _ddebug object with a special case for the header line.
+ */
+static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       struct ddebug_iter *iter = m->private;
+       struct _ddebug *dp;
+
+       if (verbose)
+               printk(KERN_INFO "%s: called m=%p p=%p *pos=%lld\n",
+                       __func__, m, p, (unsigned long long)*pos);
+
+       if (p == SEQ_START_TOKEN)
+               dp = ddebug_iter_first(iter);
+       else
+               dp = ddebug_iter_next(iter);
+       ++*pos;
+       return dp;
+}
+
+/*
+ * Seq_ops show method.  Called several times within a read()
+ * call from userspace, with ddebug_lock held.  Formats the
+ * current _ddebug as a single human-readable line, with a
+ * special case for the header line.
+ */
+static int ddebug_proc_show(struct seq_file *m, void *p)
+{
+       struct ddebug_iter *iter = m->private;
+       struct _ddebug *dp = p;
+       char flagsbuf[8];
+
+       if (verbose)
+               printk(KERN_INFO "%s: called m=%p p=%p\n",
+                       __func__, m, p);
+
+       if (p == SEQ_START_TOKEN) {
+               seq_puts(m,
+                       "# filename:lineno [module]function flags format\n");
+               return 0;
+       }
+
+       seq_printf(m, "%s:%u [%s]%s %s \"",
+                  dp->filename, dp->lineno,
+                  iter->table->mod_name, dp->function,
+                  ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
+       seq_escape(m, dp->format, "\t\r\n\"");
+       seq_puts(m, "\"\n");
+
+       return 0;
+}
+
+/*
+ * Seq_ops stop method.  Called at the end of each read()
+ * call from userspace.  Drops ddebug_lock.
+ */
+static void ddebug_proc_stop(struct seq_file *m, void *p)
+{
+       if (verbose)
+               printk(KERN_INFO "%s: called m=%p p=%p\n",
+                       __func__, m, p);
+       mutex_unlock(&ddebug_lock);
+}
+
+static const struct seq_operations ddebug_proc_seqops = {
+       .start = ddebug_proc_start,
+       .next = ddebug_proc_next,
+       .show = ddebug_proc_show,
+       .stop = ddebug_proc_stop
+};
+
+/*
+ * File_ops->open method for <debugfs>/dynamic_debug/control.  Does the seq_file
+ * setup dance, and also creates an iterator to walk the _ddebugs.
+ * Note that we create a seq_file always, even for O_WRONLY files
+ * where it's not needed, as doing so simplifies the ->release method.
+ */
+static int ddebug_proc_open(struct inode *inode, struct file *file)
+{
+       struct ddebug_iter *iter;
+       int err;
+
+       if (verbose)
+               printk(KERN_INFO "%s: called\n", __func__);
+
+       iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+       if (iter == NULL)
+               return -ENOMEM;
+
+       err = seq_open(file, &ddebug_proc_seqops);
+       if (err) {
+               kfree(iter);
+               return err;
+       }
+       ((struct seq_file *) file->private_data)->private = iter;
+       return 0;
+}
+
+static const struct file_operations ddebug_proc_fops = {
+       .owner = THIS_MODULE,
+       .open = ddebug_proc_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release_private,
+       .write = ddebug_proc_write
+};
+
+/*
+ * Allocate a new ddebug_table for the given module
+ * and add it to the global list.
+ */
+int ddebug_add_module(struct _ddebug *tab, unsigned int n,
+                            const char *name)
+{
+       struct ddebug_table *dt;
+       char *new_name;
+
+       dt = kzalloc(sizeof(*dt), GFP_KERNEL);
+       if (dt == NULL)
+               return -ENOMEM;
+       new_name = kstrdup(name, GFP_KERNEL);
+       if (new_name == NULL) {
+               kfree(dt);
+               return -ENOMEM;
+       }
+       dt->mod_name = new_name;
+       dt->num_ddebugs = n;
+       dt->num_enabled = 0;
+       dt->ddebugs = tab;
+
+       mutex_lock(&ddebug_lock);
+       list_add_tail(&dt->link, &ddebug_tables);
+       mutex_unlock(&ddebug_lock);
+
+       if (verbose)
+               printk(KERN_INFO "%u debug prints in module %s\n",
+                                n, dt->mod_name);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ddebug_add_module);
+
+static void ddebug_table_free(struct ddebug_table *dt)
+{
+       list_del_init(&dt->link);
+       kfree(dt->mod_name);
+       kfree(dt);
+}
+
+/*
+ * Called in response to a module being unloaded.  Removes
+ * any ddebug_table's which point at the module.
+ */
+int ddebug_remove_module(char *mod_name)
+{
+       struct ddebug_table *dt, *nextdt;
+       int ret = -ENOENT;
+
+       if (verbose)
+               printk(KERN_INFO "%s: removing module \"%s\"\n",
+                               __func__, mod_name);
+
+       mutex_lock(&ddebug_lock);
+       list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
+               if (!strcmp(dt->mod_name, mod_name)) {
+                       ddebug_table_free(dt);
+                       ret = 0;
+               }
+       }
+       mutex_unlock(&ddebug_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ddebug_remove_module);
+
+static void ddebug_remove_all_tables(void)
+{
+       mutex_lock(&ddebug_lock);
+       while (!list_empty(&ddebug_tables)) {
+               struct ddebug_table *dt = list_entry(ddebug_tables.next,
+                                                     struct ddebug_table,
+                                                     link);
+               ddebug_table_free(dt);
+       }
+       mutex_unlock(&ddebug_lock);
+}
+
+static int __init dynamic_debug_init(void)
+{
+       struct dentry *dir, *file;
+       struct _ddebug *iter, *iter_start;
+       const char *modname = NULL;
+       int ret = 0;
+       int n = 0;
+
+       dir = debugfs_create_dir("dynamic_debug", NULL);
+       if (!dir)
+               return -ENOMEM;
+       file = debugfs_create_file("control", 0644, dir, NULL,
+                                       &ddebug_proc_fops);
+       if (!file) {
+               debugfs_remove(dir);
+               return -ENOMEM;
+       }
+       if (__start___verbose != __stop___verbose) {
+               iter = __start___verbose;
+               modname = iter->modname;
+               iter_start = iter;
+               for (; iter < __stop___verbose; iter++) {
+                       if (strcmp(modname, iter->modname)) {
+                               ret = ddebug_add_module(iter_start, n, modname);
+                               if (ret)
+                                       goto out_free;
+                               n = 0;
+                               modname = iter->modname;
+                               iter_start = iter;
+                       }
+                       n++;
+               }
+               ret = ddebug_add_module(iter_start, n, modname);
+       }
+out_free:
+       if (ret) {
+               ddebug_remove_all_tables();
+               debugfs_remove(dir);
+               debugfs_remove(file);
+       }
+       return 0;
+}
+module_init(dynamic_debug_init);
diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
deleted file mode 100644 (file)
index 165a197..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * lib/dynamic_printk.c
- *
- * make pr_debug()/dev_dbg() calls runtime configurable based upon their
- * their source module.
- *
- * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-#include <linux/fs.h>
-
-extern struct mod_debug __start___verbose[];
-extern struct mod_debug __stop___verbose[];
-
-struct debug_name {
-       struct hlist_node hlist;
-       struct hlist_node hlist2;
-       int hash1;
-       int hash2;
-       char *name;
-       int enable;
-       int type;
-};
-
-static int nr_entries;
-static int num_enabled;
-int dynamic_enabled = DYNAMIC_ENABLED_NONE;
-static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
-       { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
-static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
-       { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
-static DECLARE_MUTEX(debug_list_mutex);
-
-/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
- * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
- * use independent hash functions, to reduce the chance of false positives.
- */
-long long dynamic_printk_enabled;
-EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
-long long dynamic_printk_enabled2;
-EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
-
-/* returns the debug module pointer. */
-static struct debug_name *find_debug_module(char *module_name)
-{
-       int i;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct debug_name *element;
-
-       element = NULL;
-       for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
-               head = &module_table[i];
-               hlist_for_each_entry_rcu(element, node, head, hlist)
-                       if (!strcmp(element->name, module_name))
-                               return element;
-       }
-       return NULL;
-}
-
-/* returns the debug module pointer. */
-static struct debug_name *find_debug_module_hash(char *module_name, int hash)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct debug_name *element;
-
-       element = NULL;
-       head = &module_table[hash];
-       hlist_for_each_entry_rcu(element, node, head, hlist)
-               if (!strcmp(element->name, module_name))
-                       return element;
-       return NULL;
-}
-
-/* caller must hold mutex*/
-static int __add_debug_module(char *mod_name, int hash, int hash2)
-{
-       struct debug_name *new;
-       char *module_name;
-       int ret = 0;
-
-       if (find_debug_module(mod_name)) {
-               ret = -EINVAL;
-               goto out;
-       }
-       module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
-       if (!module_name) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       module_name = strcpy(module_name, mod_name);
-       module_name[strlen(mod_name)] = '\0';
-       new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
-       if (!new) {
-               kfree(module_name);
-               ret = -ENOMEM;
-               goto out;
-       }
-       INIT_HLIST_NODE(&new->hlist);
-       INIT_HLIST_NODE(&new->hlist2);
-       new->name = module_name;
-       new->hash1 = hash;
-       new->hash2 = hash2;
-       hlist_add_head_rcu(&new->hlist, &module_table[hash]);
-       hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
-       nr_entries++;
-out:
-       return ret;
-}
-
-int unregister_dynamic_debug_module(char *mod_name)
-{
-       struct debug_name *element;
-       int ret = 0;
-
-       down(&debug_list_mutex);
-       element = find_debug_module(mod_name);
-       if (!element) {
-               ret = -EINVAL;
-               goto out;
-       }
-       hlist_del_rcu(&element->hlist);
-       hlist_del_rcu(&element->hlist2);
-       synchronize_rcu();
-       kfree(element->name);
-       if (element->enable)
-               num_enabled--;
-       kfree(element);
-       nr_entries--;
-out:
-       up(&debug_list_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
-
-int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
-                                       char *flags, int hash, int hash2)
-{
-       struct debug_name *elem;
-       int ret = 0;
-
-       down(&debug_list_mutex);
-       elem = find_debug_module(mod_name);
-       if (!elem) {
-               if (__add_debug_module(mod_name, hash, hash2))
-                       goto out;
-               elem = find_debug_module(mod_name);
-               if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
-                               !strcmp(mod_name, share_name)) {
-                       elem->enable = true;
-                       num_enabled++;
-               }
-       }
-       elem->type |= type;
-out:
-       up(&debug_list_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
-
-int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
-{
-       struct debug_name *elem;
-       int ret = 0;
-
-       if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
-               return 1;
-       rcu_read_lock();
-       elem = find_debug_module_hash(mod_name, hash);
-       if (elem && elem->enable)
-               ret = 1;
-       rcu_read_unlock();
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
-
-static void set_all(bool enable)
-{
-       struct debug_name *e;
-       struct hlist_node *node;
-       int i;
-       long long enable_mask;
-
-       for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
-               if (module_table[i].first != NULL) {
-                       hlist_for_each_entry(e, node, &module_table[i], hlist) {
-                               e->enable = enable;
-                       }
-               }
-       }
-       if (enable)
-               enable_mask = ULLONG_MAX;
-       else
-               enable_mask = 0;
-       dynamic_printk_enabled = enable_mask;
-       dynamic_printk_enabled2 = enable_mask;
-}
-
-static int disabled_hash(int i, bool first_table)
-{
-       struct debug_name *e;
-       struct hlist_node *node;
-
-       if (first_table) {
-               hlist_for_each_entry(e, node, &module_table[i], hlist) {
-                       if (e->enable)
-                               return 0;
-               }
-       } else {
-               hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
-                       if (e->enable)
-                               return 0;
-               }
-       }
-       return 1;
-}
-
-static ssize_t pr_debug_write(struct file *file, const char __user *buf,
-                               size_t length, loff_t *ppos)
-{
-       char *buffer, *s, *value_str, *setting_str;
-       int err, value;
-       struct debug_name *elem = NULL;
-       int all = 0;
-
-       if (length > PAGE_SIZE || length < 0)
-               return -EINVAL;
-
-       buffer = (char *)__get_free_page(GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       err = -EFAULT;
-       if (copy_from_user(buffer, buf, length))
-               goto out;
-
-       err = -EINVAL;
-       if (length < PAGE_SIZE)
-               buffer[length] = '\0';
-       else if (buffer[PAGE_SIZE-1])
-               goto out;
-
-       err = -EINVAL;
-       down(&debug_list_mutex);
-
-       if (strncmp("set", buffer, 3))
-               goto out_up;
-       s = buffer + 3;
-       setting_str = strsep(&s, "=");
-       if (s == NULL)
-               goto out_up;
-       setting_str = strstrip(setting_str);
-       value_str = strsep(&s, " ");
-       if (s == NULL)
-               goto out_up;
-       s = strstrip(s);
-       if (!strncmp(s, "all", 3))
-               all = 1;
-       else
-               elem = find_debug_module(s);
-       if (!strncmp(setting_str, "enable", 6)) {
-               value = !!simple_strtol(value_str, NULL, 10);
-               if (all) {
-                       if (value) {
-                               set_all(true);
-                               num_enabled = nr_entries;
-                               dynamic_enabled = DYNAMIC_ENABLED_ALL;
-                       } else {
-                               set_all(false);
-                               num_enabled = 0;
-                               dynamic_enabled = DYNAMIC_ENABLED_NONE;
-                       }
-                       err = 0;
-               } else if (elem) {
-                       if (value && (elem->enable == 0)) {
-                               dynamic_printk_enabled |= (1LL << elem->hash1);
-                               dynamic_printk_enabled2 |= (1LL << elem->hash2);
-                               elem->enable = 1;
-                               num_enabled++;
-                               dynamic_enabled = DYNAMIC_ENABLED_SOME;
-                               err = 0;
-                               printk(KERN_DEBUG
-                                       "debugging enabled for module %s\n",
-                                       elem->name);
-                       } else if (!value && (elem->enable == 1)) {
-                               elem->enable = 0;
-                               num_enabled--;
-                               if (disabled_hash(elem->hash1, true))
-                                       dynamic_printk_enabled &=
-                                                       ~(1LL << elem->hash1);
-                               if (disabled_hash(elem->hash2, false))
-                                       dynamic_printk_enabled2 &=
-                                                       ~(1LL << elem->hash2);
-                               if (num_enabled)
-                                       dynamic_enabled = DYNAMIC_ENABLED_SOME;
-                               else
-                                       dynamic_enabled = DYNAMIC_ENABLED_NONE;
-                               err = 0;
-                               printk(KERN_DEBUG
-                                       "debugging disabled for module %s\n",
-                                       elem->name);
-                       }
-               }
-       }
-       if (!err)
-               err = length;
-out_up:
-       up(&debug_list_mutex);
-out:
-       free_page((unsigned long)buffer);
-       return err;
-}
-
-static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
-{
-       return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
-}
-
-static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
-       (*pos)++;
-       if (*pos >= DEBUG_HASH_TABLE_SIZE)
-               return NULL;
-       return pos;
-}
-
-static void pr_debug_seq_stop(struct seq_file *s, void *v)
-{
-       /* Nothing to do */
-}
-
-static int pr_debug_seq_show(struct seq_file *s, void *v)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct debug_name *elem;
-       unsigned int i = *(loff_t *) v;
-
-       rcu_read_lock();
-       head = &module_table[i];
-       hlist_for_each_entry_rcu(elem, node, head, hlist) {
-               seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
-               seq_printf(s, "\n");
-       }
-       rcu_read_unlock();
-       return 0;
-}
-
-static struct seq_operations pr_debug_seq_ops = {
-       .start = pr_debug_seq_start,
-       .next  = pr_debug_seq_next,
-       .stop  = pr_debug_seq_stop,
-       .show  = pr_debug_seq_show
-};
-
-static int pr_debug_open(struct inode *inode, struct file *filp)
-{
-       return seq_open(filp, &pr_debug_seq_ops);
-}
-
-static const struct file_operations pr_debug_operations = {
-       .open           = pr_debug_open,
-       .read           = seq_read,
-       .write          = pr_debug_write,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static int __init dynamic_printk_init(void)
-{
-       struct dentry *dir, *file;
-       struct mod_debug *iter;
-       unsigned long value;
-
-       dir = debugfs_create_dir("dynamic_printk", NULL);
-       if (!dir)
-               return -ENOMEM;
-       file = debugfs_create_file("modules", 0644, dir, NULL,
-                                       &pr_debug_operations);
-       if (!file) {
-               debugfs_remove(dir);
-               return -ENOMEM;
-       }
-       for (value = (unsigned long)__start___verbose;
-               value < (unsigned long)__stop___verbose;
-               value += sizeof(struct mod_debug)) {
-                       iter = (struct mod_debug *)value;
-                       register_dynamic_debug_module(iter->modname,
-                               iter->type,
-                               iter->logical_modname,
-                               iter->flag_names, iter->hash, iter->hash2);
-       }
-       if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
-               set_all(true);
-       return 0;
-}
-module_init(dynamic_printk_init);
-/* may want to move this earlier so we can get traces as early as possible */
-
-static int __init dynamic_printk_setup(char *str)
-{
-       if (str)
-               return -ENOENT;
-       dynamic_enabled = DYNAMIC_ENABLED_ALL;
-       return 0;
-}
-/* Use early_param(), so we can get debug output as early as possible */
-early_param("dynamic_printk", dynamic_printk_setup);
index 0487d1f64806c645927fdc22ea4a5848f3d9ea5f..a6dec32f2ddd5f683c5d1295358dc11842ebd2e7 100644 (file)
@@ -212,7 +212,7 @@ static int kobject_add_internal(struct kobject *kobj)
  * @fmt: format string used to build the name
  * @vargs: vargs to format the string.
  */
-static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                                  va_list vargs)
 {
        const char *old_name = kobj->name;
index 318328ddbd1cf57b89cc84dc63b2818b480231d9..e68e743bd86134eb11a84d4000512d4291bceaf0 100644 (file)
@@ -118,6 +118,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        kset = top_kobj->kset;
        uevent_ops = kset->uevent_ops;
 
+       /* skip the event, if uevent_suppress is set*/
+       if (kobj->uevent_suppress) {
+               pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
+                                "caused the event to drop!\n",
+                                kobject_name(kobj), kobj, __func__);
+               return 0;
+       }
        /* skip the event, if the filter returns zero. */
        if (uevent_ops && uevent_ops->filter)
                if (!uevent_ops->filter(kset, kobj)) {
@@ -248,7 +255,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                        goto exit;
 
                retval = call_usermodehelper(argv[0], argv,
-                                            env->envp, UMH_WAIT_EXEC);
+                                            env->envp, UMH_NO_WAIT);
        }
 
 exit:
similarity index 99%
rename from net/netlink/attr.c
rename to lib/nlattr.c
index 56c3ce7fe29af8b2bf47dd8bdc41edb93576c70a..80009a24e21dd553a6204310b083ccd5e8bf6cf3 100644 (file)
@@ -281,6 +281,7 @@ int nla_strcmp(const struct nlattr *nla, const char *str)
        return d;
 }
 
+#ifdef CONFIG_NET
 /**
  * __nla_reserve - reserve room for attribute on the skb
  * @skb: socket buffer to reserve room on
@@ -305,6 +306,7 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 
        return nla;
 }
+EXPORT_SYMBOL(__nla_reserve);
 
 /**
  * __nla_reserve_nohdr - reserve room for attribute without header
@@ -325,6 +327,7 @@ void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
 
        return start;
 }
+EXPORT_SYMBOL(__nla_reserve_nohdr);
 
 /**
  * nla_reserve - reserve room for attribute on the skb
@@ -345,6 +348,7 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 
        return __nla_reserve(skb, attrtype, attrlen);
 }
+EXPORT_SYMBOL(nla_reserve);
 
 /**
  * nla_reserve_nohdr - reserve room for attribute without header
@@ -363,6 +367,7 @@ void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
 
        return __nla_reserve_nohdr(skb, attrlen);
 }
+EXPORT_SYMBOL(nla_reserve_nohdr);
 
 /**
  * __nla_put - Add a netlink attribute to a socket buffer
@@ -382,6 +387,7 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
        nla = __nla_reserve(skb, attrtype, attrlen);
        memcpy(nla_data(nla), data, attrlen);
 }
+EXPORT_SYMBOL(__nla_put);
 
 /**
  * __nla_put_nohdr - Add a netlink attribute without header
@@ -399,6 +405,7 @@ void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
        start = __nla_reserve_nohdr(skb, attrlen);
        memcpy(start, data, attrlen);
 }
+EXPORT_SYMBOL(__nla_put_nohdr);
 
 /**
  * nla_put - Add a netlink attribute to a socket buffer
@@ -418,6 +425,7 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
        __nla_put(skb, attrtype, attrlen, data);
        return 0;
 }
+EXPORT_SYMBOL(nla_put);
 
 /**
  * nla_put_nohdr - Add a netlink attribute without header
@@ -436,6 +444,7 @@ int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
        __nla_put_nohdr(skb, attrlen, data);
        return 0;
 }
+EXPORT_SYMBOL(nla_put_nohdr);
 
 /**
  * nla_append - Add a netlink attribute without header or padding
@@ -454,20 +463,13 @@ int nla_append(struct sk_buff *skb, int attrlen, const void *data)
        memcpy(skb_put(skb, attrlen), data, attrlen);
        return 0;
 }
+EXPORT_SYMBOL(nla_append);
+#endif
 
 EXPORT_SYMBOL(nla_validate);
 EXPORT_SYMBOL(nla_parse);
 EXPORT_SYMBOL(nla_find);
 EXPORT_SYMBOL(nla_strlcpy);
-EXPORT_SYMBOL(__nla_reserve);
-EXPORT_SYMBOL(__nla_reserve_nohdr);
-EXPORT_SYMBOL(nla_reserve);
-EXPORT_SYMBOL(nla_reserve_nohdr);
-EXPORT_SYMBOL(__nla_put);
-EXPORT_SYMBOL(__nla_put_nohdr);
-EXPORT_SYMBOL(nla_put);
-EXPORT_SYMBOL(nla_put_nohdr);
 EXPORT_SYMBOL(nla_memcpy);
 EXPORT_SYMBOL(nla_memcmp);
 EXPORT_SYMBOL(nla_strcmp);
-EXPORT_SYMBOL(nla_append);
index 00ced3ee49a8cd393d199656fc816980d4e7b1e6..1abb9185a686d2787125c7af61120b68e726ccb5 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/hugetlb.h>
 #include <linux/profile.h>
 #include <linux/module.h>
@@ -1047,6 +1048,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        }
 
        error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
+       if (error)
+               return error;
+       error = ima_file_mmap(file, prot);
        if (error)
                return error;
 
index 74dc57c74349ff124dd31a3e04531ee503ecedca..40ca7cdb653ec280d8115ff3d8b35cb6ee57669e 100644 (file)
@@ -66,7 +66,7 @@ static inline long sync_writeback_pages(void)
 /*
  * Start background writeback (via pdflush) at this percentage
  */
-int dirty_background_ratio = 5;
+int dirty_background_ratio = 10;
 
 /*
  * dirty_background_bytes starts at 0 (disabled) so that it is a function of
@@ -83,7 +83,7 @@ int vm_highmem_is_dirtyable;
 /*
  * The generator of dirty data starts writeback at this percentage
  */
-int vm_dirty_ratio = 10;
+int vm_dirty_ratio = 20;
 
 /*
  * vm_dirty_bytes starts at 0 (disabled) so that it is a function of
index 4103a239ce843326faca51c61c5b0b105797b24b..7ec78e24a30dcc549670b88643078509bbd12e4d 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/swap.h>
+#include <linux/ima.h>
 
 static struct vfsmount *shm_mnt;
 
@@ -2665,6 +2666,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
        if (IS_ERR(file))
                return PTR_ERR(file);
 
+       ima_shm_check(file);
        if (vma->vm_file)
                fput(vma->vm_file);
        vma->vm_file = file;
index cdb8fdef6c4aaac30b1ba6cf5ace134ea6bfcb89..eab40a481356cdeebafe444b304c0ef83a0de8cd 100644 (file)
@@ -4,6 +4,7 @@
 
 menuconfig NET
        bool "Networking support"
+       select NLATTR
        ---help---
          Unless you really know what you are doing, you should say Y here.
          The reason is that some programs need kernel networking support even
index 1a1f916be44e258a853fcbf4d60483199c976c32..ed82796d4a0fe353a2ac8722221c479957c56907 100644 (file)
@@ -140,7 +140,7 @@ static void del_conn(struct work_struct *work)
                dev = device_find_child(&conn->dev, NULL, __match_tty);
                if (!dev)
                        break;
-               device_move(dev, NULL);
+               device_move(dev, NULL, DPM_ORDER_DEV_LAST);
                put_device(dev);
        }
 
index d030c69cb5a306ee2cf8c89584e286fc4cf1afb9..abdc703a11d2709ea0305f1cf0b9d9ff0965818a 100644 (file)
@@ -731,7 +731,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
        remove_wait_queue(&dev->wait, &wait);
 
        if (err == 0)
-               device_move(dev->tty_dev, rfcomm_get_device(dev));
+               device_move(dev->tty_dev, rfcomm_get_device(dev),
+                           DPM_ORDER_DEV_AFTER_PARENT);
 
        rfcomm_tty_copy_pending(dev);
 
@@ -751,7 +752,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 
        if (atomic_dec_and_test(&dev->opened)) {
                if (dev->tty_dev->parent)
-                       device_move(dev->tty_dev, NULL);
+                       device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
 
                /* Close DLC and dettach TTY */
                rfcomm_dlc_close(dev->dlc, 0);
index 9e169ef2e85443eaff5c8224ccbeaad1d0f4a202..12bd09dbd36c644f05155b66df0a5f2743ae6be7 100644 (file)
@@ -66,7 +66,7 @@ void
                             struct nf_conntrack_expect *exp) __read_mostly;
 EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
 
-#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 /* PptpControlMessageType names */
 const char *const pptp_msg_name[] = {
        "UNKNOWN_MESSAGE",
index e3589c2de49e9b5e6c76c1d4a4e02a58dda5dd46..bdd6ddf4e95beb401ddd883f7caa00b9be389b9d 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the netlink driver.
 #
 
-obj-y                                  := af_netlink.o attr.o genetlink.o
+obj-y                                  := af_netlink.o genetlink.o
index e06365775bdfe16f5c0242f5bb4464a3c72c0c8c..c18fa150b6fe502319c92bd09f98ee984d48819c 100644 (file)
@@ -97,7 +97,7 @@ modname_flags  = $(if $(filter 1,$(words $(modname))),\
                  -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
 
 #hash values
-ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ifdef CONFIG_DYNAMIC_DEBUG
 debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
               -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
 else
index 4eea60b1693e1173960f34e7c73927f5fe61fccb..a3344285ccf4cbd17a66c8fd8118041e3ab5d025 100644 (file)
@@ -710,6 +710,14 @@ static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
        strcat(alias, ":");
        return 1;
 }
+
+static int do_platform_entry(const char *filename,
+                            struct platform_device_id *id, char *alias)
+{
+       sprintf(alias, PLATFORM_MODULE_PREFIX "%s", id->name);
+       return 1;
+}
+
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -849,6 +857,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct dmi_system_id), "dmi",
                         do_dmi_entry, mod);
+       else if (sym_is(symname, "__mod_platform_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct platform_device_id), "platform",
+                        do_platform_entry, mod);
        free(zeros);
 }
 
index 9438535d7fd0f2bec51905538bd27b7f73f3ad25..bb244774e9d765ae10e41768f5dfd5c40f1f3069 100644 (file)
@@ -55,7 +55,8 @@ config SECURITYFS
        bool "Enable the securityfs filesystem"
        help
          This will build the securityfs filesystem.  It is currently used by
-         the TPM bios character driver.  It is not used by SELinux or SMACK.
+         the TPM bios character driver and IMA, an integrity provider.  It is
+         not used by SELinux or SMACK.
 
          If you are unsure how to answer this question, answer N.
 
@@ -134,6 +135,9 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
 
 source security/selinux/Kconfig
 source security/smack/Kconfig
+source security/tomoyo/Kconfig
+
+source security/integrity/ima/Kconfig
 
 endmenu
 
index c05c127fff9a795d9b3c21d7c1a510c6b7a5a4cc..fa77021d9778ac1f32d7ec10e5322a0e6825e5c9 100644 (file)
@@ -5,6 +5,7 @@
 obj-$(CONFIG_KEYS)                     += keys/
 subdir-$(CONFIG_SECURITY_SELINUX)      += selinux
 subdir-$(CONFIG_SECURITY_SMACK)                += smack
+subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 
 # always enable default capabilities
 obj-y          += commoncap.o
@@ -15,5 +16,10 @@ obj-$(CONFIG_SECURITYFS)             += inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
+obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_IMA)                   += integrity/ima
+obj-$(CONFIG_IMA)                      += integrity/ima/built-in.o
index 007ef252dde7b966661f2d1f9d8df4f47cb72927..f3b91bfbe4cb9483ea55e7e64c5c1c52b8c71d0d 100644 (file)
@@ -202,12 +202,11 @@ static int create_by_name(const char *name, mode_t mode,
  * This function returns a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the securityfs_remove() function when the file is
  * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here).  If an error occurs, %NULL is returned.
+ * you are responsible here).  If an error occurs, the function will return
+ * the erorr value (via ERR_PTR).
  *
  * If securityfs is not enabled in the kernel, the value %-ENODEV is
- * returned.  It is not wise to check for this value, but rather, check for
- * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
- * code.
+ * returned.
  */
 struct dentry *securityfs_create_file(const char *name, mode_t mode,
                                   struct dentry *parent, void *data,
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
new file mode 100644 (file)
index 0000000..53d9764
--- /dev/null
@@ -0,0 +1,55 @@
+# IBM Integrity Measurement Architecture
+#
+config IMA
+       bool "Integrity Measurement Architecture(IMA)"
+       depends on ACPI
+       select SECURITYFS
+       select CRYPTO
+       select CRYPTO_HMAC
+       select CRYPTO_MD5
+       select CRYPTO_SHA1
+       select TCG_TPM
+       select TCG_TIS
+       help
+         The Trusted Computing Group(TCG) runtime Integrity
+         Measurement Architecture(IMA) maintains a list of hash
+         values of executables and other sensitive system files,
+         as they are read or executed. If an attacker manages
+         to change the contents of an important system file
+         being measured, we can tell.
+
+         If your system has a TPM chip, then IMA also maintains
+         an aggregate integrity value over this list inside the
+         TPM hardware, so that the TPM can prove to a third party
+         whether or not critical system files have been modified.
+         Read <http://www.usenix.org/events/sec04/tech/sailer.html>
+         to learn more about IMA.
+         If unsure, say N.
+
+config IMA_MEASURE_PCR_IDX
+       int
+       depends on IMA
+       range 8 14
+       default 10
+       help
+         IMA_MEASURE_PCR_IDX determines the TPM PCR register index
+         that IMA uses to maintain the integrity aggregate of the
+         measurement list.  If unsure, use the default 10.
+
+config IMA_AUDIT
+       bool
+       depends on IMA
+       default y
+       help
+         This option adds a kernel parameter 'ima_audit', which
+         allows informational auditing messages to be enabled
+         at boot.  If this option is selected, informational integrity
+         auditing messages can be enabled with 'ima_audit=1' on
+         the kernel command line.
+
+config IMA_LSM_RULES
+       bool
+       depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK)
+       default y
+       help
+         Disabling this option will disregard LSM based policy rules.
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
new file mode 100644 (file)
index 0000000..787c4cb
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for building Trusted Computing Group's(TCG) runtime Integrity
+# Measurement Architecture(IMA).
+#
+
+obj-$(CONFIG_IMA) += ima.o
+
+ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
+        ima_policy.o ima_iint.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
new file mode 100644 (file)
index 0000000..165eb53
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima.h
+ *     internal Integrity Measurement Architecture (IMA) definitions
+ */
+
+#ifndef __LINUX_IMA_H
+#define __LINUX_IMA_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/security.h>
+#include <linux/hash.h>
+#include <linux/tpm.h>
+#include <linux/audit.h>
+
+enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII };
+enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
+
+/* digest size for IMA, fits SHA1 or MD5 */
+#define IMA_DIGEST_SIZE                20
+#define IMA_EVENT_NAME_LEN_MAX 255
+
+#define IMA_HASH_BITS 9
+#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
+
+/* set during initialization */
+extern int ima_initialized;
+extern int ima_used_chip;
+extern char *ima_hash;
+
+/* IMA inode template definition */
+struct ima_template_data {
+       u8 digest[IMA_DIGEST_SIZE];     /* sha1/md5 measurement hash */
+       char file_name[IMA_EVENT_NAME_LEN_MAX + 1];     /* name + \0 */
+};
+
+struct ima_template_entry {
+       u8 digest[IMA_DIGEST_SIZE];     /* sha1 or md5 measurement hash */
+       const char *template_name;
+       int template_len;
+       struct ima_template_data template;
+};
+
+struct ima_queue_entry {
+       struct hlist_node hnext;        /* place in hash collision list */
+       struct list_head later;         /* place in ima_measurements list */
+       struct ima_template_entry *entry;
+};
+extern struct list_head ima_measurements;      /* list of all measurements */
+
+/* declarations */
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                        const unsigned char *fname, const char *op,
+                        const char *cause, int result, int info);
+
+/* Internal IMA function definitions */
+void ima_iintcache_init(void);
+int ima_init(void);
+void ima_cleanup(void);
+int ima_fs_init(void);
+void ima_fs_cleanup(void);
+int ima_add_template_entry(struct ima_template_entry *entry, int violation,
+                          const char *op, struct inode *inode);
+int ima_calc_hash(struct file *file, char *digest);
+int ima_calc_template_hash(int template_len, void *template, char *digest);
+int ima_calc_boot_aggregate(char *digest);
+void ima_add_violation(struct inode *inode, const unsigned char *filename,
+                      const char *op, const char *cause);
+
+/*
+ * used to protect h_table and sha_table
+ */
+extern spinlock_t ima_queue_lock;
+
+struct ima_h_table {
+       atomic_long_t len;      /* number of stored measurements in the list */
+       atomic_long_t violations;
+       struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
+};
+extern struct ima_h_table ima_htable;
+
+static inline unsigned long ima_hash_key(u8 *digest)
+{
+       return hash_long(*digest, IMA_HASH_BITS);
+}
+
+/* iint cache flags */
+#define IMA_MEASURED           1
+#define IMA_IINT_DUMP_STACK    512
+
+/* integrity data associated with an inode */
+struct ima_iint_cache {
+       u64 version;            /* track inode changes */
+       unsigned long flags;
+       u8 digest[IMA_DIGEST_SIZE];
+       struct mutex mutex;     /* protects: version, flags, digest */
+       long readcount;         /* measured files readcount */
+       long writecount;        /* measured files writecount */
+       long opencount;         /* opens reference count */
+       struct kref refcount;   /* ima_iint_cache reference count */
+       struct rcu_head rcu;
+};
+
+/* LIM API function definitions */
+int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
+                    int mask, int function);
+int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
+void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
+                          const unsigned char *filename);
+int ima_store_template(struct ima_template_entry *entry, int violation,
+                      struct inode *inode);
+void ima_template_show(struct seq_file *m, void *e,
+                      enum ima_show_type show);
+
+/* radix tree calls to lookup, insert, delete
+ * integrity data associated with an inode.
+ */
+struct ima_iint_cache *ima_iint_insert(struct inode *inode);
+struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
+struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode);
+void ima_iint_delete(struct inode *inode);
+void iint_free(struct kref *kref);
+void iint_rcu_free(struct rcu_head *rcu);
+
+/* IMA policy related functions */
+enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK };
+
+int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
+void ima_init_policy(void);
+void ima_update_policy(void);
+int ima_parse_add_rule(char *);
+void ima_delete_rules(void);
+
+/* LSM based policy rules require audit */
+#ifdef CONFIG_IMA_LSM_RULES
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+#else
+
+static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
+                                           void **lsmrule)
+{
+       return -EINVAL;
+}
+
+static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
+                                            void *lsmrule,
+                                            struct audit_context *actx)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_IMA_LSM_RULES */
+#endif
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
new file mode 100644 (file)
index 0000000..3cd58b6
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_api.c
+ *     Implements must_measure, collect_measurement, store_measurement,
+ *     and store_template.
+ */
+#include <linux/module.h>
+
+#include "ima.h"
+static const char *IMA_TEMPLATE_NAME = "ima";
+
+/*
+ * ima_store_template - store ima template measurements
+ *
+ * Calculate the hash of a template entry, add the template entry
+ * to an ordered list of measurement entries maintained inside the kernel,
+ * and also update the aggregate integrity value (maintained inside the
+ * configured TPM PCR) over the hashes of the current list of measurement
+ * entries.
+ *
+ * Applications retrieve the current kernel-held measurement list through
+ * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
+ * TPM PCR (called quote) can be retrieved using a TPM user space library
+ * and is used to validate the measurement list.
+ *
+ * Returns 0 on success, error code otherwise
+ */
+int ima_store_template(struct ima_template_entry *entry,
+                      int violation, struct inode *inode)
+{
+       const char *op = "add_template_measure";
+       const char *audit_cause = "hashing_error";
+       int result;
+
+       memset(entry->digest, 0, sizeof(entry->digest));
+       entry->template_name = IMA_TEMPLATE_NAME;
+       entry->template_len = sizeof(entry->template);
+
+       if (!violation) {
+               result = ima_calc_template_hash(entry->template_len,
+                                               &entry->template,
+                                               entry->digest);
+               if (result < 0) {
+                       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+                                           entry->template_name, op,
+                                           audit_cause, result, 0);
+                       return result;
+               }
+       }
+       result = ima_add_template_entry(entry, violation, op, inode);
+       return result;
+}
+
+/*
+ * ima_add_violation - add violation to measurement list.
+ *
+ * Violations are flagged in the measurement list with zero hash values.
+ * By extending the PCR with 0xFF's instead of with zeroes, the PCR
+ * value is invalidated.
+ */
+void ima_add_violation(struct inode *inode, const unsigned char *filename,
+                      const char *op, const char *cause)
+{
+       struct ima_template_entry *entry;
+       int violation = 1;
+       int result;
+
+       /* can overflow, only indicator */
+       atomic_long_inc(&ima_htable.violations);
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry) {
+               result = -ENOMEM;
+               goto err_out;
+       }
+       memset(&entry->template, 0, sizeof(entry->template));
+       strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
+       result = ima_store_template(entry, violation, inode);
+       if (result < 0)
+               kfree(entry);
+err_out:
+       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
+                           op, cause, result, 0);
+}
+
+/**
+ * ima_must_measure - measure decision based on policy.
+ * @inode: pointer to inode to measure
+ * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
+ * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP)
+ *
+ * The policy is defined in terms of keypairs:
+ *             subj=, obj=, type=, func=, mask=, fsmagic=
+ *     subj,obj, and type: are LSM specific.
+ *     func: PATH_CHECK | BPRM_CHECK | FILE_MMAP
+ *     mask: contains the permission mask
+ *     fsmagic: hex value
+ *
+ * Must be called with iint->mutex held.
+ *
+ * Return 0 to measure. Return 1 if already measured.
+ * For matching a DONT_MEASURE policy, no policy, or other
+ * error, return an error code.
+*/
+int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
+                    int mask, int function)
+{
+       int must_measure;
+
+       if (iint->flags & IMA_MEASURED)
+               return 1;
+
+       must_measure = ima_match_policy(inode, function, mask);
+       return must_measure ? 0 : -EACCES;
+}
+
+/*
+ * ima_collect_measurement - collect file measurement
+ *
+ * Calculate the file hash, if it doesn't already exist,
+ * storing the measurement and i_version in the iint.
+ *
+ * Must be called with iint->mutex held.
+ *
+ * Return 0 on success, error code otherwise
+ */
+int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
+{
+       int result = -EEXIST;
+
+       if (!(iint->flags & IMA_MEASURED)) {
+               u64 i_version = file->f_dentry->d_inode->i_version;
+
+               memset(iint->digest, 0, IMA_DIGEST_SIZE);
+               result = ima_calc_hash(file, iint->digest);
+               if (!result)
+                       iint->version = i_version;
+       }
+       return result;
+}
+
+/*
+ * ima_store_measurement - store file measurement
+ *
+ * Create an "ima" template and then store the template by calling
+ * ima_store_template.
+ *
+ * We only get here if the inode has not already been measured,
+ * but the measurement could already exist:
+ *     - multiple copies of the same file on either the same or
+ *       different filesystems.
+ *     - the inode was previously flushed as well as the iint info,
+ *       containing the hashing info.
+ *
+ * Must be called with iint->mutex held.
+ */
+void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
+                          const unsigned char *filename)
+{
+       const char *op = "add_template_measure";
+       const char *audit_cause = "ENOMEM";
+       int result = -ENOMEM;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ima_template_entry *entry;
+       int violation = 0;
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry) {
+               integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
+                                   op, audit_cause, result, 0);
+               return;
+       }
+       memset(&entry->template, 0, sizeof(entry->template));
+       memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
+       strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
+
+       result = ima_store_template(entry, violation, inode);
+       if (!result)
+               iint->flags |= IMA_MEASURED;
+       else
+               kfree(entry);
+}
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
new file mode 100644 (file)
index 0000000..1e082bb
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ *     Audit calls for the integrity subsystem
+ */
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+#include "ima.h"
+
+static int ima_audit;
+
+#ifdef CONFIG_IMA_AUDIT
+
+/* ima_audit_setup - enable informational auditing messages */
+static int __init ima_audit_setup(char *str)
+{
+       unsigned long audit;
+       int rc, result = 0;
+       char *op = "ima_audit";
+       char *cause;
+
+       rc = strict_strtoul(str, 0, &audit);
+       if (rc || audit > 1)
+               result = 1;
+       else
+               ima_audit = audit;
+       cause = ima_audit ? "enabled" : "not_enabled";
+       integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+                           op, cause, result, 0);
+       return 1;
+}
+__setup("ima_audit=", ima_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                        const unsigned char *fname, const char *op,
+                        const char *cause, int result, int audit_info)
+{
+       struct audit_buffer *ab;
+
+       if (!ima_audit && audit_info == 1) /* Skip informational messages */
+               return;
+
+       ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+       audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
+                        current->pid, current->cred->uid,
+                        audit_get_loginuid(current),
+                        audit_get_sessionid(current));
+       audit_log_task_context(ab);
+       switch (audit_msgno) {
+       case AUDIT_INTEGRITY_DATA:
+       case AUDIT_INTEGRITY_METADATA:
+       case AUDIT_INTEGRITY_PCR:
+       case AUDIT_INTEGRITY_STATUS:
+               audit_log_format(ab, " op=%s cause=%s", op, cause);
+               break;
+       case AUDIT_INTEGRITY_HASH:
+               audit_log_format(ab, " op=%s hash=%s", op, cause);
+               break;
+       default:
+               audit_log_format(ab, " op=%s", op);
+       }
+       audit_log_format(ab, " comm=");
+       audit_log_untrustedstring(ab, current->comm);
+       if (fname) {
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, fname);
+       }
+       if (inode)
+               audit_log_format(ab, " dev=%s ino=%lu",
+                                inode->i_sb->s_id, inode->i_ino);
+       audit_log_format(ab, " res=%d", !result ? 0 : 1);
+       audit_log_end(ab);
+}
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
new file mode 100644 (file)
index 0000000..50d572b
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: ima_crypto.c
+ *     Calculates md5/sha1 file hash, template hash, boot-aggreate hash
+ */
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+#include "ima.h"
+
+static int init_desc(struct hash_desc *desc)
+{
+       int rc;
+
+       desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(desc->tfm)) {
+               pr_info("failed to load %s transform: %ld\n",
+                       ima_hash, PTR_ERR(desc->tfm));
+               rc = PTR_ERR(desc->tfm);
+               return rc;
+       }
+       desc->flags = 0;
+       rc = crypto_hash_init(desc);
+       if (rc)
+               crypto_free_hash(desc->tfm);
+       return rc;
+}
+
+/*
+ * Calculate the MD5/SHA1 file digest
+ */
+int ima_calc_hash(struct file *file, char *digest)
+{
+       struct hash_desc desc;
+       struct scatterlist sg[1];
+       loff_t i_size;
+       char *rbuf;
+       int rc, offset = 0;
+
+       rc = init_desc(&desc);
+       if (rc != 0)
+               return rc;
+
+       rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!rbuf) {
+               rc = -ENOMEM;
+               goto out;
+       }
+       i_size = i_size_read(file->f_dentry->d_inode);
+       while (offset < i_size) {
+               int rbuf_len;
+
+               rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
+               if (rbuf_len < 0) {
+                       rc = rbuf_len;
+                       break;
+               }
+               offset += rbuf_len;
+               sg_init_one(sg, rbuf, rbuf_len);
+
+               rc = crypto_hash_update(&desc, sg, rbuf_len);
+               if (rc)
+                       break;
+       }
+       kfree(rbuf);
+       if (!rc)
+               rc = crypto_hash_final(&desc, digest);
+out:
+       crypto_free_hash(desc.tfm);
+       return rc;
+}
+
+/*
+ * Calculate the hash of a given template
+ */
+int ima_calc_template_hash(int template_len, void *template, char *digest)
+{
+       struct hash_desc desc;
+       struct scatterlist sg[1];
+       int rc;
+
+       rc = init_desc(&desc);
+       if (rc != 0)
+               return rc;
+
+       sg_init_one(sg, template, template_len);
+       rc = crypto_hash_update(&desc, sg, template_len);
+       if (!rc)
+               rc = crypto_hash_final(&desc, digest);
+       crypto_free_hash(desc.tfm);
+       return rc;
+}
+
+static void ima_pcrread(int idx, u8 *pcr)
+{
+       if (!ima_used_chip)
+               return;
+
+       if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
+               pr_err("Error Communicating to TPM chip\n");
+}
+
+/*
+ * Calculate the boot aggregate hash
+ */
+int ima_calc_boot_aggregate(char *digest)
+{
+       struct hash_desc desc;
+       struct scatterlist sg;
+       u8 pcr_i[IMA_DIGEST_SIZE];
+       int rc, i;
+
+       rc = init_desc(&desc);
+       if (rc != 0)
+               return rc;
+
+       /* cumulative sha1 over tpm registers 0-7 */
+       for (i = TPM_PCR0; i < TPM_PCR8; i++) {
+               ima_pcrread(i, pcr_i);
+               /* now accumulate with current aggregate */
+               sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE);
+               rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE);
+       }
+       if (!rc)
+               crypto_hash_final(&desc, digest);
+       crypto_free_hash(desc.tfm);
+       return rc;
+}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
new file mode 100644 (file)
index 0000000..ffbe259
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ * Reiner Sailer <sailer@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_fs.c
+ *     implemenents security file system for reporting
+ *     current measurement list and IMA statistics
+ */
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/parser.h>
+
+#include "ima.h"
+
+static int valid_policy = 1;
+#define TMPBUFLEN 12
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+                                    loff_t *ppos, atomic_long_t *val)
+{
+       char tmpbuf[TMPBUFLEN];
+       ssize_t len;
+
+       len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val));
+       return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
+}
+
+static ssize_t ima_show_htable_violations(struct file *filp,
+                                         char __user *buf,
+                                         size_t count, loff_t *ppos)
+{
+       return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
+}
+
+static struct file_operations ima_htable_violations_ops = {
+       .read = ima_show_htable_violations
+};
+
+static ssize_t ima_show_measurements_count(struct file *filp,
+                                          char __user *buf,
+                                          size_t count, loff_t *ppos)
+{
+       return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
+
+}
+
+static struct file_operations ima_measurements_count_ops = {
+       .read = ima_show_measurements_count
+};
+
+/* returns pointer to hlist_node */
+static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t l = *pos;
+       struct ima_queue_entry *qe;
+
+       /* we need a lock since pos could point beyond last element */
+       rcu_read_lock();
+       list_for_each_entry_rcu(qe, &ima_measurements, later) {
+               if (!l--) {
+                       rcu_read_unlock();
+                       return qe;
+               }
+       }
+       rcu_read_unlock();
+       return NULL;
+}
+
+static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct ima_queue_entry *qe = v;
+
+       /* lock protects when reading beyond last element
+        * against concurrent list-extension
+        */
+       rcu_read_lock();
+       qe = list_entry(rcu_dereference(qe->later.next),
+                       struct ima_queue_entry, later);
+       rcu_read_unlock();
+       (*pos)++;
+
+       return (&qe->later == &ima_measurements) ? NULL : qe;
+}
+
+static void ima_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static void ima_putc(struct seq_file *m, void *data, int datalen)
+{
+       while (datalen--)
+               seq_putc(m, *(char *)data++);
+}
+
+/* print format:
+ *       32bit-le=pcr#
+ *       char[20]=template digest
+ *       32bit-le=template name size
+ *       char[n]=template name
+ *       eventdata[n]=template specific data
+ */
+static int ima_measurements_show(struct seq_file *m, void *v)
+{
+       /* the list never shrinks, so we don't need a lock here */
+       struct ima_queue_entry *qe = v;
+       struct ima_template_entry *e;
+       int namelen;
+       u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+
+       /* get entry */
+       e = qe->entry;
+       if (e == NULL)
+               return -1;
+
+       /*
+        * 1st: PCRIndex
+        * PCR used is always the same (config option) in
+        * little-endian format
+        */
+       ima_putc(m, &pcr, sizeof pcr);
+
+       /* 2nd: template digest */
+       ima_putc(m, e->digest, IMA_DIGEST_SIZE);
+
+       /* 3rd: template name size */
+       namelen = strlen(e->template_name);
+       ima_putc(m, &namelen, sizeof namelen);
+
+       /* 4th:  template name */
+       ima_putc(m, (void *)e->template_name, namelen);
+
+       /* 5th:  template specific data */
+       ima_template_show(m, (struct ima_template_data *)&e->template,
+                         IMA_SHOW_BINARY);
+       return 0;
+}
+
+static struct seq_operations ima_measurments_seqops = {
+       .start = ima_measurements_start,
+       .next = ima_measurements_next,
+       .stop = ima_measurements_stop,
+       .show = ima_measurements_show
+};
+
+static int ima_measurements_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &ima_measurments_seqops);
+}
+
+static struct file_operations ima_measurements_ops = {
+       .open = ima_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static void ima_print_digest(struct seq_file *m, u8 *digest)
+{
+       int i;
+
+       for (i = 0; i < IMA_DIGEST_SIZE; i++)
+               seq_printf(m, "%02x", *(digest + i));
+}
+
+void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show)
+{
+       struct ima_template_data *entry = e;
+       int namelen;
+
+       switch (show) {
+       case IMA_SHOW_ASCII:
+               ima_print_digest(m, entry->digest);
+               seq_printf(m, " %s\n", entry->file_name);
+               break;
+       case IMA_SHOW_BINARY:
+               ima_putc(m, entry->digest, IMA_DIGEST_SIZE);
+
+               namelen = strlen(entry->file_name);
+               ima_putc(m, &namelen, sizeof namelen);
+               ima_putc(m, entry->file_name, namelen);
+       default:
+               break;
+       }
+}
+
+/* print in ascii */
+static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+       /* the list never shrinks, so we don't need a lock here */
+       struct ima_queue_entry *qe = v;
+       struct ima_template_entry *e;
+
+       /* get entry */
+       e = qe->entry;
+       if (e == NULL)
+               return -1;
+
+       /* 1st: PCR used (config option) */
+       seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
+
+       /* 2nd: SHA1 template hash */
+       ima_print_digest(m, e->digest);
+
+       /* 3th:  template name */
+       seq_printf(m, " %s ", e->template_name);
+
+       /* 4th:  template specific data */
+       ima_template_show(m, (struct ima_template_data *)&e->template,
+                         IMA_SHOW_ASCII);
+       return 0;
+}
+
+static struct seq_operations ima_ascii_measurements_seqops = {
+       .start = ima_measurements_start,
+       .next = ima_measurements_next,
+       .stop = ima_measurements_stop,
+       .show = ima_ascii_measurements_show
+};
+
+static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &ima_ascii_measurements_seqops);
+}
+
+static struct file_operations ima_ascii_measurements_ops = {
+       .open = ima_ascii_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+                               size_t datalen, loff_t *ppos)
+{
+       char *data;
+       int rc;
+
+       if (datalen >= PAGE_SIZE)
+               return -ENOMEM;
+       if (*ppos != 0) {
+               /* No partial writes. */
+               return -EINVAL;
+       }
+       data = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (copy_from_user(data, buf, datalen)) {
+               kfree(data);
+               return -EFAULT;
+       }
+       *(data + datalen) = '\0';
+       rc = ima_parse_add_rule(data);
+       if (rc < 0) {
+               datalen = -EINVAL;
+               valid_policy = 0;
+       }
+
+       kfree(data);
+       return datalen;
+}
+
+static struct dentry *ima_dir;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
+static atomic_t policy_opencount = ATOMIC_INIT(1);
+/*
+ * ima_open_policy: sequentialize access to the policy file
+ */
+int ima_open_policy(struct inode * inode, struct file * filp)
+{
+       if (atomic_dec_and_test(&policy_opencount))
+               return 0;
+       return -EBUSY;
+}
+
+/*
+ * ima_release_policy - start using the new measure policy rules.
+ *
+ * Initially, ima_measure points to the default policy rules, now
+ * point to the new policy rules, and remove the securityfs policy file,
+ * assuming a valid policy.
+ */
+static int ima_release_policy(struct inode *inode, struct file *file)
+{
+       if (!valid_policy) {
+               ima_delete_rules();
+               valid_policy = 1;
+               atomic_set(&policy_opencount, 1);
+               return 0;
+       }
+       ima_update_policy();
+       securityfs_remove(ima_policy);
+       ima_policy = NULL;
+       return 0;
+}
+
+static struct file_operations ima_measure_policy_ops = {
+       .open = ima_open_policy,
+       .write = ima_write_policy,
+       .release = ima_release_policy
+};
+
+int ima_fs_init(void)
+{
+       ima_dir = securityfs_create_dir("ima", NULL);
+       if (IS_ERR(ima_dir))
+               return -1;
+
+       binary_runtime_measurements =
+           securityfs_create_file("binary_runtime_measurements",
+                                  S_IRUSR | S_IRGRP, ima_dir, NULL,
+                                  &ima_measurements_ops);
+       if (IS_ERR(binary_runtime_measurements))
+               goto out;
+
+       ascii_runtime_measurements =
+           securityfs_create_file("ascii_runtime_measurements",
+                                  S_IRUSR | S_IRGRP, ima_dir, NULL,
+                                  &ima_ascii_measurements_ops);
+       if (IS_ERR(ascii_runtime_measurements))
+               goto out;
+
+       runtime_measurements_count =
+           securityfs_create_file("runtime_measurements_count",
+                                  S_IRUSR | S_IRGRP, ima_dir, NULL,
+                                  &ima_measurements_count_ops);
+       if (IS_ERR(runtime_measurements_count))
+               goto out;
+
+       violations =
+           securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+                                  ima_dir, NULL, &ima_htable_violations_ops);
+       if (IS_ERR(violations))
+               goto out;
+
+       ima_policy = securityfs_create_file("policy",
+                                           S_IRUSR | S_IRGRP | S_IWUSR,
+                                           ima_dir, NULL,
+                                           &ima_measure_policy_ops);
+       if (IS_ERR(ima_policy))
+               goto out;
+
+       return 0;
+out:
+       securityfs_remove(runtime_measurements_count);
+       securityfs_remove(ascii_runtime_measurements);
+       securityfs_remove(binary_runtime_measurements);
+       securityfs_remove(ima_dir);
+       securityfs_remove(ima_policy);
+       return -1;
+}
+
+void __exit ima_fs_cleanup(void)
+{
+       securityfs_remove(violations);
+       securityfs_remove(runtime_measurements_count);
+       securityfs_remove(ascii_runtime_measurements);
+       securityfs_remove(binary_runtime_measurements);
+       securityfs_remove(ima_dir);
+       securityfs_remove(ima_policy);
+}
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
new file mode 100644 (file)
index 0000000..ec79f1e
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_iint.c
+ *     - implements the IMA hooks: ima_inode_alloc, ima_inode_free
+ *     - cache integrity information associated with an inode
+ *       using a radix tree.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/radix-tree.h>
+#include "ima.h"
+
+#define ima_iint_delete ima_inode_free
+
+RADIX_TREE(ima_iint_store, GFP_ATOMIC);
+DEFINE_SPINLOCK(ima_iint_lock);
+
+static struct kmem_cache *iint_cache __read_mostly;
+
+/* ima_iint_find_get - return the iint associated with an inode
+ *
+ * ima_iint_find_get gets a reference to the iint. Caller must
+ * remember to put the iint reference.
+ */
+struct ima_iint_cache *ima_iint_find_get(struct inode *inode)
+{
+       struct ima_iint_cache *iint;
+
+       rcu_read_lock();
+       iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
+       if (!iint)
+               goto out;
+       kref_get(&iint->refcount);
+out:
+       rcu_read_unlock();
+       return iint;
+}
+
+/* Allocate memory for the iint associated with the inode
+ * from the iint_cache slab, initialize the iint, and
+ * insert it into the radix tree.
+ *
+ * On success return a pointer to the iint; on failure return NULL.
+ */
+struct ima_iint_cache *ima_iint_insert(struct inode *inode)
+{
+       struct ima_iint_cache *iint = NULL;
+       int rc = 0;
+
+       if (!ima_initialized)
+               return iint;
+       iint = kmem_cache_alloc(iint_cache, GFP_KERNEL);
+       if (!iint)
+               return iint;
+
+       rc = radix_tree_preload(GFP_KERNEL);
+       if (rc < 0)
+               goto out;
+
+       spin_lock(&ima_iint_lock);
+       rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
+       spin_unlock(&ima_iint_lock);
+out:
+       if (rc < 0) {
+               kmem_cache_free(iint_cache, iint);
+               if (rc == -EEXIST) {
+                       spin_lock(&ima_iint_lock);
+                       iint = radix_tree_lookup(&ima_iint_store,
+                                                (unsigned long)inode);
+                       spin_unlock(&ima_iint_lock);
+               } else
+                       iint = NULL;
+       }
+       radix_tree_preload_end();
+       return iint;
+}
+
+/**
+ * ima_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ *
+ * Return 0 on success, 1 on failure.
+ */
+int ima_inode_alloc(struct inode *inode)
+{
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized)
+               return 0;
+
+       iint = ima_iint_insert(inode);
+       if (!iint)
+               return 1;
+       return 0;
+}
+
+/* ima_iint_find_insert_get - get the iint associated with an inode
+ *
+ * Most insertions are done at inode_alloc, except those allocated
+ * before late_initcall. When the iint does not exist, allocate it,
+ * initialize and insert it, and increment the iint refcount.
+ *
+ * (Can't initialize at security_initcall before any inodes are
+ * allocated, got to wait at least until proc_init.)
+ *
+ *  Return the iint.
+ */
+struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode)
+{
+       struct ima_iint_cache *iint = NULL;
+
+       iint = ima_iint_find_get(inode);
+       if (iint)
+               return iint;
+
+       iint = ima_iint_insert(inode);
+       if (iint)
+               kref_get(&iint->refcount);
+
+       return iint;
+}
+EXPORT_SYMBOL_GPL(ima_iint_find_insert_get);
+
+/* iint_free - called when the iint refcount goes to zero */
+void iint_free(struct kref *kref)
+{
+       struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
+                                                  refcount);
+       iint->version = 0;
+       iint->flags = 0UL;
+       if (iint->readcount != 0) {
+               printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__,
+                      iint->readcount);
+               iint->readcount = 0;
+       }
+       if (iint->writecount != 0) {
+               printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__,
+                      iint->writecount);
+               iint->writecount = 0;
+       }
+       if (iint->opencount != 0) {
+               printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__,
+                      iint->opencount);
+               iint->opencount = 0;
+       }
+       kref_set(&iint->refcount, 1);
+       kmem_cache_free(iint_cache, iint);
+}
+
+void iint_rcu_free(struct rcu_head *rcu_head)
+{
+       struct ima_iint_cache *iint = container_of(rcu_head,
+                                                  struct ima_iint_cache, rcu);
+       kref_put(&iint->refcount, iint_free);
+}
+
+/**
+ * ima_iint_delete - called on integrity_inode_free
+ * @inode: pointer to the inode
+ *
+ * Free the integrity information(iint) associated with an inode.
+ */
+void ima_iint_delete(struct inode *inode)
+{
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized)
+               return;
+       spin_lock(&ima_iint_lock);
+       iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
+       spin_unlock(&ima_iint_lock);
+       if (iint)
+               call_rcu(&iint->rcu, iint_rcu_free);
+}
+
+static void init_once(void *foo)
+{
+       struct ima_iint_cache *iint = foo;
+
+       memset(iint, 0, sizeof *iint);
+       iint->version = 0;
+       iint->flags = 0UL;
+       mutex_init(&iint->mutex);
+       iint->readcount = 0;
+       iint->writecount = 0;
+       iint->opencount = 0;
+       kref_set(&iint->refcount, 1);
+}
+
+void ima_iintcache_init(void)
+{
+       iint_cache =
+           kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
+                             SLAB_PANIC, init_once);
+}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
new file mode 100644 (file)
index 0000000..0b0bb8c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer      <sailer@watson.ibm.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Mimi Zohar         <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_init.c
+ *             initialization and cleanup functions
+ */
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+#include "ima.h"
+
+/* name for boot aggregate entry */
+static const char *boot_aggregate_name = "boot_aggregate";
+int ima_used_chip;
+
+/* Add the boot aggregate to the IMA measurement list and extend
+ * the PCR register.
+ *
+ * Calculate the boot aggregate, a SHA1 over tpm registers 0-7,
+ * assuming a TPM chip exists, and zeroes if the TPM chip does not
+ * exist.  Add the boot aggregate measurement to the measurement
+ * list and extend the PCR register.
+ *
+ * If a tpm chip does not exist, indicate the core root of trust is
+ * not hardware based by invalidating the aggregate PCR value.
+ * (The aggregate PCR value is invalidated by adding one value to
+ * the measurement list and extending the aggregate PCR value with
+ * a different value.) Violations add a zero entry to the measurement
+ * list and extend the aggregate PCR value with ff...ff's.
+ */
+static void ima_add_boot_aggregate(void)
+{
+       struct ima_template_entry *entry;
+       const char *op = "add_boot_aggregate";
+       const char *audit_cause = "ENOMEM";
+       int result = -ENOMEM;
+       int violation = 1;
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               goto err_out;
+
+       memset(&entry->template, 0, sizeof(entry->template));
+       strncpy(entry->template.file_name, boot_aggregate_name,
+               IMA_EVENT_NAME_LEN_MAX);
+       if (ima_used_chip) {
+               violation = 0;
+               result = ima_calc_boot_aggregate(entry->template.digest);
+               if (result < 0) {
+                       audit_cause = "hashing_error";
+                       kfree(entry);
+                       goto err_out;
+               }
+       }
+       result = ima_store_template(entry, violation, NULL);
+       if (result < 0)
+               kfree(entry);
+       return;
+err_out:
+       integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
+                           audit_cause, result, 0);
+}
+
+int ima_init(void)
+{
+       u8 pcr_i[IMA_DIGEST_SIZE];
+       int rc;
+
+       ima_used_chip = 0;
+       rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i);
+       if (rc == 0)
+               ima_used_chip = 1;
+
+       if (!ima_used_chip)
+               pr_info("No TPM chip found, activating TPM-bypass!\n");
+
+       ima_add_boot_aggregate();       /* boot aggregate must be first entry */
+       ima_init_policy();
+
+       return ima_fs_init();
+}
+
+void __exit ima_cleanup(void)
+{
+       ima_fs_cleanup();
+}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
new file mode 100644 (file)
index 0000000..f4e7266
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Serge Hallyn <serue@us.ibm.com>
+ * Kylene Hall <kylene@us.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_main.c
+ *             implements the IMA hooks: ima_bprm_check, ima_file_mmap,
+ *             and ima_path_check.
+ */
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/binfmts.h>
+#include <linux/mount.h>
+#include <linux/mman.h>
+
+#include "ima.h"
+
+int ima_initialized;
+
+char *ima_hash = "sha1";
+static int __init hash_setup(char *str)
+{
+       const char *op = "hash_setup";
+       const char *hash = "sha1";
+       int result = 0;
+       int audit_info = 0;
+
+       if (strncmp(str, "md5", 3) == 0) {
+               hash = "md5";
+               ima_hash = str;
+       } else if (strncmp(str, "sha1", 4) != 0) {
+               hash = "invalid_hash_type";
+               result = 1;
+       }
+       integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
+                           result, audit_info);
+       return 1;
+}
+__setup("ima_hash=", hash_setup);
+
+/**
+ * ima_file_free - called on __fput()
+ * @file: pointer to file structure being freed
+ *
+ * Flag files that changed, based on i_version;
+ * and decrement the iint readcount/writecount.
+ */
+void ima_file_free(struct file *file)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return;
+       iint = ima_iint_find_get(inode);
+       if (!iint)
+               return;
+
+       mutex_lock(&iint->mutex);
+       if (iint->opencount <= 0) {
+               printk(KERN_INFO
+                      "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n",
+                      __FUNCTION__, file->f_dentry->d_name.name,
+                      iint->readcount, iint->writecount,
+                      iint->opencount, atomic_long_read(&file->f_count));
+               if (!(iint->flags & IMA_IINT_DUMP_STACK)) {
+                       dump_stack();
+                       iint->flags |= IMA_IINT_DUMP_STACK;
+               }
+       }
+       iint->opencount--;
+
+       if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+               iint->readcount--;
+
+       if (file->f_mode & FMODE_WRITE) {
+               iint->writecount--;
+               if (iint->writecount == 0) {
+                       if (iint->version != inode->i_version)
+                               iint->flags &= ~IMA_MEASURED;
+               }
+       }
+       mutex_unlock(&iint->mutex);
+       kref_put(&iint->refcount, iint_free);
+}
+
+/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
+ *
+ * When opening a file for read, if the file is already open for write,
+ * the file could change, resulting in a file measurement error.
+ *
+ * Opening a file for write, if the file is already open for read, results
+ * in a time of measure, time of use (ToMToU) error.
+ *
+ * In either case invalidate the PCR.
+ */
+enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
+static void ima_read_write_check(enum iint_pcr_error error,
+                                struct ima_iint_cache *iint,
+                                struct inode *inode,
+                                const unsigned char *filename)
+{
+       switch (error) {
+       case TOMTOU:
+               if (iint->readcount > 0)
+                       ima_add_violation(inode, filename, "invalid_pcr",
+                                         "ToMToU");
+               break;
+       case OPEN_WRITERS:
+               if (iint->writecount > 0)
+                       ima_add_violation(inode, filename, "invalid_pcr",
+                                         "open_writers");
+               break;
+       }
+}
+
+static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
+                               const unsigned char *filename)
+{
+       int rc = 0;
+
+       if (IS_ERR(file)) {
+               pr_info("%s dentry_open failed\n", filename);
+               return rc;
+       }
+       iint->opencount++;
+       iint->readcount++;
+
+       rc = ima_collect_measurement(iint, file);
+       if (!rc)
+               ima_store_measurement(iint, file, filename);
+       return rc;
+}
+
+/**
+ * ima_path_check - based on policy, collect/store measurement.
+ * @path: contains a pointer to the path to be measured
+ * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
+ *
+ * Measure the file being open for readonly, based on the
+ * ima_must_measure() policy decision.
+ *
+ * Keep read/write counters for all files, but only
+ * invalidate the PCR for measured files:
+ *     - Opening a file for write when already open for read,
+ *       results in a time of measure, time of use (ToMToU) error.
+ *     - Opening a file for read when already open for write,
+ *       could result in a file measurement error.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+int ima_path_check(struct path *path, int mask)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct ima_iint_cache *iint;
+       struct file *file = NULL;
+       int rc;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return 0;
+       iint = ima_iint_find_insert_get(inode);
+       if (!iint)
+               return 0;
+
+       mutex_lock(&iint->mutex);
+       iint->opencount++;
+       if ((mask & MAY_WRITE) || (mask == 0))
+               iint->writecount++;
+       else if (mask & (MAY_READ | MAY_EXEC))
+               iint->readcount++;
+
+       rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
+       if (rc < 0)
+               goto out;
+
+       if ((mask & MAY_WRITE) || (mask == 0))
+               ima_read_write_check(TOMTOU, iint, inode,
+                                    path->dentry->d_name.name);
+
+       if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
+               goto out;
+
+       ima_read_write_check(OPEN_WRITERS, iint, inode,
+                            path->dentry->d_name.name);
+       if (!(iint->flags & IMA_MEASURED)) {
+               struct dentry *dentry = dget(path->dentry);
+               struct vfsmount *mnt = mntget(path->mnt);
+
+               file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
+               rc = get_path_measurement(iint, file, dentry->d_name.name);
+       }
+out:
+       mutex_unlock(&iint->mutex);
+       if (file)
+               fput(file);
+       kref_put(&iint->refcount, iint_free);
+       return 0;
+}
+
+static int process_measurement(struct file *file, const unsigned char *filename,
+                              int mask, int function)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ima_iint_cache *iint;
+       int rc;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return 0;
+       iint = ima_iint_find_insert_get(inode);
+       if (!iint)
+               return -ENOMEM;
+
+       mutex_lock(&iint->mutex);
+       rc = ima_must_measure(iint, inode, mask, function);
+       if (rc != 0)
+               goto out;
+
+       rc = ima_collect_measurement(iint, file);
+       if (!rc)
+               ima_store_measurement(iint, file, filename);
+out:
+       mutex_unlock(&iint->mutex);
+       kref_put(&iint->refcount, iint_free);
+       return rc;
+}
+
+static void opencount_get(struct file *file)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return;
+       iint = ima_iint_find_insert_get(inode);
+       if (!iint)
+               return;
+       mutex_lock(&iint->mutex);
+       iint->opencount++;
+       mutex_unlock(&iint->mutex);
+}
+
+/**
+ * ima_file_mmap - based on policy, collect/store measurement.
+ * @file: pointer to the file to be measured (May be NULL)
+ * @prot: contains the protection that will be applied by the kernel.
+ *
+ * Measure files being mmapped executable based on the ima_must_measure()
+ * policy decision.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+int ima_file_mmap(struct file *file, unsigned long prot)
+{
+       int rc;
+
+       if (!file)
+               return 0;
+       if (prot & PROT_EXEC)
+               rc = process_measurement(file, file->f_dentry->d_name.name,
+                                        MAY_EXEC, FILE_MMAP);
+       return 0;
+}
+
+/*
+ * ima_shm_check - IPC shm and shmat create/fput a file
+ *
+ * Maintain the opencount for these files to prevent unnecessary
+ * imbalance messages.
+ */
+void ima_shm_check(struct file *file)
+{
+       opencount_get(file);
+       return;
+}
+
+/**
+ * ima_bprm_check - based on policy, collect/store measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * The OS protects against an executable file, already open for write,
+ * from being executed in deny_write_access() and an executable file,
+ * already open for execute, from being modified in get_write_access().
+ * So we can be certain that what we verify and measure here is actually
+ * what is being executed.
+ *
+ * Return 0 on success, an error code on failure.
+ * (Based on the results of appraise_measurement().)
+ */
+int ima_bprm_check(struct linux_binprm *bprm)
+{
+       int rc;
+
+       rc = process_measurement(bprm->file, bprm->filename,
+                                MAY_EXEC, BPRM_CHECK);
+       return 0;
+}
+
+static int __init init_ima(void)
+{
+       int error;
+
+       ima_iintcache_init();
+       error = ima_init();
+       ima_initialized = 1;
+       return error;
+}
+
+static void __exit cleanup_ima(void)
+{
+       ima_cleanup();
+}
+
+late_initcall(init_ima);       /* Start IMA after the TPM is available */
+
+MODULE_DESCRIPTION("Integrity Measurement Architecture");
+MODULE_LICENSE("GPL");
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
new file mode 100644 (file)
index 0000000..b5291ad
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * ima_policy.c
+ *     - initialize default measure policy rules
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/security.h>
+#include <linux/magic.h>
+#include <linux/parser.h>
+
+#include "ima.h"
+
+/* flags definitions */
+#define IMA_FUNC       0x0001
+#define IMA_MASK       0x0002
+#define IMA_FSMAGIC    0x0004
+#define IMA_UID                0x0008
+
+enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE };
+
+#define MAX_LSM_RULES 6
+enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
+       LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
+};
+
+struct ima_measure_rule_entry {
+       struct list_head list;
+       enum ima_action action;
+       unsigned int flags;
+       enum ima_hooks func;
+       int mask;
+       unsigned long fsmagic;
+       uid_t uid;
+       struct {
+               void *rule;     /* LSM file metadata specific */
+               int type;       /* audit type */
+       } lsm[MAX_LSM_RULES];
+};
+
+/* Without LSM specific knowledge, the default policy can only be
+ * written in terms of .action, .func, .mask, .fsmagic, and .uid
+ */
+static struct ima_measure_rule_entry default_rules[] = {
+       {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
+        .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
+        .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
+       {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
+        .flags = IMA_FUNC | IMA_MASK},
+       {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
+        .flags = IMA_FUNC | IMA_MASK},
+       {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
+        .flags = IMA_FUNC | IMA_MASK | IMA_UID}
+};
+
+static LIST_HEAD(measure_default_rules);
+static LIST_HEAD(measure_policy_rules);
+static struct list_head *ima_measure;
+
+static DEFINE_MUTEX(ima_measure_mutex);
+
+/**
+ * ima_match_rules - determine whether an inode matches the measure rule.
+ * @rule: a pointer to a rule
+ * @inode: a pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns true on rule match, false on failure.
+ */
+static bool ima_match_rules(struct ima_measure_rule_entry *rule,
+                           struct inode *inode, enum ima_hooks func, int mask)
+{
+       struct task_struct *tsk = current;
+       int i;
+
+       if ((rule->flags & IMA_FUNC) && rule->func != func)
+               return false;
+       if ((rule->flags & IMA_MASK) && rule->mask != mask)
+               return false;
+       if ((rule->flags & IMA_FSMAGIC)
+           && rule->fsmagic != inode->i_sb->s_magic)
+               return false;
+       if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
+               return false;
+       for (i = 0; i < MAX_LSM_RULES; i++) {
+               int rc;
+               u32 osid, sid;
+
+               if (!rule->lsm[i].rule)
+                       continue;
+
+               switch (i) {
+               case LSM_OBJ_USER:
+               case LSM_OBJ_ROLE:
+               case LSM_OBJ_TYPE:
+                       security_inode_getsecid(inode, &osid);
+                       rc = security_filter_rule_match(osid,
+                                                       rule->lsm[i].type,
+                                                       AUDIT_EQUAL,
+                                                       rule->lsm[i].rule,
+                                                       NULL);
+                       break;
+               case LSM_SUBJ_USER:
+               case LSM_SUBJ_ROLE:
+               case LSM_SUBJ_TYPE:
+                       security_task_getsecid(tsk, &sid);
+                       rc = security_filter_rule_match(sid,
+                                                       rule->lsm[i].type,
+                                                       AUDIT_EQUAL,
+                                                       rule->lsm[i].rule,
+                                                       NULL);
+               default:
+                       break;
+               }
+               if (!rc)
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * ima_match_policy - decision based on LSM and other conditions
+ * @inode: pointer to an inode for which the policy decision is being made
+ * @func: IMA hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
+ * conditions.
+ *
+ * (There is no need for locking when walking the policy list,
+ * as elements in the list are never deleted, nor does the list
+ * change.)
+ */
+int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
+{
+       struct ima_measure_rule_entry *entry;
+
+       list_for_each_entry(entry, ima_measure, list) {
+               bool rc;
+
+               rc = ima_match_rules(entry, inode, func, mask);
+               if (rc)
+                       return entry->action;
+       }
+       return 0;
+}
+
+/**
+ * ima_init_policy - initialize the default measure rules.
+ *
+ * ima_measure points to either the measure_default_rules or the
+ * the new measure_policy_rules.
+ */
+void ima_init_policy(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+               list_add_tail(&default_rules[i].list, &measure_default_rules);
+       ima_measure = &measure_default_rules;
+}
+
+/**
+ * ima_update_policy - update default_rules with new measure rules
+ *
+ * Called on file .release to update the default rules with a complete new
+ * policy.  Once updated, the policy is locked, no additional rules can be
+ * added to the policy.
+ */
+void ima_update_policy(void)
+{
+       const char *op = "policy_update";
+       const char *cause = "already exists";
+       int result = 1;
+       int audit_info = 0;
+
+       if (ima_measure == &measure_default_rules) {
+               ima_measure = &measure_policy_rules;
+               cause = "complete";
+               result = 0;
+       }
+       integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+                           NULL, op, cause, result, audit_info);
+}
+
+enum {
+       Opt_err = -1,
+       Opt_measure = 1, Opt_dont_measure,
+       Opt_obj_user, Opt_obj_role, Opt_obj_type,
+       Opt_subj_user, Opt_subj_role, Opt_subj_type,
+       Opt_func, Opt_mask, Opt_fsmagic, Opt_uid
+};
+
+static match_table_t policy_tokens = {
+       {Opt_measure, "measure"},
+       {Opt_dont_measure, "dont_measure"},
+       {Opt_obj_user, "obj_user=%s"},
+       {Opt_obj_role, "obj_role=%s"},
+       {Opt_obj_type, "obj_type=%s"},
+       {Opt_subj_user, "subj_user=%s"},
+       {Opt_subj_role, "subj_role=%s"},
+       {Opt_subj_type, "subj_type=%s"},
+       {Opt_func, "func=%s"},
+       {Opt_mask, "mask=%s"},
+       {Opt_fsmagic, "fsmagic=%s"},
+       {Opt_uid, "uid=%s"},
+       {Opt_err, NULL}
+};
+
+static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
+                            char *args, int lsm_rule, int audit_type)
+{
+       int result;
+
+       entry->lsm[lsm_rule].type = audit_type;
+       result = security_filter_rule_init(entry->lsm[lsm_rule].type,
+                                          AUDIT_EQUAL, args,
+                                          &entry->lsm[lsm_rule].rule);
+       return result;
+}
+
+static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
+{
+       struct audit_buffer *ab;
+       char *p;
+       int result = 0;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
+
+       entry->action = -1;
+       while ((p = strsep(&rule, " \n")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               unsigned long lnum;
+
+               if (result < 0)
+                       break;
+               if (!*p)
+                       continue;
+               token = match_token(p, policy_tokens, args);
+               switch (token) {
+               case Opt_measure:
+                       audit_log_format(ab, "%s ", "measure");
+                       entry->action = MEASURE;
+                       break;
+               case Opt_dont_measure:
+                       audit_log_format(ab, "%s ", "dont_measure");
+                       entry->action = DONT_MEASURE;
+                       break;
+               case Opt_func:
+                       audit_log_format(ab, "func=%s ", args[0].from);
+                       if (strcmp(args[0].from, "PATH_CHECK") == 0)
+                               entry->func = PATH_CHECK;
+                       else if (strcmp(args[0].from, "FILE_MMAP") == 0)
+                               entry->func = FILE_MMAP;
+                       else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
+                               entry->func = BPRM_CHECK;
+                       else
+                               result = -EINVAL;
+                       if (!result)
+                               entry->flags |= IMA_FUNC;
+                       break;
+               case Opt_mask:
+                       audit_log_format(ab, "mask=%s ", args[0].from);
+                       if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
+                               entry->mask = MAY_EXEC;
+                       else if (strcmp(args[0].from, "MAY_WRITE") == 0)
+                               entry->mask = MAY_WRITE;
+                       else if (strcmp(args[0].from, "MAY_READ") == 0)
+                               entry->mask = MAY_READ;
+                       else if (strcmp(args[0].from, "MAY_APPEND") == 0)
+                               entry->mask = MAY_APPEND;
+                       else
+                               result = -EINVAL;
+                       if (!result)
+                               entry->flags |= IMA_MASK;
+                       break;
+               case Opt_fsmagic:
+                       audit_log_format(ab, "fsmagic=%s ", args[0].from);
+                       result = strict_strtoul(args[0].from, 16,
+                                               &entry->fsmagic);
+                       if (!result)
+                               entry->flags |= IMA_FSMAGIC;
+                       break;
+               case Opt_uid:
+                       audit_log_format(ab, "uid=%s ", args[0].from);
+                       result = strict_strtoul(args[0].from, 10, &lnum);
+                       if (!result) {
+                               entry->uid = (uid_t) lnum;
+                               if (entry->uid != lnum)
+                                       result = -EINVAL;
+                               else
+                                       entry->flags |= IMA_UID;
+                       }
+                       break;
+               case Opt_obj_user:
+                       audit_log_format(ab, "obj_user=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_OBJ_USER,
+                                                  AUDIT_OBJ_USER);
+                       break;
+               case Opt_obj_role:
+                       audit_log_format(ab, "obj_role=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_OBJ_ROLE,
+                                                  AUDIT_OBJ_ROLE);
+                       break;
+               case Opt_obj_type:
+                       audit_log_format(ab, "obj_type=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_OBJ_TYPE,
+                                                  AUDIT_OBJ_TYPE);
+                       break;
+               case Opt_subj_user:
+                       audit_log_format(ab, "subj_user=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_SUBJ_USER,
+                                                  AUDIT_SUBJ_USER);
+                       break;
+               case Opt_subj_role:
+                       audit_log_format(ab, "subj_role=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_SUBJ_ROLE,
+                                                  AUDIT_SUBJ_ROLE);
+                       break;
+               case Opt_subj_type:
+                       audit_log_format(ab, "subj_type=%s ", args[0].from);
+                       result = ima_lsm_rule_init(entry, args[0].from,
+                                                  LSM_SUBJ_TYPE,
+                                                  AUDIT_SUBJ_TYPE);
+                       break;
+               case Opt_err:
+                       audit_log_format(ab, "UNKNOWN=%s ", p);
+                       break;
+               }
+       }
+       if (entry->action == UNKNOWN)
+               result = -EINVAL;
+
+       audit_log_format(ab, "res=%d", !result ? 0 : 1);
+       audit_log_end(ab);
+       return result;
+}
+
+/**
+ * ima_parse_add_rule - add a rule to measure_policy_rules
+ * @rule - ima measurement policy rule
+ *
+ * Uses a mutex to protect the policy list from multiple concurrent writers.
+ * Returns 0 on success, an error code on failure.
+ */
+int ima_parse_add_rule(char *rule)
+{
+       const char *op = "update_policy";
+       struct ima_measure_rule_entry *entry;
+       int result = 0;
+       int audit_info = 0;
+
+       /* Prevent installed policy from changing */
+       if (ima_measure != &measure_default_rules) {
+               integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+                                   NULL, op, "already exists",
+                                   -EACCES, audit_info);
+               return -EACCES;
+       }
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry) {
+               integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+                                   NULL, op, "-ENOMEM", -ENOMEM, audit_info);
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&entry->list);
+
+       result = ima_parse_rule(rule, entry);
+       if (!result) {
+               mutex_lock(&ima_measure_mutex);
+               list_add_tail(&entry->list, &measure_policy_rules);
+               mutex_unlock(&ima_measure_mutex);
+       } else {
+               kfree(entry);
+               integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+                                   NULL, op, "invalid policy", result,
+                                   audit_info);
+       }
+       return result;
+}
+
+/* ima_delete_rules called to cleanup invalid policy */
+void ima_delete_rules(void)
+{
+       struct ima_measure_rule_entry *entry, *tmp;
+
+       mutex_lock(&ima_measure_mutex);
+       list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+       mutex_unlock(&ima_measure_mutex);
+}
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
new file mode 100644 (file)
index 0000000..7ec9431
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Serge Hallyn <serue@us.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_queue.c
+ *       Implements queues that store template measurements and
+ *       maintains aggregate over the stored measurements
+ *       in the pre-configured TPM PCR (if available).
+ *       The measurement list is append-only. No entry is
+ *       ever removed or changed during the boot-cycle.
+ */
+#include <linux/module.h>
+#include <linux/rculist.h>
+#include "ima.h"
+
+LIST_HEAD(ima_measurements);   /* list of all measurements */
+
+/* key: inode (before secure-hashing a file) */
+struct ima_h_table ima_htable = {
+       .len = ATOMIC_LONG_INIT(0),
+       .violations = ATOMIC_LONG_INIT(0),
+       .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT
+};
+
+/* mutex protects atomicity of extending measurement list
+ * and extending the TPM PCR aggregate. Since tpm_extend can take
+ * long (and the tpm driver uses a mutex), we can't use the spinlock.
+ */
+static DEFINE_MUTEX(ima_extend_list_mutex);
+
+/* lookup up the digest value in the hash table, and return the entry */
+static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
+{
+       struct ima_queue_entry *qe, *ret = NULL;
+       unsigned int key;
+       struct hlist_node *pos;
+       int rc;
+
+       key = ima_hash_key(digest_value);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) {
+               rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE);
+               if (rc == 0) {
+                       ret = qe;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+       return ret;
+}
+
+/* ima_add_template_entry helper function:
+ * - Add template entry to measurement list and hash table.
+ *
+ * (Called with ima_extend_list_mutex held.)
+ */
+static int ima_add_digest_entry(struct ima_template_entry *entry)
+{
+       struct ima_queue_entry *qe;
+       unsigned int key;
+
+       qe = kmalloc(sizeof(*qe), GFP_KERNEL);
+       if (qe == NULL) {
+               pr_err("OUT OF MEMORY ERROR creating queue entry.\n");
+               return -ENOMEM;
+       }
+       qe->entry = entry;
+
+       INIT_LIST_HEAD(&qe->later);
+       list_add_tail_rcu(&qe->later, &ima_measurements);
+
+       atomic_long_inc(&ima_htable.len);
+       key = ima_hash_key(entry->digest);
+       hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+       return 0;
+}
+
+static int ima_pcr_extend(const u8 *hash)
+{
+       int result = 0;
+
+       if (!ima_used_chip)
+               return result;
+
+       result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
+       if (result != 0)
+               pr_err("Error Communicating to TPM chip\n");
+       return result;
+}
+
+/* Add template entry to the measurement list and hash table,
+ * and extend the pcr.
+ */
+int ima_add_template_entry(struct ima_template_entry *entry, int violation,
+                          const char *op, struct inode *inode)
+{
+       u8 digest[IMA_DIGEST_SIZE];
+       const char *audit_cause = "hash_added";
+       int audit_info = 1;
+       int result = 0;
+
+       mutex_lock(&ima_extend_list_mutex);
+       if (!violation) {
+               memcpy(digest, entry->digest, sizeof digest);
+               if (ima_lookup_digest_entry(digest)) {
+                       audit_cause = "hash_exists";
+                       goto out;
+               }
+       }
+
+       result = ima_add_digest_entry(entry);
+       if (result < 0) {
+               audit_cause = "ENOMEM";
+               audit_info = 0;
+               goto out;
+       }
+
+       if (violation)          /* invalidate pcr */
+               memset(digest, 0xff, sizeof digest);
+
+       result = ima_pcr_extend(digest);
+       if (result != 0) {
+               audit_cause = "TPM error";
+               audit_info = 0;
+       }
+out:
+       mutex_unlock(&ima_extend_list_mutex);
+       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name,
+                           op, audit_cause, result, audit_info);
+       return result;
+}
index 81932abefe7b1b3120c06c44365c07f889a397ec..9fb679c66b8af3c90f85b7c016ff5657268685d2 100644 (file)
@@ -53,6 +53,7 @@ struct key_user {
        atomic_t                nkeys;          /* number of keys */
        atomic_t                nikeys;         /* number of instantiated keys */
        uid_t                   uid;
+       struct user_namespace   *user_ns;
        int                     qnkeys;         /* number of keys allocated to this user */
        int                     qnbytes;        /* number of bytes allocated to this user */
 };
@@ -61,7 +62,8 @@ extern struct rb_root key_user_tree;
 extern spinlock_t      key_user_lock;
 extern struct key_user root_key_user;
 
-extern struct key_user *key_user_lookup(uid_t uid);
+extern struct key_user *key_user_lookup(uid_t uid,
+                                       struct user_namespace *user_ns);
 extern void key_user_put(struct key_user *user);
 
 /*
index f76c8a546fd3688e4cc2cadd076e05debe43f9a3..4a1297d1ada4f41d97fd314a8848d7e132112da4 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/workqueue.h>
 #include <linux/random.h>
 #include <linux/err.h>
+#include <linux/user_namespace.h>
 #include "internal.h"
 
 static struct kmem_cache       *key_jar;
@@ -60,7 +61,7 @@ void __key_check(const struct key *key)
  * get the key quota record for a user, allocating a new record if one doesn't
  * already exist
  */
-struct key_user *key_user_lookup(uid_t uid)
+struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
 {
        struct key_user *candidate = NULL, *user;
        struct rb_node *parent = NULL;
@@ -79,6 +80,10 @@ struct key_user *key_user_lookup(uid_t uid)
                        p = &(*p)->rb_left;
                else if (uid > user->uid)
                        p = &(*p)->rb_right;
+               else if (user_ns < user->user_ns)
+                       p = &(*p)->rb_left;
+               else if (user_ns > user->user_ns)
+                       p = &(*p)->rb_right;
                else
                        goto found;
        }
@@ -106,6 +111,7 @@ struct key_user *key_user_lookup(uid_t uid)
        atomic_set(&candidate->nkeys, 0);
        atomic_set(&candidate->nikeys, 0);
        candidate->uid = uid;
+       candidate->user_ns = get_user_ns(user_ns);
        candidate->qnkeys = 0;
        candidate->qnbytes = 0;
        spin_lock_init(&candidate->lock);
@@ -136,6 +142,7 @@ void key_user_put(struct key_user *user)
        if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
                rb_erase(&user->node, &key_user_tree);
                spin_unlock(&key_user_lock);
+               put_user_ns(user->user_ns);
 
                kfree(user);
        }
@@ -234,7 +241,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        quotalen = desclen + type->def_datalen;
 
        /* get hold of the key tracking for this user */
-       user = key_user_lookup(uid);
+       user = key_user_lookup(uid, cred->user->user_ns);
        if (!user)
                goto no_memory_1;
 
index b1ec3b4ee17df919101b3aee3e3853f4b4ea75bb..7f09fb897d2b49e1b4a1e2f96e942094b9239474 100644 (file)
@@ -726,7 +726,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
        /* change the UID */
        if (uid != (uid_t) -1 && uid != key->uid) {
                ret = -ENOMEM;
-               newowner = key_user_lookup(uid);
+               newowner = key_user_lookup(uid, current_user_ns());
                if (!newowner)
                        goto error_put;
 
index ed851574d07301ecc07f6920ffaee5be86635efd..3dba81c2eba360a615d9116e124cb36d86e89427 100644 (file)
@@ -539,6 +539,9 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
                                    &keyring_name_hash[bucket],
                                    type_data.link
                                    ) {
+                       if (keyring->user->user_ns != current_user_ns())
+                               continue;
+
                        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
                                continue;
 
index 5d9fc7b93f2e988f0b96c8fb2e89caacac4147cb..0ed802c9e698151b9c04440b4a6e8ab43eb9b9d4 100644 (file)
@@ -35,6 +35,9 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
 
        key = key_ref_to_ptr(key_ref);
 
+       if (key->user->user_ns != cred->user->user_ns)
+               goto use_other_perms;
+
        /* use the second 8-bits of permissions for keys the caller owns */
        if (key->uid == cred->fsuid) {
                kperm = key->perm >> 16;
@@ -56,6 +59,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
                }
        }
 
+use_other_perms:
+
        /* otherwise use the least-significant 8-bits */
        kperm = key->perm;
 
index 7f508def50e319a5110032a7e169a19a5ec02fab..769f9bdfd2b33aaeadbd7eb3efb895a364d0536a 100644 (file)
@@ -91,6 +91,28 @@ __initcall(key_proc_init);
  */
 #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 
+static struct rb_node *__key_serial_next(struct rb_node *n)
+{
+       while (n) {
+               struct key *key = rb_entry(n, struct key, serial_node);
+               if (key->user->user_ns == current_user_ns())
+                       break;
+               n = rb_next(n);
+       }
+       return n;
+}
+
+static struct rb_node *key_serial_next(struct rb_node *n)
+{
+       return __key_serial_next(rb_next(n));
+}
+
+static struct rb_node *key_serial_first(struct rb_root *r)
+{
+       struct rb_node *n = rb_first(r);
+       return __key_serial_next(n);
+}
+
 static int proc_keys_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &proc_keys_ops);
@@ -104,10 +126,10 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
 
        spin_lock(&key_serial_lock);
 
-       _p = rb_first(&key_serial_tree);
+       _p = key_serial_first(&key_serial_tree);
        while (pos > 0 && _p) {
                pos--;
-               _p = rb_next(_p);
+               _p = key_serial_next(_p);
        }
 
        return _p;
@@ -117,7 +139,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
 static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
 {
        (*_pos)++;
-       return rb_next((struct rb_node *) v);
+       return key_serial_next((struct rb_node *) v);
 
 }
 
@@ -203,6 +225,27 @@ static int proc_keys_show(struct seq_file *m, void *v)
 
 #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
 
+static struct rb_node *__key_user_next(struct rb_node *n)
+{
+       while (n) {
+               struct key_user *user = rb_entry(n, struct key_user, node);
+               if (user->user_ns == current_user_ns())
+                       break;
+               n = rb_next(n);
+       }
+       return n;
+}
+
+static struct rb_node *key_user_next(struct rb_node *n)
+{
+       return __key_user_next(rb_next(n));
+}
+
+static struct rb_node *key_user_first(struct rb_root *r)
+{
+       struct rb_node *n = rb_first(r);
+       return __key_user_next(n);
+}
 /*****************************************************************************/
 /*
  * implement "/proc/key-users" to provides a list of the key users
@@ -220,10 +263,10 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
 
        spin_lock(&key_user_lock);
 
-       _p = rb_first(&key_user_tree);
+       _p = key_user_first(&key_user_tree);
        while (pos > 0 && _p) {
                pos--;
-               _p = rb_next(_p);
+               _p = key_user_next(_p);
        }
 
        return _p;
@@ -233,7 +276,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
 static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
 {
        (*_pos)++;
-       return rb_next((struct rb_node *) v);
+       return key_user_next((struct rb_node *) v);
 
 }
 
index 2f5d89e92b853a3a4e0ea910aa2e023fc749690a..276d27882ce84394d7d6ce5b0c12d82e05f89987 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -34,6 +35,7 @@ struct key_user root_key_user = {
        .nkeys          = ATOMIC_INIT(2),
        .nikeys         = ATOMIC_INIT(2),
        .uid            = 0,
+       .user_ns        = &init_user_ns,
 };
 
 /*****************************************************************************/
index 0e04f72ef2d4339c8ac50691d0171e138dc11df2..22a31582bfaae26ffe5911acf72dc2c09e8d06ec 100644 (file)
@@ -365,7 +365,7 @@ static struct key *construct_key_and_link(struct key_type *type,
 
        kenter("");
 
-       user = key_user_lookup(current_fsuid());
+       user = key_user_lookup(current_fsuid(), current_user_ns());
        if (!user)
                return ERR_PTR(-ENOMEM);
 
index eb41f43e2772d8cc35261103efcd6942c7f6bf12..7f9b5fac87793a19faf3d310a4e04f8a158bb476 100644 (file)
@@ -88,17 +88,16 @@ struct avc_entry {
        u32                     tsid;
        u16                     tclass;
        struct av_decision      avd;
-       atomic_t                used;   /* used recently */
 };
 
 struct avc_node {
        struct avc_entry        ae;
-       struct list_head        list;
+       struct hlist_node       list; /* anchored in avc_cache->slots[i] */
        struct rcu_head         rhead;
 };
 
 struct avc_cache {
-       struct list_head        slots[AVC_CACHE_SLOTS];
+       struct hlist_head       slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
        spinlock_t              slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
        atomic_t                lru_hint;       /* LRU hint for reclaim scan */
        atomic_t                active_nodes;
@@ -234,7 +233,7 @@ void __init avc_init(void)
        int i;
 
        for (i = 0; i < AVC_CACHE_SLOTS; i++) {
-               INIT_LIST_HEAD(&avc_cache.slots[i]);
+               INIT_HLIST_HEAD(&avc_cache.slots[i]);
                spin_lock_init(&avc_cache.slots_lock[i]);
        }
        atomic_set(&avc_cache.active_nodes, 0);
@@ -250,16 +249,20 @@ int avc_get_hash_stats(char *page)
 {
        int i, chain_len, max_chain_len, slots_used;
        struct avc_node *node;
+       struct hlist_head *head;
 
        rcu_read_lock();
 
        slots_used = 0;
        max_chain_len = 0;
        for (i = 0; i < AVC_CACHE_SLOTS; i++) {
-               if (!list_empty(&avc_cache.slots[i])) {
+               head = &avc_cache.slots[i];
+               if (!hlist_empty(head)) {
+                       struct hlist_node *next;
+
                        slots_used++;
                        chain_len = 0;
-                       list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+                       hlist_for_each_entry_rcu(node, next, head, list)
                                chain_len++;
                        if (chain_len > max_chain_len)
                                max_chain_len = chain_len;
@@ -283,7 +286,7 @@ static void avc_node_free(struct rcu_head *rhead)
 
 static void avc_node_delete(struct avc_node *node)
 {
-       list_del_rcu(&node->list);
+       hlist_del_rcu(&node->list);
        call_rcu(&node->rhead, avc_node_free);
        atomic_dec(&avc_cache.active_nodes);
 }
@@ -297,7 +300,7 @@ static void avc_node_kill(struct avc_node *node)
 
 static void avc_node_replace(struct avc_node *new, struct avc_node *old)
 {
-       list_replace_rcu(&old->list, &new->list);
+       hlist_replace_rcu(&old->list, &new->list);
        call_rcu(&old->rhead, avc_node_free);
        atomic_dec(&avc_cache.active_nodes);
 }
@@ -307,29 +310,31 @@ static inline int avc_reclaim_node(void)
        struct avc_node *node;
        int hvalue, try, ecx;
        unsigned long flags;
+       struct hlist_head *head;
+       struct hlist_node *next;
+       spinlock_t *lock;
 
        for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
                hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
+               head = &avc_cache.slots[hvalue];
+               lock = &avc_cache.slots_lock[hvalue];
 
-               if (!spin_trylock_irqsave(&avc_cache.slots_lock[hvalue], flags))
+               if (!spin_trylock_irqsave(lock, flags))
                        continue;
 
                rcu_read_lock();
-               list_for_each_entry(node, &avc_cache.slots[hvalue], list) {
-                       if (atomic_dec_and_test(&node->ae.used)) {
-                               /* Recently Unused */
-                               avc_node_delete(node);
-                               avc_cache_stats_incr(reclaims);
-                               ecx++;
-                               if (ecx >= AVC_CACHE_RECLAIM) {
-                                       rcu_read_unlock();
-                                       spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
-                                       goto out;
-                               }
+               hlist_for_each_entry(node, next, head, list) {
+                       avc_node_delete(node);
+                       avc_cache_stats_incr(reclaims);
+                       ecx++;
+                       if (ecx >= AVC_CACHE_RECLAIM) {
+                               rcu_read_unlock();
+                               spin_unlock_irqrestore(lock, flags);
+                               goto out;
                        }
                }
                rcu_read_unlock();
-               spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+               spin_unlock_irqrestore(lock, flags);
        }
 out:
        return ecx;
@@ -344,8 +349,7 @@ static struct avc_node *avc_alloc_node(void)
                goto out;
 
        INIT_RCU_HEAD(&node->rhead);
-       INIT_LIST_HEAD(&node->list);
-       atomic_set(&node->ae.used, 1);
+       INIT_HLIST_NODE(&node->list);
        avc_cache_stats_incr(allocations);
 
        if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold)
@@ -355,21 +359,24 @@ out:
        return node;
 }
 
-static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
 {
        node->ae.ssid = ssid;
        node->ae.tsid = tsid;
        node->ae.tclass = tclass;
-       memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+       memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
 }
 
 static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
 {
        struct avc_node *node, *ret = NULL;
        int hvalue;
+       struct hlist_head *head;
+       struct hlist_node *next;
 
        hvalue = avc_hash(ssid, tsid, tclass);
-       list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list) {
+       head = &avc_cache.slots[hvalue];
+       hlist_for_each_entry_rcu(node, next, head, list) {
                if (ssid == node->ae.ssid &&
                    tclass == node->ae.tclass &&
                    tsid == node->ae.tsid) {
@@ -378,15 +385,6 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
                }
        }
 
-       if (ret == NULL) {
-               /* cache miss */
-               goto out;
-       }
-
-       /* cache hit */
-       if (atomic_read(&ret->ae.used) != 1)
-               atomic_set(&ret->ae.used, 1);
-out:
        return ret;
 }
 
@@ -395,30 +393,25 @@ out:
  * @ssid: source security identifier
  * @tsid: target security identifier
  * @tclass: target security class
- * @requested: requested permissions, interpreted based on @tclass
  *
  * Look up an AVC entry that is valid for the
- * @requested permissions between the SID pair
  * (@ssid, @tsid), interpreting the permissions
  * based on @tclass.  If a valid AVC entry exists,
  * then this function return the avc_node.
  * Otherwise, this function returns NULL.
  */
-static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
 {
        struct avc_node *node;
 
        avc_cache_stats_incr(lookups);
        node = avc_search_node(ssid, tsid, tclass);
 
-       if (node && ((node->ae.avd.decided & requested) == requested)) {
+       if (node)
                avc_cache_stats_incr(hits);
-               goto out;
-       }
+       else
+               avc_cache_stats_incr(misses);
 
-       node = NULL;
-       avc_cache_stats_incr(misses);
-out:
        return node;
 }
 
@@ -449,34 +442,41 @@ static int avc_latest_notif_update(int seqno, int is_insert)
  * @ssid: source security identifier
  * @tsid: target security identifier
  * @tclass: target security class
- * @ae: AVC entry
+ * @avd: resulting av decision
  *
  * Insert an AVC entry for the SID pair
  * (@ssid, @tsid) and class @tclass.
  * The access vectors and the sequence number are
  * normally provided by the security server in
  * response to a security_compute_av() call.  If the
- * sequence number @ae->avd.seqno is not less than the latest
+ * sequence number @avd->seqno is not less than the latest
  * revocation notification, then the function copies
  * the access vectors into a cache entry, returns
  * avc_node inserted. Otherwise, this function returns NULL.
  */
-static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
 {
        struct avc_node *pos, *node = NULL;
        int hvalue;
        unsigned long flag;
 
-       if (avc_latest_notif_update(ae->avd.seqno, 1))
+       if (avc_latest_notif_update(avd->seqno, 1))
                goto out;
 
        node = avc_alloc_node();
        if (node) {
+               struct hlist_head *head;
+               struct hlist_node *next;
+               spinlock_t *lock;
+
                hvalue = avc_hash(ssid, tsid, tclass);
-               avc_node_populate(node, ssid, tsid, tclass, ae);
+               avc_node_populate(node, ssid, tsid, tclass, avd);
+
+               head = &avc_cache.slots[hvalue];
+               lock = &avc_cache.slots_lock[hvalue];
 
-               spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
-               list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+               spin_lock_irqsave(lock, flag);
+               hlist_for_each_entry(pos, next, head, list) {
                        if (pos->ae.ssid == ssid &&
                            pos->ae.tsid == tsid &&
                            pos->ae.tclass == tclass) {
@@ -484,9 +484,9 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_en
                                goto found;
                        }
                }
-               list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+               hlist_add_head_rcu(&node->list, head);
 found:
-               spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+               spin_unlock_irqrestore(lock, flag);
        }
 out:
        return node;
@@ -742,17 +742,22 @@ static inline int avc_sidcmp(u32 x, u32 y)
  * @event : Updating event
  * @perms : Permission mask bits
  * @ssid,@tsid,@tclass : identifier of an AVC entry
+ * @seqno : sequence number when decision was made
  *
  * if a valid AVC entry doesn't exist,this function returns -ENOENT.
  * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
  * otherwise, this function update the AVC entry. The original AVC-entry object
  * will release later by RCU.
  */
-static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+                          u32 seqno)
 {
        int hvalue, rc = 0;
        unsigned long flag;
        struct avc_node *pos, *node, *orig = NULL;
+       struct hlist_head *head;
+       struct hlist_node *next;
+       spinlock_t *lock;
 
        node = avc_alloc_node();
        if (!node) {
@@ -762,12 +767,17 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
 
        /* Lock the target slot */
        hvalue = avc_hash(ssid, tsid, tclass);
-       spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
 
-       list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+       head = &avc_cache.slots[hvalue];
+       lock = &avc_cache.slots_lock[hvalue];
+
+       spin_lock_irqsave(lock, flag);
+
+       hlist_for_each_entry(pos, next, head, list) {
                if (ssid == pos->ae.ssid &&
                    tsid == pos->ae.tsid &&
-                   tclass == pos->ae.tclass){
+                   tclass == pos->ae.tclass &&
+                   seqno == pos->ae.avd.seqno){
                        orig = pos;
                        break;
                }
@@ -783,7 +793,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
         * Copy and replace original node.
         */
 
-       avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+       avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
 
        switch (event) {
        case AVC_CALLBACK_GRANT:
@@ -808,7 +818,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
        }
        avc_node_replace(node, orig);
 out_unlock:
-       spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+       spin_unlock_irqrestore(lock, flag);
 out:
        return rc;
 }
@@ -823,18 +833,24 @@ int avc_ss_reset(u32 seqno)
        int i, rc = 0, tmprc;
        unsigned long flag;
        struct avc_node *node;
+       struct hlist_head *head;
+       struct hlist_node *next;
+       spinlock_t *lock;
 
        for (i = 0; i < AVC_CACHE_SLOTS; i++) {
-               spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+               head = &avc_cache.slots[i];
+               lock = &avc_cache.slots_lock[i];
+
+               spin_lock_irqsave(lock, flag);
                /*
                 * With preemptable RCU, the outer spinlock does not
                 * prevent RCU grace periods from ending.
                 */
                rcu_read_lock();
-               list_for_each_entry(node, &avc_cache.slots[i], list)
+               hlist_for_each_entry(node, next, head, list)
                        avc_node_delete(node);
                rcu_read_unlock();
-               spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+               spin_unlock_irqrestore(lock, flag);
        }
 
        for (c = avc_callbacks; c; c = c->next) {
@@ -875,10 +891,10 @@ int avc_ss_reset(u32 seqno)
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         u16 tclass, u32 requested,
                         unsigned flags,
-                        struct av_decision *avd)
+                        struct av_decision *in_avd)
 {
        struct avc_node *node;
-       struct avc_entry entry, *p_ae;
+       struct av_decision avd_entry, *avd;
        int rc = 0;
        u32 denied;
 
@@ -886,29 +902,34 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
 
        rcu_read_lock();
 
-       node = avc_lookup(ssid, tsid, tclass, requested);
+       node = avc_lookup(ssid, tsid, tclass);
        if (!node) {
                rcu_read_unlock();
-               rc = security_compute_av(ssid, tsid, tclass, requested, &entry.avd);
+
+               if (in_avd)
+                       avd = in_avd;
+               else
+                       avd = &avd_entry;
+
+               rc = security_compute_av(ssid, tsid, tclass, requested, avd);
                if (rc)
                        goto out;
                rcu_read_lock();
-               node = avc_insert(ssid, tsid, tclass, &entry);
+               node = avc_insert(ssid, tsid, tclass, avd);
+       } else {
+               if (in_avd)
+                       memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+               avd = &node->ae.avd;
        }
 
-       p_ae = node ? &node->ae : &entry;
-
-       if (avd)
-               memcpy(avd, &p_ae->avd, sizeof(*avd));
-
-       denied = requested & ~(p_ae->avd.allowed);
+       denied = requested & ~(avd->allowed);
 
        if (denied) {
                if (flags & AVC_STRICT)
                        rc = -EACCES;
                else if (!selinux_enforcing || security_permissive_sid(ssid))
                        avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
-                                       tsid, tclass);
+                                       tsid, tclass, avd->seqno);
                else
                        rc = -EACCES;
        }
index 00815973d4126492d596f278431c342bc7b6efc6..7c52ba243c6490acf9d22f719763a3931fbaabfb 100644 (file)
@@ -89,7 +89,7 @@
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
-#define NUM_SEL_MNT_OPTS 4
+#define NUM_SEL_MNT_OPTS 5
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -353,6 +353,7 @@ enum {
        Opt_fscontext = 2,
        Opt_defcontext = 3,
        Opt_rootcontext = 4,
+       Opt_labelsupport = 5,
 };
 
 static const match_table_t tokens = {
@@ -360,6 +361,7 @@ static const match_table_t tokens = {
        {Opt_fscontext, FSCONTEXT_STR "%s"},
        {Opt_defcontext, DEFCONTEXT_STR "%s"},
        {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
+       {Opt_labelsupport, LABELSUPP_STR},
        {Opt_error, NULL},
 };
 
@@ -431,7 +433,7 @@ static int sb_finish_set_opts(struct super_block *sb)
                }
        }
 
-       sbsec->initialized = 1;
+       sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
 
        if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
@@ -441,6 +443,12 @@ static int sb_finish_set_opts(struct super_block *sb)
                       sb->s_id, sb->s_type->name,
                       labeling_behaviors[sbsec->behavior-1]);
 
+       if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
+           sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
+           sbsec->behavior == SECURITY_FS_USE_NONE ||
+           sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+               sbsec->flags &= ~SE_SBLABELSUPP;
+
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
 
@@ -487,23 +495,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
 
        security_init_mnt_opts(opts);
 
-       if (!sbsec->initialized)
+       if (!(sbsec->flags & SE_SBINITIALIZED))
                return -EINVAL;
 
        if (!ss_initialized)
                return -EINVAL;
 
-       /*
-        * if we ever use sbsec flags for anything other than tracking mount
-        * settings this is going to need a mask
-        */
-       tmp = sbsec->flags;
+       tmp = sbsec->flags & SE_MNTMASK;
        /* count the number of mount options for this sb */
        for (i = 0; i < 8; i++) {
                if (tmp & 0x01)
                        opts->num_mnt_opts++;
                tmp >>= 1;
        }
+       /* Check if the Label support flag is set */
+       if (sbsec->flags & SE_SBLABELSUPP)
+               opts->num_mnt_opts++;
 
        opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
        if (!opts->mnt_opts) {
@@ -549,6 +556,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                opts->mnt_opts[i] = context;
                opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
        }
+       if (sbsec->flags & SE_SBLABELSUPP) {
+               opts->mnt_opts[i] = NULL;
+               opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
+       }
 
        BUG_ON(i != opts->num_mnt_opts);
 
@@ -562,8 +573,10 @@ out_free:
 static int bad_option(struct superblock_security_struct *sbsec, char flag,
                      u32 old_sid, u32 new_sid)
 {
+       char mnt_flags = sbsec->flags & SE_MNTMASK;
+
        /* check if the old mount command had the same options */
-       if (sbsec->initialized)
+       if (sbsec->flags & SE_SBINITIALIZED)
                if (!(sbsec->flags & flag) ||
                    (old_sid != new_sid))
                        return 1;
@@ -571,8 +584,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
        /* check if we were passed the same options twice,
         * aka someone passed context=a,context=b
         */
-       if (!sbsec->initialized)
-               if (sbsec->flags & flag)
+       if (!(sbsec->flags & SE_SBINITIALIZED))
+               if (mnt_flags & flag)
                        return 1;
        return 0;
 }
@@ -626,7 +639,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * this sb does not set any security options.  (The first options
         * will be used for both mounts)
         */
-       if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+       if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
            && (num_opts == 0))
                goto out;
 
@@ -637,6 +650,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        for (i = 0; i < num_opts; i++) {
                u32 sid;
+
+               if (flags[i] == SE_SBLABELSUPP)
+                       continue;
                rc = security_context_to_sid(mount_options[i],
                                             strlen(mount_options[i]), &sid);
                if (rc) {
@@ -690,19 +706,19 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                }
        }
 
-       if (sbsec->initialized) {
+       if (sbsec->flags & SE_SBINITIALIZED) {
                /* previously mounted with options, but not on this attempt? */
-               if (sbsec->flags && !num_opts)
+               if ((sbsec->flags & SE_MNTMASK) && !num_opts)
                        goto out_double_mount;
                rc = 0;
                goto out;
        }
 
        if (strcmp(sb->s_type->name, "proc") == 0)
-               sbsec->proc = 1;
+               sbsec->flags |= SE_SBPROC;
 
        /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
                       __func__, sb->s_type->name, rc);
@@ -806,10 +822,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        }
 
        /* how can we clone if the old one wasn't set up?? */
-       BUG_ON(!oldsbsec->initialized);
+       BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
 
        /* if fs is reusing a sb, just let its options stand... */
-       if (newsbsec->initialized)
+       if (newsbsec->flags & SE_SBINITIALIZED)
                return;
 
        mutex_lock(&newsbsec->lock);
@@ -917,7 +933,8 @@ static int selinux_parse_opts_str(char *options,
                                goto out_err;
                        }
                        break;
-
+               case Opt_labelsupport:
+                       break;
                default:
                        rc = -EINVAL;
                        printk(KERN_WARNING "SELinux:  unknown mount option\n");
@@ -999,7 +1016,12 @@ static void selinux_write_opts(struct seq_file *m,
        char *prefix;
 
        for (i = 0; i < opts->num_mnt_opts; i++) {
-               char *has_comma = strchr(opts->mnt_opts[i], ',');
+               char *has_comma;
+
+               if (opts->mnt_opts[i])
+                       has_comma = strchr(opts->mnt_opts[i], ',');
+               else
+                       has_comma = NULL;
 
                switch (opts->mnt_opts_flags[i]) {
                case CONTEXT_MNT:
@@ -1014,6 +1036,10 @@ static void selinux_write_opts(struct seq_file *m,
                case DEFCONTEXT_MNT:
                        prefix = DEFCONTEXT_STR;
                        break;
+               case SE_SBLABELSUPP:
+                       seq_putc(m, ',');
+                       seq_puts(m, LABELSUPP_STR);
+                       continue;
                default:
                        BUG();
                };
@@ -1209,7 +1235,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                goto out_unlock;
 
        sbsec = inode->i_sb->s_security;
-       if (!sbsec->initialized) {
+       if (!(sbsec->flags & SE_SBINITIALIZED)) {
                /* Defer initialization until selinux_complete_init,
                   after the initial policy is loaded and the security
                   server is ready to handle calls. */
@@ -1237,19 +1263,26 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        dentry = d_find_alias(inode);
                }
                if (!dentry) {
-                       printk(KERN_WARNING "SELinux: %s:  no dentry for dev=%s "
-                              "ino=%ld\n", __func__, inode->i_sb->s_id,
-                              inode->i_ino);
+                       /*
+                        * this is can be hit on boot when a file is accessed
+                        * before the policy is loaded.  When we load policy we
+                        * may find inodes that have no dentry on the
+                        * sbsec->isec_head list.  No reason to complain as these
+                        * will get fixed up the next time we go through
+                        * inode_doinit with a dentry, before these inodes could
+                        * be used again by userspace.
+                        */
                        goto out_unlock;
                }
 
                len = INITCONTEXTLEN;
-               context = kmalloc(len, GFP_NOFS);
+               context = kmalloc(len+1, GFP_NOFS);
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
                        goto out_unlock;
                }
+               context[len] = '\0';
                rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
                                           context, len);
                if (rc == -ERANGE) {
@@ -1262,12 +1295,13 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        }
                        kfree(context);
                        len = rc;
-                       context = kmalloc(len, GFP_NOFS);
+                       context = kmalloc(len+1, GFP_NOFS);
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
                                goto out_unlock;
                        }
+                       context[len] = '\0';
                        rc = inode->i_op->getxattr(dentry,
                                                   XATTR_NAME_SELINUX,
                                                   context, len);
@@ -1289,10 +1323,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                                             sbsec->def_sid,
                                                             GFP_NOFS);
                        if (rc) {
-                               printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
-                                      "returned %d for dev=%s ino=%ld\n",
-                                      __func__, context, -rc,
-                                      inode->i_sb->s_id, inode->i_ino);
+                               char *dev = inode->i_sb->s_id;
+                               unsigned long ino = inode->i_ino;
+
+                               if (rc == -EINVAL) {
+                                       if (printk_ratelimit())
+                                               printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
+                                                       "context=%s.  This indicates you may need to relabel the inode or the "
+                                                       "filesystem in question.\n", ino, dev, context);
+                               } else {
+                                       printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
+                                              "returned %d for dev=%s ino=%ld\n",
+                                              __func__, context, -rc, dev, ino);
+                               }
                                kfree(context);
                                /* Leave with the unlabeled SID */
                                rc = 0;
@@ -1326,7 +1369,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                /* Default to the fs superblock SID. */
                isec->sid = sbsec->sid;
 
-               if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
+               if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
                        struct proc_inode *proci = PROC_I(inode);
                        if (proci->pde) {
                                isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -1587,7 +1630,7 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
                if (rc)
                        return rc;
@@ -1801,6 +1844,8 @@ static inline u32 open_file_to_av(struct file *file)
                        av |= FIFO_FILE__OPEN;
                else if (S_ISDIR(mode))
                        av |= DIR__OPEN;
+               else if (S_ISSOCK(mode))
+                       av |= SOCK_FILE__OPEN;
                else
                        printk(KERN_ERR "SELinux: WARNING: inside %s with "
                                "unknown mode:%o\n", __func__, mode);
@@ -1815,7 +1860,7 @@ static int selinux_ptrace_may_access(struct task_struct *child,
 {
        int rc;
 
-       rc = secondary_ops->ptrace_may_access(child, mode);
+       rc = cap_ptrace_may_access(child, mode);
        if (rc)
                return rc;
 
@@ -1832,7 +1877,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
 {
        int rc;
 
-       rc = secondary_ops->ptrace_traceme(parent);
+       rc = cap_ptrace_traceme(parent);
        if (rc)
                return rc;
 
@@ -1848,7 +1893,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
        if (error)
                return error;
 
-       return secondary_ops->capget(target, effective, inheritable, permitted);
+       return cap_capget(target, effective, inheritable, permitted);
 }
 
 static int selinux_capset(struct cred *new, const struct cred *old,
@@ -1858,7 +1903,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
 {
        int error;
 
-       error = secondary_ops->capset(new, old,
+       error = cap_capset(new, old,
                                      effective, inheritable, permitted);
        if (error)
                return error;
@@ -1866,12 +1911,22 @@ static int selinux_capset(struct cred *new, const struct cred *old,
        return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
+/*
+ * (This comment used to live with the selinux_task_setuid hook,
+ * which was removed).
+ *
+ * Since setuid only affects the current process, and since the SELinux
+ * controls are not based on the Linux identity attributes, SELinux does not
+ * need to control this operation.  However, SELinux does control the use of
+ * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
+ */
+
 static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
                           int cap, int audit)
 {
        int rc;
 
-       rc = secondary_ops->capable(tsk, cred, cap, audit);
+       rc = cap_capable(tsk, cred, cap, audit);
        if (rc)
                return rc;
 
@@ -1997,7 +2052,7 @@ static int selinux_syslog(int type)
 {
        int rc;
 
-       rc = secondary_ops->syslog(type);
+       rc = cap_syslog(type);
        if (rc)
                return rc;
 
@@ -2028,10 +2083,6 @@ static int selinux_syslog(int type)
  * mapping. 0 means there is enough memory for the allocation to
  * succeed and -ENOMEM implies there is not.
  *
- * Note that secondary_ops->capable and task_has_perm_noaudit return 0
- * if the capability is granted, but __vm_enough_memory requires 1 if
- * the capability is granted.
- *
  * Do not audit the selinux permission check, as this is applied to all
  * processes that allocate mappings.
  */
@@ -2058,7 +2109,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        struct inode *inode = bprm->file->f_path.dentry->d_inode;
        int rc;
 
-       rc = secondary_ops->bprm_set_creds(bprm);
+       rc = cap_bprm_set_creds(bprm);
        if (rc)
                return rc;
 
@@ -2156,11 +2207,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        return 0;
 }
 
-static int selinux_bprm_check_security(struct linux_binprm *bprm)
-{
-       return secondary_ops->bprm_check_security(bprm);
-}
-
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
        const struct cred *cred = current_cred();
@@ -2180,7 +2226,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
                                        PROCESS__NOATSECURE, NULL);
        }
 
-       return (atsecure || secondary_ops->bprm_secureexec(bprm));
+       return (atsecure || cap_bprm_secureexec(bprm));
 }
 
 extern struct vfsmount *selinuxfs_mount;
@@ -2290,8 +2336,6 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
        struct rlimit *rlim, *initrlim;
        int rc, i;
 
-       secondary_ops->bprm_committing_creds(bprm);
-
        new_tsec = bprm->cred->security;
        if (new_tsec->sid == new_tsec->osid)
                return;
@@ -2337,8 +2381,6 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
        int rc, i;
        unsigned long flags;
 
-       secondary_ops->bprm_committed_creds(bprm);
-
        osid = tsec->osid;
        sid = tsec->sid;
 
@@ -2400,7 +2442,8 @@ static inline int selinux_option(char *option, int len)
        return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
                match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
                match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
-               match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
+               match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
+               match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -2513,11 +2556,6 @@ static int selinux_mount(char *dev_name,
                         void *data)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
-       if (rc)
-               return rc;
 
        if (flags & MS_REMOUNT)
                return superblock_has_perm(cred, path->mnt->mnt_sb,
@@ -2530,11 +2568,6 @@ static int selinux_mount(char *dev_name,
 static int selinux_umount(struct vfsmount *mnt, int flags)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->sb_umount(mnt, flags);
-       if (rc)
-               return rc;
 
        return superblock_has_perm(cred, mnt->mnt_sb,
                                   FILESYSTEM__UNMOUNT, NULL);
@@ -2570,7 +2603,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
                                             &newsid);
@@ -2585,14 +2618,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        /* Possibly defer initialization to selinux_complete_init. */
-       if (sbsec->initialized) {
+       if (sbsec->flags & SE_SBINITIALIZED) {
                struct inode_security_struct *isec = inode->i_security;
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
                isec->sid = newsid;
                isec->initialized = 1;
        }
 
-       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
        if (name) {
@@ -2622,21 +2655,11 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma
 
 static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
-       int rc;
-
-       rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
-       if (rc)
-               return rc;
        return may_link(dir, old_dentry, MAY_LINK);
 }
 
 static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
 {
-       int rc;
-
-       rc = secondary_ops->inode_unlink(dir, dentry);
-       if (rc)
-               return rc;
        return may_link(dir, dentry, MAY_UNLINK);
 }
 
@@ -2657,12 +2680,6 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
 
 static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-       int rc;
-
-       rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
-       if (rc)
-               return rc;
-
        return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
 
@@ -2682,22 +2699,13 @@ static int selinux_inode_readlink(struct dentry *dentry)
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
        const struct cred *cred = current_cred();
-       int rc;
 
-       rc = secondary_ops->inode_follow_link(dentry, nameidata);
-       if (rc)
-               return rc;
        return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->inode_permission(inode, mask);
-       if (rc)
-               return rc;
 
        if (!mask) {
                /* No permission to check.  Existence test. */
@@ -2711,11 +2719,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->inode_setattr(dentry, iattr);
-       if (rc)
-               return rc;
 
        if (iattr->ia_valid & ATTR_FORCE)
                return 0;
@@ -2769,7 +2772,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return selinux_inode_setotherxattr(dentry, name);
 
        sbsec = inode->i_sb->s_security;
-       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (!(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
        if (!is_owner_or_cap(inode))
@@ -2931,16 +2934,6 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
        return len;
 }
 
-static int selinux_inode_need_killpriv(struct dentry *dentry)
-{
-       return secondary_ops->inode_need_killpriv(dentry);
-}
-
-static int selinux_inode_killpriv(struct dentry *dentry)
-{
-       return secondary_ops->inode_killpriv(dentry);
-}
-
 static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
 {
        struct inode_security_struct *isec = inode->i_security;
@@ -3078,18 +3071,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                                 unsigned long prot)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->file_mprotect(vma, reqprot, prot);
-       if (rc)
-               return rc;
 
        if (selinux_checkreqprot)
                prot = reqprot;
 
 #ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
-               rc = 0;
+               int rc = 0;
                if (vma->vm_start >= vma->vm_mm->start_brk &&
                    vma->vm_end <= vma->vm_mm->brk) {
                        rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
@@ -3239,12 +3227,6 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
 
 static int selinux_task_create(unsigned long clone_flags)
 {
-       int rc;
-
-       rc = secondary_ops->task_create(clone_flags);
-       if (rc)
-               return rc;
-
        return current_has_perm(current, PROCESS__FORK);
 }
 
@@ -3277,14 +3259,6 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
-/*
- * commit new credentials
- */
-static void selinux_cred_commit(struct cred *new, const struct cred *old)
-{
-       secondary_ops->cred_commit(new, old);
-}
-
 /*
  * set the security data for a kernel service
  * - all the creation contexts are set to unlabelled
@@ -3329,29 +3303,6 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
        return 0;
 }
 
-static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
-{
-       /* Since setuid only affects the current process, and
-          since the SELinux controls are not based on the Linux
-          identity attributes, SELinux does not need to control
-          this operation.  However, SELinux does control the use
-          of the CAP_SETUID and CAP_SETGID capabilities using the
-          capable hook. */
-       return 0;
-}
-
-static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
-                                  int flags)
-{
-       return secondary_ops->task_fix_setuid(new, old, flags);
-}
-
-static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
-{
-       /* See the comment for setuid above. */
-       return 0;
-}
-
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return current_has_perm(p, PROCESS__SETPGID);
@@ -3372,17 +3323,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
        *secid = task_sid(p);
 }
 
-static int selinux_task_setgroups(struct group_info *group_info)
-{
-       /* See the comment for setuid above. */
-       return 0;
-}
-
 static int selinux_task_setnice(struct task_struct *p, int nice)
 {
        int rc;
 
-       rc = secondary_ops->task_setnice(p, nice);
+       rc = cap_task_setnice(p, nice);
        if (rc)
                return rc;
 
@@ -3393,7 +3338,7 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio)
 {
        int rc;
 
-       rc = secondary_ops->task_setioprio(p, ioprio);
+       rc = cap_task_setioprio(p, ioprio);
        if (rc)
                return rc;
 
@@ -3408,11 +3353,6 @@ static int selinux_task_getioprio(struct task_struct *p)
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
 {
        struct rlimit *old_rlim = current->signal->rlim + resource;
-       int rc;
-
-       rc = secondary_ops->task_setrlimit(resource, new_rlim);
-       if (rc)
-               return rc;
 
        /* Control the ability to change the hard limit (whether
           lowering or raising it), so that the hard limit can
@@ -3428,7 +3368,7 @@ static int selinux_task_setscheduler(struct task_struct *p, int policy, struct s
 {
        int rc;
 
-       rc = secondary_ops->task_setscheduler(p, policy, lp);
+       rc = cap_task_setscheduler(p, policy, lp);
        if (rc)
                return rc;
 
@@ -3451,10 +3391,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        u32 perm;
        int rc;
 
-       rc = secondary_ops->task_kill(p, info, sig, secid);
-       if (rc)
-               return rc;
-
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
@@ -3467,18 +3403,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        return rc;
 }
 
-static int selinux_task_prctl(int option,
-                             unsigned long arg2,
-                             unsigned long arg3,
-                             unsigned long arg4,
-                             unsigned long arg5)
-{
-       /* The current prctl operations do not appear to require
-          any SELinux controls since they merely observe or modify
-          the state of the current process. */
-       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
-}
-
 static int selinux_task_wait(struct task_struct *p)
 {
        return task_has_perm(p, current, PROCESS__SIGCHLD);
@@ -4047,10 +3971,6 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        struct avc_audit_data ad;
        int err;
 
-       err = secondary_ops->unix_stream_connect(sock, other, newsk);
-       if (err)
-               return err;
-
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
@@ -4844,7 +4764,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
        int err;
 
-       err = secondary_ops->netlink_send(sk, skb);
+       err = cap_netlink_send(sk, skb);
        if (err)
                return err;
 
@@ -4859,7 +4779,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability)
        int err;
        struct avc_audit_data ad;
 
-       err = secondary_ops->netlink_recv(skb, capability);
+       err = cap_netlink_recv(skb, capability);
        if (err)
                return err;
 
@@ -5167,11 +5087,6 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
                             char __user *shmaddr, int shmflg)
 {
        u32 perms;
-       int rc;
-
-       rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
-       if (rc)
-               return rc;
 
        if (shmflg & SHM_RDONLY)
                perms = SHM__READ;
@@ -5581,7 +5496,6 @@ static struct security_operations selinux_ops = {
        .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_set_creds =               selinux_bprm_set_creds,
-       .bprm_check_security =          selinux_bprm_check_security,
        .bprm_committing_creds =        selinux_bprm_committing_creds,
        .bprm_committed_creds =         selinux_bprm_committed_creds,
        .bprm_secureexec =              selinux_bprm_secureexec,
@@ -5623,8 +5537,6 @@ static struct security_operations selinux_ops = {
        .inode_getsecurity =            selinux_inode_getsecurity,
        .inode_setsecurity =            selinux_inode_setsecurity,
        .inode_listsecurity =           selinux_inode_listsecurity,
-       .inode_need_killpriv =          selinux_inode_need_killpriv,
-       .inode_killpriv =               selinux_inode_killpriv,
        .inode_getsecid =               selinux_inode_getsecid,
 
        .file_permission =              selinux_file_permission,
@@ -5644,17 +5556,12 @@ static struct security_operations selinux_ops = {
        .task_create =                  selinux_task_create,
        .cred_free =                    selinux_cred_free,
        .cred_prepare =                 selinux_cred_prepare,
-       .cred_commit =                  selinux_cred_commit,
        .kernel_act_as =                selinux_kernel_act_as,
        .kernel_create_files_as =       selinux_kernel_create_files_as,
-       .task_setuid =                  selinux_task_setuid,
-       .task_fix_setuid =              selinux_task_fix_setuid,
-       .task_setgid =                  selinux_task_setgid,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
        .task_getsecid =                selinux_task_getsecid,
-       .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
        .task_setioprio =               selinux_task_setioprio,
        .task_getioprio =               selinux_task_getioprio,
@@ -5664,7 +5571,6 @@ static struct security_operations selinux_ops = {
        .task_movememory =              selinux_task_movememory,
        .task_kill =                    selinux_task_kill,
        .task_wait =                    selinux_task_wait,
-       .task_prctl =                   selinux_task_prctl,
        .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
index c0c885427b91fe2ba57eebf5fa14f1a986410605..31df1d7c1aee2c0ead5536846a3ab7a46a074278 100644 (file)
@@ -24,6 +24,7 @@
    S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod")
    S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open")
    S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open")
+   S_(SECCLASS_SOCK_FILE, SOCK_FILE__OPEN, "open")
    S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open")
    S_(SECCLASS_FD, FD__USE, "use")
    S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto")
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write")
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay")
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv")
+   S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT, "nlmsg_tty_audit")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
index 0ba79fe00e11e834bd6c91cfd5020ff4563325f1..d645192ee950aaf74f2693943e38cd7dda9bfdbf 100644 (file)
 #define SOCK_FILE__SWAPON                         0x00004000UL
 #define SOCK_FILE__QUOTAON                        0x00008000UL
 #define SOCK_FILE__MOUNTON                        0x00010000UL
+#define SOCK_FILE__OPEN                           0x00020000UL
 #define FIFO_FILE__IOCTL                          0x00000001UL
 #define FIFO_FILE__READ                           0x00000002UL
 #define FIFO_FILE__WRITE                          0x00000004UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_WRITE         0x00800000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_RELAY         0x01000000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV      0x02000000UL
+#define NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT     0x04000000UL
 #define NETLINK_IP6FW_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_IP6FW_SOCKET__READ                0x00000002UL
 #define NETLINK_IP6FW_SOCKET__WRITE               0x00000004UL
index 3cc45168f674fbe6c98c89f9597398af6778a95a..c4e062336ef3a6d6265d99f750e6ea8c6ba8f8f7 100644 (file)
@@ -60,9 +60,7 @@ struct superblock_security_struct {
        u32 def_sid;                    /* default SID for labeling */
        u32 mntpoint_sid;               /* SECURITY_FS_USE_MNTPOINT context for files */
        unsigned int behavior;          /* labeling behavior */
-       unsigned char initialized;      /* initialization flag */
        unsigned char flags;            /* which mount options were specified */
-       unsigned char proc;             /* proc fs */
        struct mutex lock;
        struct list_head isec_head;
        spinlock_t isec_lock;
index 72447370bc959f4551583d421993138dc9c513b2..5c3434f7626fdd5cbe81ff0120ad3f092713fd95 100644 (file)
 #define POLICYDB_VERSION_MAX   POLICYDB_VERSION_BOUNDARY
 #endif
 
+/* Mask for just the mount related flags */
+#define SE_MNTMASK     0x0f
+/* Super block security struct flags for mount options */
 #define CONTEXT_MNT    0x01
 #define FSCONTEXT_MNT  0x02
 #define ROOTCONTEXT_MNT        0x04
 #define DEFCONTEXT_MNT 0x08
+/* Non-mount related flags */
+#define SE_SBINITIALIZED       0x10
+#define SE_SBPROC              0x20
+#define SE_SBLABELSUPP 0x40
 
 #define CONTEXT_STR    "context="
 #define FSCONTEXT_STR  "fscontext="
 #define ROOTCONTEXT_STR        "rootcontext="
 #define DEFCONTEXT_STR "defcontext="
+#define LABELSUPP_STR "seclabel"
 
 struct netlbl_lsm_secattr;
 
@@ -80,7 +88,6 @@ int security_policycap_supported(unsigned int req_cap);
 #define SEL_VEC_MAX 32
 struct av_decision {
        u32 allowed;
-       u32 decided;
        u32 auditallow;
        u32 auditdeny;
        u32 seqno;
index 4ed7bab89c5938675fd21442550a0791826077d8..c6875fd3b9d61445009f22d3ea8b91037b864d25 100644 (file)
@@ -113,7 +113,7 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
        { AUDIT_USER,           NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
        { AUDIT_SIGNAL_INFO,    NETLINK_AUDIT_SOCKET__NLMSG_READ     },
        { AUDIT_TTY_GET,        NETLINK_AUDIT_SOCKET__NLMSG_READ     },
-       { AUDIT_TTY_SET,        NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+       { AUDIT_TTY_SET,        NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT   },
 };
 
 
index 01ec6d2c6b97d310490b7c70410f5461eecdab3b..d3c8b982cfb0e179cb11d130318f3ebf3fd5b50d 100644 (file)
@@ -595,7 +595,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 
        length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
                          "%x %x %x %x %u",
-                         avd.allowed, avd.decided,
+                         avd.allowed, 0xffffffff,
                          avd.auditallow, avd.auditdeny,
                          avd.seqno);
 out2:
index c65e4fe4a0f176fc561717e6c28f0053332250e4..deeec6c013aef6dee9d664e3fe46b0a892d9f27e 100644 (file)
@@ -407,7 +407,6 @@ static int context_struct_compute_av(struct context *scontext,
         * Initialize the access vectors to the default values.
         */
        avd->allowed = 0;
-       avd->decided = 0xffffffff;
        avd->auditallow = 0;
        avd->auditdeny = 0xffffffff;
        avd->seqno = latest_granting;
@@ -743,7 +742,6 @@ int security_compute_av(u32 ssid,
 
        if (!ss_initialized) {
                avd->allowed = 0xffffffff;
-               avd->decided = 0xffffffff;
                avd->auditallow = 0;
                avd->auditdeny = 0xffffffff;
                avd->seqno = latest_granting;
index 2e0b83e77ffea727375a23e0abe29e894573a251..cfa19ca125e3596ed2b80b3bb0d2a0f05a594903 100644 (file)
@@ -162,8 +162,8 @@ int smk_access(char *subject_label, char *object_label, int request)
 
 /**
  * smk_curacc - determine if current has a specific access to an object
- * @object_label: a pointer to the object's Smack label
- * @request: the access requested, in "MAY" format
+ * @obj_label: a pointer to the object's Smack label
+ * @mode: the access requested, in "MAY" format
  *
  * This function checks the current subject label/object label pair
  * in the access rule list and returns 0 if the access is permitted,
index e7ded1326b0ff835cec48f4e448b0c69f8df1d04..84b62b5e9e2c681b3837a5da2a8cd2f39ce409f6 100644 (file)
@@ -91,6 +91,7 @@ struct inode_smack *new_inode_smack(char *smack)
 /**
  * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH
  * @ctp: child task pointer
+ * @mode: ptrace attachment mode
  *
  * Returns 0 if access is OK, an error code otherwise
  *
@@ -203,9 +204,8 @@ static void smack_sb_free_security(struct super_block *sb)
 
 /**
  * smack_sb_copy_data - copy mount options data for processing
- * @type: file system type
  * @orig: where to start
- * @smackopts
+ * @smackopts: mount options string
  *
  * Returns 0 on success or -ENOMEM on error.
  *
@@ -331,7 +331,7 @@ static int smack_sb_statfs(struct dentry *dentry)
 /**
  * smack_sb_mount - Smack check for mounting
  * @dev_name: unused
- * @nd: mount point
+ * @path: mount point
  * @type: unused
  * @flags: unused
  * @data: unused
@@ -370,7 +370,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
 
 /**
  * smack_inode_alloc_security - allocate an inode blob
- * @inode - the inode in need of a blob
+ * @inode: the inode in need of a blob
  *
  * Returns 0 if it gets a blob, -ENOMEM otherwise
  */
@@ -384,7 +384,7 @@ static int smack_inode_alloc_security(struct inode *inode)
 
 /**
  * smack_inode_free_security - free an inode blob
- * @inode - the inode with a blob
+ * @inode: the inode with a blob
  *
  * Clears the blob pointer in inode
  */
@@ -538,7 +538,6 @@ static int smack_inode_rename(struct inode *old_inode,
  * smack_inode_permission - Smack version of permission()
  * @inode: the inode in question
  * @mask: the access requested
- * @nd: unused
  *
  * This is the important Smack hook.
  *
@@ -701,8 +700,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
  * @inode: the object
  * @name: attribute name
  * @buffer: where to put the result
- * @size: size of the buffer
- * @err: unused
+ * @alloc: unused
  *
  * Returns the size of the attribute or an error code
  */
@@ -864,7 +862,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
 /**
  * smack_file_lock - Smack check on file locking
  * @file: the object
- * @cmd unused
+ * @cmd: unused
  *
  * Returns 0 if current has write access, error code otherwise
  */
@@ -1003,8 +1001,8 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
-/*
- * commit new credentials
+/**
+ * smack_cred_commit - commit new credentials
  * @new: the new credentials
  * @old: the original credentials
  */
@@ -1014,8 +1012,8 @@ static void smack_cred_commit(struct cred *new, const struct cred *old)
 
 /**
  * smack_kernel_act_as - Set the subjective context in a set of credentials
- * @new points to the set of credentials to be modified.
- * @secid specifies the security ID to be set
+ * @new: points to the set of credentials to be modified.
+ * @secid: specifies the security ID to be set
  *
  * Set the security data for a kernel service.
  */
@@ -1032,8 +1030,8 @@ static int smack_kernel_act_as(struct cred *new, u32 secid)
 
 /**
  * smack_kernel_create_files_as - Set the file creation label in a set of creds
- * @new points to the set of credentials to be modified
- * @inode points to the inode to use as a reference
+ * @new: points to the set of credentials to be modified
+ * @inode: points to the inode to use as a reference
  *
  * Set the file creation context in a set of credentials to the same
  * as the objective context of the specified inode
@@ -1242,7 +1240,7 @@ static int smack_task_wait(struct task_struct *p)
 /**
  * smack_task_to_inode - copy task smack into the inode blob
  * @p: task to copy from
- * inode: inode to copy to
+ * @inode: inode to copy to
  *
  * Sets the smack pointer in the inode security blob
  */
@@ -1260,7 +1258,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
  * smack_sk_alloc_security - Allocate a socket blob
  * @sk: the socket
  * @family: unused
- * @priority: memory allocation priority
+ * @gfp_flags: memory allocation flags
  *
  * Assign Smack pointers to current
  *
@@ -1974,7 +1972,7 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 
 /**
  * smack_ipc_getsecid - Extract smack security id
- * @ipcp: the object permissions
+ * @ipp: the object permissions
  * @secid: where result will be saved
  */
 static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
@@ -2251,7 +2249,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 /**
  * smack_socket_sendmsg - Smack check based on destination host
  * @sock: the socket
- * @msghdr: the message
+ * @msg: the message
  * @size: the size of the message
  *
  * Return 0 if the current subject can write to the destination
@@ -2292,8 +2290,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 
 
 /**
- * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
- *     pair to smack
+ * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack
  * @sap: netlabel secattr
  * @sip: where to put the result
  *
@@ -2414,7 +2411,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
  * @sock: the socket
  * @optval: user's destination
  * @optlen: size thereof
- * @len: max thereoe
+ * @len: max thereof
  *
  * returns zero on success, an error code otherwise
  */
@@ -2749,7 +2746,7 @@ static void smack_audit_rule_free(void *vrule)
 
 #endif /* CONFIG_AUDIT */
 
-/*
+/**
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2766,7 +2763,7 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        return 0;
 }
 
-/*
+/**
  * smack_secctx_to_secid - return the secid for a smack label
  * @secdata: smack label
  * @seclen: how long result is
@@ -2780,11 +2777,10 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
        return 0;
 }
 
-/*
+/**
  * smack_release_secctx - don't do anything.
- * @key_ref: unused
- * @context: unused
- * @perm: unused
+ * @secdata: unused
+ * @seclen: unused
  *
  * Exists to make sure nothing gets done, and properly
  */
index 51f0efc50dab46a9200f98b6d22db0039a9a0653..a1b57e4dba3e0865902a7a3691ee1d3afc1f8748 100644 (file)
@@ -245,7 +245,7 @@ out:
 
 /**
  * smk_write_load - write() for /smack/load
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start - must be 0
@@ -402,6 +402,7 @@ static void smk_cipso_doi(void)
 
 /**
  * smk_unlbl_ambient - initialize the unlabeled domain
+ * @oldambient: previous domain string
  */
 static void smk_unlbl_ambient(char *oldambient)
 {
@@ -513,7 +514,7 @@ static int smk_open_cipso(struct inode *inode, struct file *file)
 
 /**
  * smk_write_cipso - write() for /smack/cipso
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
@@ -733,7 +734,7 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
 
 /**
  * smk_write_netlbladdr - write() for /smack/netlabel
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
@@ -884,7 +885,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf,
 
 /**
  * smk_write_doi - write() for /smack/doi
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
@@ -949,7 +950,7 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf,
 
 /**
  * smk_write_direct - write() for /smack/direct
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
@@ -1024,7 +1025,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
 
 /**
  * smk_write_ambient - write() for /smack/ambient
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
@@ -1099,7 +1100,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
 
 /**
  * smk_write_onlycap - write() for /smack/onlycap
- * @filp: file pointer, not actually used
+ * @file: file pointer, not actually used
  * @buf: where to get the data from
  * @count: bytes sent
  * @ppos: where to start
diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig
new file mode 100644 (file)
index 0000000..c8f3857
--- /dev/null
@@ -0,0 +1,11 @@
+config SECURITY_TOMOYO
+       bool "TOMOYO Linux Support"
+       depends on SECURITY
+       select SECURITYFS
+       select SECURITY_PATH
+       default n
+       help
+         This selects TOMOYO Linux, pathname-based access control.
+         Required userspace tools and further information may be
+         found at <http://tomoyo.sourceforge.jp/>.
+         If you are unsure how to answer this question, answer N.
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
new file mode 100644 (file)
index 0000000..10ccd68
--- /dev/null
@@ -0,0 +1 @@
+obj-y = common.o realpath.o tomoyo.o domain.o file.o
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
new file mode 100644 (file)
index 0000000..92cea65
--- /dev/null
@@ -0,0 +1,2206 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Common functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/security.h>
+#include <linux/hardirq.h>
+#include "realpath.h"
+#include "common.h"
+#include "tomoyo.h"
+
+/* Has loading policy done? */
+bool tomoyo_policy_loaded;
+
+/* String table for functionality that takes 4 modes. */
+static const char *tomoyo_mode_4[4] = {
+       "disabled", "learning", "permissive", "enforcing"
+};
+/* String table for functionality that takes 2 modes. */
+static const char *tomoyo_mode_2[4] = {
+       "disabled", "enabled", "enabled", "enabled"
+};
+
+/* Table for profile. */
+static struct {
+       const char *keyword;
+       unsigned int current_value;
+       const unsigned int max_value;
+} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
+       [TOMOYO_MAC_FOR_FILE]     = { "MAC_FOR_FILE",        0,       3 },
+       [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
+       [TOMOYO_VERBOSE]          = { "TOMOYO_VERBOSE",      1,       1 },
+};
+
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile {
+       unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
+       const struct tomoyo_path_info *comment;
+} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
+
+/* Permit policy management by non-root user? */
+static bool tomoyo_manage_by_non_root;
+
+/* Utility functions. */
+
+/* Open operation for /sys/kernel/security/tomoyo/ interface. */
+static int tomoyo_open_control(const u8 type, struct file *file);
+/* Close /sys/kernel/security/tomoyo/ interface. */
+static int tomoyo_close_control(struct file *file);
+/* Read operation for /sys/kernel/security/tomoyo/ interface. */
+static int tomoyo_read_control(struct file *file, char __user *buffer,
+                              const int buffer_len);
+/* Write operation for /sys/kernel/security/tomoyo/ interface. */
+static int tomoyo_write_control(struct file *file, const char __user *buffer,
+                               const int buffer_len);
+
+/**
+ * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_is_byte_range(const char *str)
+{
+       return *str >= '0' && *str++ <= '3' &&
+               *str >= '0' && *str++ <= '7' &&
+               *str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_is_alphabet_char(const char c)
+{
+       return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+       return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src:  Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+static bool tomoyo_str_starts(char **src, const char *find)
+{
+       const int len = strlen(find);
+       char *tmp = *src;
+
+       if (strncmp(tmp, find, len))
+               return false;
+       tmp += len;
+       *src = tmp;
+       return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_normalize_line(unsigned char *buffer)
+{
+       unsigned char *sp = buffer;
+       unsigned char *dp = buffer;
+       bool first = true;
+
+       while (tomoyo_is_invalid(*sp))
+               sp++;
+       while (*sp) {
+               if (!first)
+                       *dp++ = ' ';
+               first = false;
+               while (tomoyo_is_valid(*sp))
+                       *dp++ = *sp++;
+               while (tomoyo_is_invalid(*sp))
+                       sp++;
+       }
+       *dp = '\0';
+}
+
+/**
+ * tomoyo_is_correct_path - Validate a pathname.
+ * @filename:     The pathname to check.
+ * @start_type:   Should the pathname start with '/'?
+ *                1 = must / -1 = must not / 0 = don't care
+ * @pattern_type: Can the pathname contain a wildcard?
+ *                1 = must / -1 = must not / 0 = don't care
+ * @end_type:     Should the pathname end with '/'?
+ *                1 = must / -1 = must not / 0 = don't care
+ * @function:     The name of function calling me.
+ *
+ * Check whether the given filename follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
+                           const s8 pattern_type, const s8 end_type,
+                           const char *function)
+{
+       bool contains_pattern = false;
+       unsigned char c;
+       unsigned char d;
+       unsigned char e;
+       const char *original_filename = filename;
+
+       if (!filename)
+               goto out;
+       c = *filename;
+       if (start_type == 1) { /* Must start with '/' */
+               if (c != '/')
+                       goto out;
+       } else if (start_type == -1) { /* Must not start with '/' */
+               if (c == '/')
+                       goto out;
+       }
+       if (c)
+               c = *(filename + strlen(filename) - 1);
+       if (end_type == 1) { /* Must end with '/' */
+               if (c != '/')
+                       goto out;
+       } else if (end_type == -1) { /* Must not end with '/' */
+               if (c == '/')
+                       goto out;
+       }
+       while ((c = *filename++) != '\0') {
+               if (c == '\\') {
+                       switch ((c = *filename++)) {
+                       case '\\':  /* "\\" */
+                               continue;
+                       case '$':   /* "\$" */
+                       case '+':   /* "\+" */
+                       case '?':   /* "\?" */
+                       case '*':   /* "\*" */
+                       case '@':   /* "\@" */
+                       case 'x':   /* "\x" */
+                       case 'X':   /* "\X" */
+                       case 'a':   /* "\a" */
+                       case 'A':   /* "\A" */
+                       case '-':   /* "\-" */
+                               if (pattern_type == -1)
+                                       break; /* Must not contain pattern */
+                               contains_pattern = true;
+                               continue;
+                       case '0':   /* "\ooo" */
+                       case '1':
+                       case '2':
+                       case '3':
+                               d = *filename++;
+                               if (d < '0' || d > '7')
+                                       break;
+                               e = *filename++;
+                               if (e < '0' || e > '7')
+                                       break;
+                               c = tomoyo_make_byte(c, d, e);
+                               if (tomoyo_is_invalid(c))
+                                       continue; /* pattern is not \000 */
+                       }
+                       goto out;
+               } else if (tomoyo_is_invalid(c)) {
+                       goto out;
+               }
+       }
+       if (pattern_type == 1) { /* Must contain pattern */
+               if (!contains_pattern)
+                       goto out;
+       }
+       return true;
+ out:
+       printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function,
+              original_filename);
+       return false;
+}
+
+/**
+ * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
+ * @domainname:   The domainname to check.
+ * @function:     The name of function calling me.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_is_correct_domain(const unsigned char *domainname,
+                             const char *function)
+{
+       unsigned char c;
+       unsigned char d;
+       unsigned char e;
+       const char *org_domainname = domainname;
+
+       if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
+                                  TOMOYO_ROOT_NAME_LEN))
+               goto out;
+       domainname += TOMOYO_ROOT_NAME_LEN;
+       if (!*domainname)
+               return true;
+       do {
+               if (*domainname++ != ' ')
+                       goto out;
+               if (*domainname++ != '/')
+                       goto out;
+               while ((c = *domainname) != '\0' && c != ' ') {
+                       domainname++;
+                       if (c == '\\') {
+                               c = *domainname++;
+                               switch ((c)) {
+                               case '\\':  /* "\\" */
+                                       continue;
+                               case '0':   /* "\ooo" */
+                               case '1':
+                               case '2':
+                               case '3':
+                                       d = *domainname++;
+                                       if (d < '0' || d > '7')
+                                               break;
+                                       e = *domainname++;
+                                       if (e < '0' || e > '7')
+                                               break;
+                                       c = tomoyo_make_byte(c, d, e);
+                                       if (tomoyo_is_invalid(c))
+                                               /* pattern is not \000 */
+                                               continue;
+                               }
+                               goto out;
+                       } else if (tomoyo_is_invalid(c)) {
+                               goto out;
+                       }
+               }
+       } while (*domainname);
+       return true;
+ out:
+       printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function,
+              org_domainname);
+       return false;
+}
+
+/**
+ * tomoyo_is_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_is_domain_def(const unsigned char *buffer)
+{
+       return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Caller must call down_read(&tomoyo_domain_list_lock); or
+ * down_write(&tomoyo_domain_list_lock); .
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+       struct tomoyo_domain_info *domain;
+       struct tomoyo_path_info name;
+
+       name.name = domainname;
+       tomoyo_fill_path_info(&name);
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               if (!domain->is_deleted &&
+                   !tomoyo_pathcmp(&name, domain->domainname))
+                       return domain;
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_path_depth - Evaluate the number of '/' in a string.
+ *
+ * @pathname: The string to evaluate.
+ *
+ * Returns path depth of the string.
+ *
+ * I score 2 for each of the '/' in the @pathname
+ * and score 1 if the @pathname ends with '/'.
+ */
+static int tomoyo_path_depth(const char *pathname)
+{
+       int i = 0;
+
+       if (pathname) {
+               const char *ep = pathname + strlen(pathname);
+               if (pathname < ep--) {
+                       if (*ep != '/')
+                               i++;
+                       while (pathname <= ep)
+                               if (*ep-- == '/')
+                                       i += 2;
+               }
+       }
+       return i;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+       char c;
+       int len = 0;
+
+       if (!filename)
+               return 0;
+       while ((c = *filename++) != '\0') {
+               if (c != '\\') {
+                       len++;
+                       continue;
+               }
+               c = *filename++;
+               switch (c) {
+               case '\\':  /* "\\" */
+                       len += 2;
+                       continue;
+               case '0':   /* "\ooo" */
+               case '1':
+               case '2':
+               case '3':
+                       c = *filename++;
+                       if (c < '0' || c > '7')
+                               break;
+                       c = *filename++;
+                       if (c < '0' || c > '7')
+                               break;
+                       len += 4;
+                       continue;
+               }
+               break;
+       }
+       return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+       const char *name = ptr->name;
+       const int len = strlen(name);
+
+       ptr->total_len = len;
+       ptr->const_len = tomoyo_const_part_length(name);
+       ptr->is_dir = len && (name[len - 1] == '/');
+       ptr->is_patterned = (ptr->const_len < len);
+       ptr->hash = full_name_hash(name, len);
+       ptr->depth = tomoyo_path_depth(name);
+}
+
+/**
+ * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character
+ * and "\-" pattern.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_to_pattern2(const char *filename,
+                                           const char *filename_end,
+                                           const char *pattern,
+                                           const char *pattern_end)
+{
+       while (filename < filename_end && pattern < pattern_end) {
+               char c;
+               if (*pattern != '\\') {
+                       if (*filename++ != *pattern++)
+                               return false;
+                       continue;
+               }
+               c = *filename;
+               pattern++;
+               switch (*pattern) {
+                       int i;
+                       int j;
+               case '?':
+                       if (c == '/') {
+                               return false;
+                       } else if (c == '\\') {
+                               if (filename[1] == '\\')
+                                       filename++;
+                               else if (tomoyo_is_byte_range(filename + 1))
+                                       filename += 3;
+                               else
+                                       return false;
+                       }
+                       break;
+               case '\\':
+                       if (c != '\\')
+                               return false;
+                       if (*++filename != '\\')
+                               return false;
+                       break;
+               case '+':
+                       if (!isdigit(c))
+                               return false;
+                       break;
+               case 'x':
+                       if (!isxdigit(c))
+                               return false;
+                       break;
+               case 'a':
+                       if (!tomoyo_is_alphabet_char(c))
+                               return false;
+                       break;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+                       if (c == '\\' && tomoyo_is_byte_range(filename + 1)
+                           && strncmp(filename + 1, pattern, 3) == 0) {
+                               filename += 3;
+                               pattern += 2;
+                               break;
+                       }
+                       return false; /* Not matched. */
+               case '*':
+               case '@':
+                       for (i = 0; i <= filename_end - filename; i++) {
+                               if (tomoyo_file_matches_to_pattern2(
+                                                   filename + i, filename_end,
+                                                   pattern + 1, pattern_end))
+                                       return true;
+                               c = filename[i];
+                               if (c == '.' && *pattern == '@')
+                                       break;
+                               if (c != '\\')
+                                       continue;
+                               if (filename[i + 1] == '\\')
+                                       i++;
+                               else if (tomoyo_is_byte_range(filename + i + 1))
+                                       i += 3;
+                               else
+                                       break; /* Bad pattern. */
+                       }
+                       return false; /* Not matched. */
+               default:
+                       j = 0;
+                       c = *pattern;
+                       if (c == '$') {
+                               while (isdigit(filename[j]))
+                                       j++;
+                       } else if (c == 'X') {
+                               while (isxdigit(filename[j]))
+                                       j++;
+                       } else if (c == 'A') {
+                               while (tomoyo_is_alphabet_char(filename[j]))
+                                       j++;
+                       }
+                       for (i = 1; i <= j; i++) {
+                               if (tomoyo_file_matches_to_pattern2(
+                                                   filename + i, filename_end,
+                                                   pattern + 1, pattern_end))
+                                       return true;
+                       }
+                       return false; /* Not matched or bad pattern. */
+               }
+               filename++;
+               pattern++;
+       }
+       while (*pattern == '\\' &&
+              (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+               pattern += 2;
+       return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_to_pattern(const char *filename,
+                                          const char *filename_end,
+                                          const char *pattern,
+                                          const char *pattern_end)
+{
+       const char *pattern_start = pattern;
+       bool first = true;
+       bool result;
+
+       while (pattern < pattern_end - 1) {
+               /* Split at "\-" pattern. */
+               if (*pattern++ != '\\' || *pattern++ != '-')
+                       continue;
+               result = tomoyo_file_matches_to_pattern2(filename,
+                                                        filename_end,
+                                                        pattern_start,
+                                                        pattern - 2);
+               if (first)
+                       result = !result;
+               if (result)
+                       return false;
+               first = false;
+               pattern_start = pattern;
+       }
+       result = tomoyo_file_matches_to_pattern2(filename, filename_end,
+                                                pattern_start, pattern_end);
+       return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ * @filename: The filename to check.
+ * @pattern:  The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ *   \\     \ itself.
+ *   \ooo   Octal representation of a byte.
+ *   \*     More than or equals to 0 character other than '/'.
+ *   \@     More than or equals to 0 character other than '/' or '.'.
+ *   \?     1 byte character other than '/'.
+ *   \$     More than or equals to 1 decimal digit.
+ *   \+     1 decimal digit.
+ *   \X     More than or equals to 1 hexadecimal digit.
+ *   \x     1 hexadecimal digit.
+ *   \A     More than or equals to 1 alphabet character.
+ *   \a     1 alphabet character.
+ *   \-     Subtraction operator.
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+                                const struct tomoyo_path_info *pattern)
+{
+       /*
+         if (!filename || !pattern)
+         return false;
+       */
+       const char *f = filename->name;
+       const char *p = pattern->name;
+       const int len = pattern->const_len;
+
+       /* If @pattern doesn't contain pattern, I can use strcmp(). */
+       if (!pattern->is_patterned)
+               return !tomoyo_pathcmp(filename, pattern);
+       /* Dont compare if the number of '/' differs. */
+       if (filename->depth != pattern->depth)
+               return false;
+       /* Compare the initial length without patterns. */
+       if (strncmp(f, p, len))
+               return false;
+       f += len;
+       p += len;
+       /* Main loop. Compare each directory component. */
+       while (*f && *p) {
+               const char *f_delimiter = strchr(f, '/');
+               const char *p_delimiter = strchr(p, '/');
+               if (!f_delimiter)
+                       f_delimiter = f + strlen(f);
+               if (!p_delimiter)
+                       p_delimiter = p + strlen(p);
+               if (!tomoyo_file_matches_to_pattern(f, f_delimiter,
+                                                   p, p_delimiter))
+                       return false;
+               f = f_delimiter;
+               if (*f)
+                       f++;
+               p = p_delimiter;
+               if (*p)
+                       p++;
+       }
+       /* Ignore trailing "\*" and "\@" in @pattern. */
+       while (*p == '\\' &&
+              (*(p + 1) == '*' || *(p + 1) == '@'))
+               p += 2;
+       return !*f && !*p;
+}
+
+/**
+ * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @fmt:  The printf()'s format string, followed by parameters.
+ *
+ * Returns true if output was written, false otherwise.
+ *
+ * The snprintf() will truncate, but tomoyo_io_printf() won't.
+ */
+bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       int pos = head->read_avail;
+       int size = head->readbuf_size - pos;
+
+       if (size <= 0)
+               return false;
+       va_start(args, fmt);
+       len = vsnprintf(head->read_buf + pos, size, fmt, args);
+       va_end(args);
+       if (pos + len >= head->readbuf_size)
+               return false;
+       head->read_avail += len;
+       return true;
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
+ * if this function didn't return NULL.
+ */
+static const char *tomoyo_get_exe(void)
+{
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       const char *cp = NULL;
+
+       if (!mm)
+               return NULL;
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+                       cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+                       break;
+               }
+       }
+       up_read(&mm->mmap_sem);
+       return cp;
+}
+
+/**
+ * tomoyo_get_msg - Get warning message.
+ *
+ * @is_enforce: Is it enforcing mode?
+ *
+ * Returns "ERROR" or "WARNING".
+ */
+const char *tomoyo_get_msg(const bool is_enforce)
+{
+       if (is_enforce)
+               return "ERROR";
+       else
+               return "WARNING";
+}
+
+/**
+ * tomoyo_check_flags - Check mode for specified functionality.
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @index:  The functionality to check mode.
+ *
+ * TOMOYO checks only process context.
+ * This code disables TOMOYO's enforcement in case the function is called from
+ * interrupt context.
+ */
+unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
+                               const u8 index)
+{
+       const u8 profile = domain->profile;
+
+       if (WARN_ON(in_interrupt()))
+               return 0;
+       return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
+#if TOMOYO_MAX_PROFILES != 256
+               && profile < TOMOYO_MAX_PROFILES
+#endif
+               && tomoyo_profile_ptr[profile] ?
+               tomoyo_profile_ptr[profile]->value[index] : 0;
+}
+
+/**
+ * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Returns true if domain policy violation warning should be printed to
+ * console.
+ */
+bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
+{
+       return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
+{
+       unsigned int count = 0;
+       struct tomoyo_acl_info *ptr;
+
+       if (!domain)
+               return true;
+       down_read(&tomoyo_domain_acl_info_list_lock);
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               if (ptr->type & TOMOYO_ACL_DELETED)
+                       continue;
+               switch (tomoyo_acl_type2(ptr)) {
+                       struct tomoyo_single_path_acl_record *acl1;
+                       struct tomoyo_double_path_acl_record *acl2;
+                       u16 perm;
+               case TOMOYO_TYPE_SINGLE_PATH_ACL:
+                       acl1 = container_of(ptr,
+                                   struct tomoyo_single_path_acl_record,
+                                           head);
+                       perm = acl1->perm;
+                       if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL))
+                               count++;
+                       if (perm &
+                           ((1 << TOMOYO_TYPE_READ_ACL) |
+                            (1 << TOMOYO_TYPE_WRITE_ACL)))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_CREATE_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL))
+                               count++;
+                       break;
+               case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+                       acl2 = container_of(ptr,
+                                   struct tomoyo_double_path_acl_record,
+                                           head);
+                       perm = acl2->perm;
+                       if (perm & (1 << TOMOYO_TYPE_LINK_ACL))
+                               count++;
+                       if (perm & (1 << TOMOYO_TYPE_RENAME_ACL))
+                               count++;
+                       break;
+               }
+       }
+       up_read(&tomoyo_domain_acl_info_list_lock);
+       if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
+               return true;
+       if (!domain->quota_warned) {
+               domain->quota_warned = true;
+               printk(KERN_WARNING "TOMOYO-WARNING: "
+                      "Domain '%s' has so many ACLs to hold. "
+                      "Stopped learning mode.\n", domain->domainname->name);
+       }
+       return false;
+}
+
+/**
+ * tomoyo_find_or_assign_new_profile - Create a new profile.
+ *
+ * @profile: Profile number to create.
+ *
+ * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
+ */
+static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
+                                                               int profile)
+{
+       static DEFINE_MUTEX(lock);
+       struct tomoyo_profile *ptr = NULL;
+       int i;
+
+       if (profile >= TOMOYO_MAX_PROFILES)
+               return NULL;
+       /***** EXCLUSIVE SECTION START *****/
+       mutex_lock(&lock);
+       ptr = tomoyo_profile_ptr[profile];
+       if (ptr)
+               goto ok;
+       ptr = tomoyo_alloc_element(sizeof(*ptr));
+       if (!ptr)
+               goto ok;
+       for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
+               ptr->value[i] = tomoyo_control_array[i].current_value;
+       mb(); /* Avoid out-of-order execution. */
+       tomoyo_profile_ptr[profile] = ptr;
+ ok:
+       mutex_unlock(&lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return ptr;
+}
+
+/**
+ * tomoyo_write_profile - Write to profile table.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       unsigned int i;
+       unsigned int value;
+       char *cp;
+       struct tomoyo_profile *profile;
+       unsigned long num;
+
+       cp = strchr(data, '-');
+       if (cp)
+               *cp = '\0';
+       if (strict_strtoul(data, 10, &num))
+               return -EINVAL;
+       if (cp)
+               data = cp + 1;
+       profile = tomoyo_find_or_assign_new_profile(num);
+       if (!profile)
+               return -EINVAL;
+       cp = strchr(data, '=');
+       if (!cp)
+               return -EINVAL;
+       *cp = '\0';
+       if (!strcmp(data, "COMMENT")) {
+               profile->comment = tomoyo_save_name(cp + 1);
+               return 0;
+       }
+       for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
+               if (strcmp(data, tomoyo_control_array[i].keyword))
+                       continue;
+               if (sscanf(cp + 1, "%u", &value) != 1) {
+                       int j;
+                       const char **modes;
+                       switch (i) {
+                       case TOMOYO_VERBOSE:
+                               modes = tomoyo_mode_2;
+                               break;
+                       default:
+                               modes = tomoyo_mode_4;
+                               break;
+                       }
+                       for (j = 0; j < 4; j++) {
+                               if (strcmp(cp + 1, modes[j]))
+                                       continue;
+                               value = j;
+                               break;
+                       }
+                       if (j == 4)
+                               return -EINVAL;
+               } else if (value > tomoyo_control_array[i].max_value) {
+                       value = tomoyo_control_array[i].max_value;
+               }
+               profile->value[i] = value;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/**
+ * tomoyo_read_profile - Read from profile table.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
+{
+       static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
+       int step;
+
+       if (head->read_eof)
+               return 0;
+       for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
+            step++) {
+               const u8 index = step / total;
+               u8 type = step % total;
+               const struct tomoyo_profile *profile
+                       = tomoyo_profile_ptr[index];
+               head->read_step = step;
+               if (!profile)
+                       continue;
+               if (!type) { /* Print profile' comment tag. */
+                       if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
+                                             index, profile->comment ?
+                                             profile->comment->name : ""))
+                               break;
+                       continue;
+               }
+               type--;
+               if (type < TOMOYO_MAX_CONTROL_INDEX) {
+                       const unsigned int value = profile->value[type];
+                       const char **modes = NULL;
+                       const char *keyword
+                               = tomoyo_control_array[type].keyword;
+                       switch (tomoyo_control_array[type].max_value) {
+                       case 3:
+                               modes = tomoyo_mode_4;
+                               break;
+                       case 1:
+                               modes = tomoyo_mode_2;
+                               break;
+                       }
+                       if (modes) {
+                               if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
+                                                     keyword, modes[value]))
+                                       break;
+                       } else {
+                               if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
+                                                     keyword, value))
+                                       break;
+                       }
+               }
+       }
+       if (step == TOMOYO_MAX_PROFILES * total)
+               head->read_eof = true;
+       return 0;
+}
+
+/* Structure for policy manager. */
+struct tomoyo_policy_manager_entry {
+       struct list_head list;
+       /* A path to program or a domainname. */
+       const struct tomoyo_path_info *manager;
+       bool is_domain;  /* True if manager is a domainname. */
+       bool is_deleted; /* True if this entry is deleted. */
+};
+
+/* The list for "struct tomoyo_policy_manager_entry". */
+static LIST_HEAD(tomoyo_policy_manager_list);
+static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
+
+/**
+ * tomoyo_update_manager_entry - Add a manager entry.
+ *
+ * @manager:   The path to manager or the domainnamme.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_manager_entry(const char *manager,
+                                      const bool is_delete)
+{
+       struct tomoyo_policy_manager_entry *new_entry;
+       struct tomoyo_policy_manager_entry *ptr;
+       const struct tomoyo_path_info *saved_manager;
+       int error = -ENOMEM;
+       bool is_domain = false;
+
+       if (tomoyo_is_domain_def(manager)) {
+               if (!tomoyo_is_correct_domain(manager, __func__))
+                       return -EINVAL;
+               is_domain = true;
+       } else {
+               if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__))
+                       return -EINVAL;
+       }
+       saved_manager = tomoyo_save_name(manager);
+       if (!saved_manager)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_policy_manager_list_lock);
+       list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+               if (ptr->manager != saved_manager)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->manager = saved_manager;
+       new_entry->is_domain = is_domain;
+       list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_policy_manager_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_write_manager_policy - Write manager policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+
+       if (!strcmp(data, "manage_by_non_root")) {
+               tomoyo_manage_by_non_root = !is_delete;
+               return 0;
+       }
+       return tomoyo_update_manager_entry(data, is_delete);
+}
+
+/**
+ * tomoyo_read_manager_policy - Read manager policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       if (head->read_eof)
+               return 0;
+       down_read(&tomoyo_policy_manager_list_lock);
+       list_for_each_cookie(pos, head->read_var2,
+                            &tomoyo_policy_manager_list) {
+               struct tomoyo_policy_manager_entry *ptr;
+               ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
+                                list);
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_policy_manager_list_lock);
+       head->read_eof = done;
+       return 0;
+}
+
+/**
+ * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
+ *
+ * Returns true if the current process is permitted to modify policy
+ * via /sys/kernel/security/tomoyo/ interface.
+ */
+static bool tomoyo_is_policy_manager(void)
+{
+       struct tomoyo_policy_manager_entry *ptr;
+       const char *exe;
+       const struct task_struct *task = current;
+       const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
+       bool found = false;
+
+       if (!tomoyo_policy_loaded)
+               return true;
+       if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
+               return false;
+       down_read(&tomoyo_policy_manager_list_lock);
+       list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+               if (!ptr->is_deleted && ptr->is_domain
+                   && !tomoyo_pathcmp(domainname, ptr->manager)) {
+                       found = true;
+                       break;
+               }
+       }
+       up_read(&tomoyo_policy_manager_list_lock);
+       if (found)
+               return true;
+       exe = tomoyo_get_exe();
+       if (!exe)
+               return false;
+       down_read(&tomoyo_policy_manager_list_lock);
+       list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+               if (!ptr->is_deleted && !ptr->is_domain
+                   && !strcmp(exe, ptr->manager->name)) {
+                       found = true;
+                       break;
+               }
+       }
+       up_read(&tomoyo_policy_manager_list_lock);
+       if (!found) { /* Reduce error messages. */
+               static pid_t last_pid;
+               const pid_t pid = current->pid;
+               if (last_pid != pid) {
+                       printk(KERN_WARNING "%s ( %s ) is not permitted to "
+                              "update policies.\n", domainname->name, exe);
+                       last_pid = pid;
+               }
+       }
+       tomoyo_free(exe);
+       return found;
+}
+
+/**
+ * tomoyo_is_select_one - Parse select command.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @data: String to parse.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
+                                const char *data)
+{
+       unsigned int pid;
+       struct tomoyo_domain_info *domain = NULL;
+
+       if (sscanf(data, "pid=%u", &pid) == 1) {
+               struct task_struct *p;
+               /***** CRITICAL SECTION START *****/
+               read_lock(&tasklist_lock);
+               p = find_task_by_vpid(pid);
+               if (p)
+                       domain = tomoyo_real_domain(p);
+               read_unlock(&tasklist_lock);
+               /***** CRITICAL SECTION END *****/
+       } else if (!strncmp(data, "domain=", 7)) {
+               if (tomoyo_is_domain_def(data + 7)) {
+                       down_read(&tomoyo_domain_list_lock);
+                       domain = tomoyo_find_domain(data + 7);
+                       up_read(&tomoyo_domain_list_lock);
+               }
+       } else
+               return false;
+       head->write_var1 = domain;
+       /* Accessing read_buf is safe because head->io_sem is held. */
+       if (!head->read_buf)
+               return true; /* Do nothing if open(O_WRONLY). */
+       head->read_avail = 0;
+       tomoyo_io_printf(head, "# select %s\n", data);
+       head->read_single_domain = true;
+       head->read_eof = !domain;
+       if (domain) {
+               struct tomoyo_domain_info *d;
+               head->read_var1 = NULL;
+               down_read(&tomoyo_domain_list_lock);
+               list_for_each_entry(d, &tomoyo_domain_list, list) {
+                       if (d == domain)
+                               break;
+                       head->read_var1 = &d->list;
+               }
+               up_read(&tomoyo_domain_list_lock);
+               head->read_var2 = NULL;
+               head->read_bit = 0;
+               head->read_step = 0;
+               if (domain->is_deleted)
+                       tomoyo_io_printf(head, "# This is a deleted domain.\n");
+       }
+       return true;
+}
+
+/**
+ * tomoyo_write_domain_policy - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       struct tomoyo_domain_info *domain = head->write_var1;
+       bool is_delete = false;
+       bool is_select = false;
+       bool is_undelete = false;
+       unsigned int profile;
+
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE))
+               is_delete = true;
+       else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
+               is_select = true;
+       else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_UNDELETE))
+               is_undelete = true;
+       if (is_select && tomoyo_is_select_one(head, data))
+               return 0;
+       /* Don't allow updating policies by non manager programs. */
+       if (!tomoyo_is_policy_manager())
+               return -EPERM;
+       if (tomoyo_is_domain_def(data)) {
+               domain = NULL;
+               if (is_delete)
+                       tomoyo_delete_domain(data);
+               else if (is_select) {
+                       down_read(&tomoyo_domain_list_lock);
+                       domain = tomoyo_find_domain(data);
+                       up_read(&tomoyo_domain_list_lock);
+               } else if (is_undelete)
+                       domain = tomoyo_undelete_domain(data);
+               else
+                       domain = tomoyo_find_or_assign_new_domain(data, 0);
+               head->write_var1 = domain;
+               return 0;
+       }
+       if (!domain)
+               return -EINVAL;
+
+       if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
+           && profile < TOMOYO_MAX_PROFILES) {
+               if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
+                       domain->profile = (u8) profile;
+               return 0;
+       }
+       if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
+               tomoyo_set_domain_flag(domain, is_delete,
+                              TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
+               return 0;
+       }
+       return tomoyo_write_file_policy(data, domain, is_delete);
+}
+
+/**
+ * tomoyo_print_single_path_acl - Print a single path ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_single_path_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head,
+                                        struct tomoyo_single_path_acl_record *
+                                        ptr)
+{
+       int pos;
+       u8 bit;
+       const char *atmark = "";
+       const char *filename;
+       const u16 perm = ptr->perm;
+
+       filename = ptr->filename->name;
+       for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION;
+            bit++) {
+               const char *msg;
+               if (!(perm & (1 << bit)))
+                       continue;
+               /* Print "read/write" instead of "read" and "write". */
+               if ((bit == TOMOYO_TYPE_READ_ACL ||
+                    bit == TOMOYO_TYPE_WRITE_ACL)
+                   && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
+                       continue;
+               msg = tomoyo_sp2keyword(bit);
+               pos = head->read_avail;
+               if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg,
+                                     atmark, filename))
+                       goto out;
+       }
+       head->read_bit = 0;
+       return true;
+ out:
+       head->read_bit = bit;
+       head->read_avail = pos;
+       return false;
+}
+
+/**
+ * tomoyo_print_double_path_acl - Print a double path ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_double_path_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head,
+                                        struct tomoyo_double_path_acl_record *
+                                        ptr)
+{
+       int pos;
+       const char *atmark1 = "";
+       const char *atmark2 = "";
+       const char *filename1;
+       const char *filename2;
+       const u8 perm = ptr->perm;
+       u8 bit;
+
+       filename1 = ptr->filename1->name;
+       filename2 = ptr->filename2->name;
+       for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION;
+            bit++) {
+               const char *msg;
+               if (!(perm & (1 << bit)))
+                       continue;
+               msg = tomoyo_dp2keyword(bit);
+               pos = head->read_avail;
+               if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg,
+                                     atmark1, filename1, atmark2, filename2))
+                       goto out;
+       }
+       head->read_bit = 0;
+       return true;
+ out:
+       head->read_bit = bit;
+       head->read_avail = pos;
+       return false;
+}
+
+/**
+ * tomoyo_print_entry - Print an ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to an ACL entry.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
+                              struct tomoyo_acl_info *ptr)
+{
+       const u8 acl_type = tomoyo_acl_type2(ptr);
+
+       if (acl_type & TOMOYO_ACL_DELETED)
+               return true;
+       if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) {
+               struct tomoyo_single_path_acl_record *acl
+                       = container_of(ptr,
+                                      struct tomoyo_single_path_acl_record,
+                                      head);
+               return tomoyo_print_single_path_acl(head, acl);
+       }
+       if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) {
+               struct tomoyo_double_path_acl_record *acl
+                       = container_of(ptr,
+                                      struct tomoyo_double_path_acl_record,
+                                      head);
+               return tomoyo_print_double_path_acl(head, acl);
+       }
+       BUG(); /* This must not happen. */
+       return false;
+}
+
+/**
+ * tomoyo_read_domain_policy - Read domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *dpos;
+       struct list_head *apos;
+       bool done = true;
+
+       if (head->read_eof)
+               return 0;
+       if (head->read_step == 0)
+               head->read_step = 1;
+       down_read(&tomoyo_domain_list_lock);
+       list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain;
+               const char *quota_exceeded = "";
+               const char *transition_failed = "";
+               const char *ignore_global_allow_read = "";
+               domain = list_entry(dpos, struct tomoyo_domain_info, list);
+               if (head->read_step != 1)
+                       goto acl_loop;
+               if (domain->is_deleted && !head->read_single_domain)
+                       continue;
+               /* Print domainname and flags. */
+               if (domain->quota_warned)
+                       quota_exceeded = "quota_exceeded\n";
+               if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED)
+                       transition_failed = "transition_failed\n";
+               if (domain->flags &
+                   TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
+                       ignore_global_allow_read
+                               = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
+               if (!tomoyo_io_printf(head,
+                                     "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n"
+                                     "%s%s%s\n", domain->domainname->name,
+                                     domain->profile, quota_exceeded,
+                                     transition_failed,
+                                     ignore_global_allow_read)) {
+                       done = false;
+                       break;
+               }
+               head->read_step = 2;
+acl_loop:
+               if (head->read_step == 3)
+                       goto tail_mark;
+               /* Print ACL entries in the domain. */
+               down_read(&tomoyo_domain_acl_info_list_lock);
+               list_for_each_cookie(apos, head->read_var2,
+                                     &domain->acl_info_list) {
+                       struct tomoyo_acl_info *ptr
+                               = list_entry(apos, struct tomoyo_acl_info,
+                                             list);
+                       if (!tomoyo_print_entry(head, ptr)) {
+                               done = false;
+                               break;
+                       }
+               }
+               up_read(&tomoyo_domain_acl_info_list_lock);
+               if (!done)
+                       break;
+               head->read_step = 3;
+tail_mark:
+               if (!tomoyo_io_printf(head, "\n")) {
+                       done = false;
+                       break;
+               }
+               head->read_step = 1;
+               if (head->read_single_domain)
+                       break;
+       }
+       up_read(&tomoyo_domain_list_lock);
+       head->read_eof = done;
+       return 0;
+}
+
+/**
+ * tomoyo_write_domain_profile - Assign profile for specified domain.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ *
+ * This is equivalent to doing
+ *
+ *     ( echo "select " $domainname; echo "use_profile " $profile ) |
+ *     /usr/lib/ccs/loadpolicy -d
+ */
+static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       char *cp = strchr(data, ' ');
+       struct tomoyo_domain_info *domain;
+       unsigned long profile;
+
+       if (!cp)
+               return -EINVAL;
+       *cp = '\0';
+       down_read(&tomoyo_domain_list_lock);
+       domain = tomoyo_find_domain(cp + 1);
+       up_read(&tomoyo_domain_list_lock);
+       if (strict_strtoul(data, 10, &profile))
+               return -EINVAL;
+       if (domain && profile < TOMOYO_MAX_PROFILES
+           && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+               domain->profile = (u8) profile;
+       return 0;
+}
+
+/**
+ * tomoyo_read_domain_profile - Read only domainname and profile.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns list of profile number and domainname pairs.
+ *
+ * This is equivalent to doing
+ *
+ *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
+ *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
+ *     domainname = $0; } else if ( $1 == "use_profile" ) {
+ *     print $2 " " domainname; domainname = ""; } } ; '
+ */
+static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       if (head->read_eof)
+               return 0;
+       down_read(&tomoyo_domain_list_lock);
+       list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain;
+               domain = list_entry(pos, struct tomoyo_domain_info, list);
+               if (domain->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, "%u %s\n", domain->profile,
+                                     domain->domainname->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_domain_list_lock);
+       head->read_eof = done;
+       return 0;
+}
+
+/**
+ * tomoyo_write_pid: Specify PID to obtain domainname.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
+{
+       unsigned long pid;
+       /* No error check. */
+       strict_strtoul(head->write_buf, 10, &pid);
+       head->read_step = (int) pid;
+       head->read_eof = false;
+       return 0;
+}
+
+/**
+ * tomoyo_read_pid - Get domainname of the specified PID.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns the domainname which the specified PID is in on success,
+ * empty string otherwise.
+ * The PID is specified by tomoyo_write_pid() so that the user can obtain
+ * using read()/write() interface rather than sysctl() interface.
+ */
+static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
+{
+       if (head->read_avail == 0 && !head->read_eof) {
+               const int pid = head->read_step;
+               struct task_struct *p;
+               struct tomoyo_domain_info *domain = NULL;
+               /***** CRITICAL SECTION START *****/
+               read_lock(&tasklist_lock);
+               p = find_task_by_vpid(pid);
+               if (p)
+                       domain = tomoyo_real_domain(p);
+               read_unlock(&tasklist_lock);
+               /***** CRITICAL SECTION END *****/
+               if (domain)
+                       tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
+                                        domain->domainname->name);
+               head->read_eof = true;
+       }
+       return 0;
+}
+
+/**
+ * tomoyo_write_exception_policy - Write exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
+               return tomoyo_write_domain_keeper_policy(data, false,
+                                                        is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
+               return tomoyo_write_domain_keeper_policy(data, true, is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
+               return tomoyo_write_domain_initializer_policy(data, false,
+                                                             is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
+               return tomoyo_write_domain_initializer_policy(data, true,
+                                                             is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
+               return tomoyo_write_alias_policy(data, is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
+               return tomoyo_write_globally_readable_policy(data, is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
+               return tomoyo_write_pattern_policy(data, is_delete);
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
+               return tomoyo_write_no_rewrite_policy(data, is_delete);
+       return -EINVAL;
+}
+
+/**
+ * tomoyo_read_exception_policy - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+{
+       if (!head->read_eof) {
+               switch (head->read_step) {
+               case 0:
+                       head->read_var2 = NULL;
+                       head->read_step = 1;
+               case 1:
+                       if (!tomoyo_read_domain_keeper_policy(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 2;
+               case 2:
+                       if (!tomoyo_read_globally_readable_policy(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 3;
+               case 3:
+                       head->read_var2 = NULL;
+                       head->read_step = 4;
+               case 4:
+                       if (!tomoyo_read_domain_initializer_policy(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 5;
+               case 5:
+                       if (!tomoyo_read_alias_policy(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 6;
+               case 6:
+                       head->read_var2 = NULL;
+                       head->read_step = 7;
+               case 7:
+                       if (!tomoyo_read_file_pattern(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 8;
+               case 8:
+                       if (!tomoyo_read_no_rewrite_policy(head))
+                               break;
+                       head->read_var2 = NULL;
+                       head->read_step = 9;
+               case 9:
+                       head->read_eof = true;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+/* path to policy loader */
+static const char *tomoyo_loader = "/sbin/tomoyo-init";
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+       /*
+        * Don't activate MAC if the policy loader doesn't exist.
+        * If the initrd includes /sbin/init but real-root-dev has not
+        * mounted on / yet, activating MAC will block the system since
+        * policies are not loaded yet.
+        * Thus, let do_execve() call this function everytime.
+        */
+       struct nameidata nd;
+
+       if (path_lookup(tomoyo_loader, LOOKUP_FOLLOW, &nd)) {
+               printk(KERN_INFO "Not activating Mandatory Access Control now "
+                      "since %s doesn't exist.\n", tomoyo_loader);
+               return false;
+       }
+       path_put(&nd.path);
+       return true;
+}
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+       char *argv[2];
+       char *envp[3];
+
+       if (tomoyo_policy_loaded)
+               return;
+       /*
+        * Check filename is /sbin/init or /sbin/tomoyo-start.
+        * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
+        * be passed.
+        * You can create /sbin/tomoyo-start by
+        * "ln -s /bin/true /sbin/tomoyo-start".
+        */
+       if (strcmp(filename, "/sbin/init") &&
+           strcmp(filename, "/sbin/tomoyo-start"))
+               return;
+       if (!tomoyo_policy_loader_exists())
+               return;
+
+       printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+              tomoyo_loader);
+       argv[0] = (char *) tomoyo_loader;
+       argv[1] = NULL;
+       envp[0] = "HOME=/";
+       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+       envp[2] = NULL;
+       call_usermodehelper(argv[0], argv, envp, 1);
+
+       printk(KERN_INFO "TOMOYO: 2.2.0-pre   2009/02/01\n");
+       printk(KERN_INFO "Mandatory Access Control activated.\n");
+       tomoyo_policy_loaded = true;
+       { /* Check all profiles currently assigned to domains are defined. */
+               struct tomoyo_domain_info *domain;
+               down_read(&tomoyo_domain_list_lock);
+               list_for_each_entry(domain, &tomoyo_domain_list, list) {
+                       const u8 profile = domain->profile;
+                       if (tomoyo_profile_ptr[profile])
+                               continue;
+                       panic("Profile %u (used by '%s') not defined.\n",
+                             profile, domain->domainname->name);
+               }
+               up_read(&tomoyo_domain_list_lock);
+       }
+}
+
+/**
+ * tomoyo_read_version: Get version.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns version information.
+ */
+static int tomoyo_read_version(struct tomoyo_io_buffer *head)
+{
+       if (!head->read_eof) {
+               tomoyo_io_printf(head, "2.2.0-pre");
+               head->read_eof = true;
+       }
+       return 0;
+}
+
+/**
+ * tomoyo_read_self_domain - Get the current process's domainname.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns the current process's domainname.
+ */
+static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
+{
+       if (!head->read_eof) {
+               /*
+                * tomoyo_domain()->domainname != NULL
+                * because every process belongs to a domain and
+                * the domain's name cannot be NULL.
+                */
+               tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
+               head->read_eof = true;
+       }
+       return 0;
+}
+
+/**
+ * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @type: Type of interface.
+ * @file: Pointer to "struct file".
+ *
+ * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
+ */
+static int tomoyo_open_control(const u8 type, struct file *file)
+{
+       struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head));
+
+       if (!head)
+               return -ENOMEM;
+       mutex_init(&head->io_sem);
+       switch (type) {
+       case TOMOYO_DOMAINPOLICY:
+               /* /sys/kernel/security/tomoyo/domain_policy */
+               head->write = tomoyo_write_domain_policy;
+               head->read = tomoyo_read_domain_policy;
+               break;
+       case TOMOYO_EXCEPTIONPOLICY:
+               /* /sys/kernel/security/tomoyo/exception_policy */
+               head->write = tomoyo_write_exception_policy;
+               head->read = tomoyo_read_exception_policy;
+               break;
+       case TOMOYO_SELFDOMAIN:
+               /* /sys/kernel/security/tomoyo/self_domain */
+               head->read = tomoyo_read_self_domain;
+               break;
+       case TOMOYO_DOMAIN_STATUS:
+               /* /sys/kernel/security/tomoyo/.domain_status */
+               head->write = tomoyo_write_domain_profile;
+               head->read = tomoyo_read_domain_profile;
+               break;
+       case TOMOYO_PROCESS_STATUS:
+               /* /sys/kernel/security/tomoyo/.process_status */
+               head->write = tomoyo_write_pid;
+               head->read = tomoyo_read_pid;
+               break;
+       case TOMOYO_VERSION:
+               /* /sys/kernel/security/tomoyo/version */
+               head->read = tomoyo_read_version;
+               head->readbuf_size = 128;
+               break;
+       case TOMOYO_MEMINFO:
+               /* /sys/kernel/security/tomoyo/meminfo */
+               head->write = tomoyo_write_memory_quota;
+               head->read = tomoyo_read_memory_counter;
+               head->readbuf_size = 512;
+               break;
+       case TOMOYO_PROFILE:
+               /* /sys/kernel/security/tomoyo/profile */
+               head->write = tomoyo_write_profile;
+               head->read = tomoyo_read_profile;
+               break;
+       case TOMOYO_MANAGER:
+               /* /sys/kernel/security/tomoyo/manager */
+               head->write = tomoyo_write_manager_policy;
+               head->read = tomoyo_read_manager_policy;
+               break;
+       }
+       if (!(file->f_mode & FMODE_READ)) {
+               /*
+                * No need to allocate read_buf since it is not opened
+                * for reading.
+                */
+               head->read = NULL;
+       } else {
+               if (!head->readbuf_size)
+                       head->readbuf_size = 4096 * 2;
+               head->read_buf = tomoyo_alloc(head->readbuf_size);
+               if (!head->read_buf) {
+                       tomoyo_free(head);
+                       return -ENOMEM;
+               }
+       }
+       if (!(file->f_mode & FMODE_WRITE)) {
+               /*
+                * No need to allocate write_buf since it is not opened
+                * for writing.
+                */
+               head->write = NULL;
+       } else if (head->write) {
+               head->writebuf_size = 4096 * 2;
+               head->write_buf = tomoyo_alloc(head->writebuf_size);
+               if (!head->write_buf) {
+                       tomoyo_free(head->read_buf);
+                       tomoyo_free(head);
+                       return -ENOMEM;
+               }
+       }
+       file->private_data = head;
+       /*
+        * Call the handler now if the file is
+        * /sys/kernel/security/tomoyo/self_domain
+        * so that the user can use
+        * cat < /sys/kernel/security/tomoyo/self_domain"
+        * to know the current process's domainname.
+        */
+       if (type == TOMOYO_SELFDOMAIN)
+               tomoyo_read_control(file, NULL, 0);
+       return 0;
+}
+
+/**
+ * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:       Pointer to "struct file".
+ * @buffer:     Poiner to buffer to write to.
+ * @buffer_len: Size of @buffer.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static int tomoyo_read_control(struct file *file, char __user *buffer,
+                              const int buffer_len)
+{
+       int len = 0;
+       struct tomoyo_io_buffer *head = file->private_data;
+       char *cp;
+
+       if (!head->read)
+               return -ENOSYS;
+       if (mutex_lock_interruptible(&head->io_sem))
+               return -EINTR;
+       /* Call the policy handler. */
+       len = head->read(head);
+       if (len < 0)
+               goto out;
+       /* Write to buffer. */
+       len = head->read_avail;
+       if (len > buffer_len)
+               len = buffer_len;
+       if (!len)
+               goto out;
+       /* head->read_buf changes by some functions. */
+       cp = head->read_buf;
+       if (copy_to_user(buffer, cp, len)) {
+               len = -EFAULT;
+               goto out;
+       }
+       head->read_avail -= len;
+       memmove(cp, cp + len, head->read_avail);
+ out:
+       mutex_unlock(&head->io_sem);
+       return len;
+}
+
+/**
+ * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:       Pointer to "struct file".
+ * @buffer:     Pointer to buffer to read from.
+ * @buffer_len: Size of @buffer.
+ *
+ * Returns @buffer_len on success, negative value otherwise.
+ */
+static int tomoyo_write_control(struct file *file, const char __user *buffer,
+                               const int buffer_len)
+{
+       struct tomoyo_io_buffer *head = file->private_data;
+       int error = buffer_len;
+       int avail_len = buffer_len;
+       char *cp0 = head->write_buf;
+
+       if (!head->write)
+               return -ENOSYS;
+       if (!access_ok(VERIFY_READ, buffer, buffer_len))
+               return -EFAULT;
+       /* Don't allow updating policies by non manager programs. */
+       if (head->write != tomoyo_write_pid &&
+           head->write != tomoyo_write_domain_policy &&
+           !tomoyo_is_policy_manager())
+               return -EPERM;
+       if (mutex_lock_interruptible(&head->io_sem))
+               return -EINTR;
+       /* Read a line and dispatch it to the policy handler. */
+       while (avail_len > 0) {
+               char c;
+               if (head->write_avail >= head->writebuf_size - 1) {
+                       error = -ENOMEM;
+                       break;
+               } else if (get_user(c, buffer)) {
+                       error = -EFAULT;
+                       break;
+               }
+               buffer++;
+               avail_len--;
+               cp0[head->write_avail++] = c;
+               if (c != '\n')
+                       continue;
+               cp0[head->write_avail - 1] = '\0';
+               head->write_avail = 0;
+               tomoyo_normalize_line(cp0);
+               head->write(head);
+       }
+       mutex_unlock(&head->io_sem);
+       return error;
+}
+
+/**
+ * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ *
+ * Releases memory and returns 0.
+ */
+static int tomoyo_close_control(struct file *file)
+{
+       struct tomoyo_io_buffer *head = file->private_data;
+
+       /* Release memory used for policy I/O. */
+       tomoyo_free(head->read_buf);
+       head->read_buf = NULL;
+       tomoyo_free(head->write_buf);
+       head->write_buf = NULL;
+       tomoyo_free(head);
+       head = NULL;
+       file->private_data = NULL;
+       return 0;
+}
+
+/**
+ * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry.
+ *
+ * @acl_type:  Type of ACL entry.
+ *
+ * Returns pointer to the ACL entry on success, NULL otherwise.
+ */
+void *tomoyo_alloc_acl_element(const u8 acl_type)
+{
+       int len;
+       struct tomoyo_acl_info *ptr;
+
+       switch (acl_type) {
+       case TOMOYO_TYPE_SINGLE_PATH_ACL:
+               len = sizeof(struct tomoyo_single_path_acl_record);
+               break;
+       case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+               len = sizeof(struct tomoyo_double_path_acl_record);
+               break;
+       default:
+               return NULL;
+       }
+       ptr = tomoyo_alloc_element(len);
+       if (!ptr)
+               return NULL;
+       ptr->type = acl_type;
+       return ptr;
+}
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+       const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+               - ((u8 *) NULL);
+       return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+       return tomoyo_close_control(file);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+                          loff_t *ppos)
+{
+       return tomoyo_read_control(file, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       return tomoyo_write_control(file, buf, count);
+}
+
+/* Operations for /sys/kernel/security/tomoyo/ interface. */
+static const struct file_operations tomoyo_operations = {
+       .open    = tomoyo_open,
+       .release = tomoyo_release,
+       .read    = tomoyo_read,
+       .write   = tomoyo_write,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name:   The name of the interface file.
+ * @mode:   The permission of the interface file.
+ * @parent: The parent directory.
+ * @key:    Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+                                      struct dentry *parent, const u8 key)
+{
+       securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+                              &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+       struct dentry *tomoyo_dir;
+
+       /* Don't create securityfs entries unless registered. */
+       if (current_cred()->security != &tomoyo_kernel_domain)
+               return 0;
+
+       tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+       tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
+                           TOMOYO_DOMAINPOLICY);
+       tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+                           TOMOYO_EXCEPTIONPOLICY);
+       tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
+                           TOMOYO_SELFDOMAIN);
+       tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
+                           TOMOYO_DOMAIN_STATUS);
+       tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
+                           TOMOYO_PROCESS_STATUS);
+       tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
+                           TOMOYO_MEMINFO);
+       tomoyo_create_entry("profile",          0600, tomoyo_dir,
+                           TOMOYO_PROFILE);
+       tomoyo_create_entry("manager",          0600, tomoyo_dir,
+                           TOMOYO_MANAGER);
+       tomoyo_create_entry("version",          0400, tomoyo_dir,
+                           TOMOYO_VERSION);
+       return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
new file mode 100644 (file)
index 0000000..6dcb7cc
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * security/tomoyo/common.h
+ *
+ * Common functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#ifndef _SECURITY_TOMOYO_COMMON_H
+#define _SECURITY_TOMOYO_COMMON_H
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/list.h>
+
+struct dentry;
+struct vfsmount;
+
+/* Temporary buffer for holding pathnames. */
+struct tomoyo_page_buffer {
+       char buffer[4096];
+};
+
+/* Structure for holding a token. */
+struct tomoyo_path_info {
+       const char *name;
+       u32 hash;          /* = full_name_hash(name, strlen(name)) */
+       u16 total_len;     /* = strlen(name)                       */
+       u16 const_len;     /* = tomoyo_const_part_length(name)     */
+       bool is_dir;       /* = tomoyo_strendswith(name, "/")      */
+       bool is_patterned; /* = tomoyo_path_contains_pattern(name) */
+       u16 depth;         /* = tomoyo_path_depth(name)            */
+};
+
+/*
+ * This is the max length of a token.
+ *
+ * A token consists of only ASCII printable characters.
+ * Non printable characters in a token is represented in \ooo style
+ * octal string. Thus, \ itself is represented as \\.
+ */
+#define TOMOYO_MAX_PATHNAME_LEN 4000
+
+/* Structure for holding requested pathname. */
+struct tomoyo_path_info_with_data {
+       /* Keep "head" first, for this pointer is passed to tomoyo_free(). */
+       struct tomoyo_path_info head;
+       char bariier1[16]; /* Safeguard for overrun. */
+       char body[TOMOYO_MAX_PATHNAME_LEN];
+       char barrier2[16]; /* Safeguard for overrun. */
+};
+
+/*
+ * Common header for holding ACL entries.
+ *
+ * Packing "struct tomoyo_acl_info" allows
+ * "struct tomoyo_single_path_acl_record" to embed "u16" and
+ * "struct tomoyo_double_path_acl_record" to embed "u8"
+ * without enlarging their structure size.
+ */
+struct tomoyo_acl_info {
+       struct list_head list;
+       /*
+        * Type of this ACL entry.
+        *
+        * MSB is is_deleted flag.
+        */
+       u8 type;
+} __packed;
+
+/* This ACL entry is deleted.           */
+#define TOMOYO_ACL_DELETED        0x80
+
+/* Structure for domain information. */
+struct tomoyo_domain_info {
+       struct list_head list;
+       struct list_head acl_info_list;
+       /* Name of this domain. Never NULL.          */
+       const struct tomoyo_path_info *domainname;
+       u8 profile;        /* Profile number to use. */
+       u8 is_deleted;     /* Delete flag.
+                             0 = active.
+                             1 = deleted but undeletable.
+                             255 = deleted and no longer undeletable. */
+       bool quota_warned; /* Quota warnning flag.   */
+       /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */
+       u8 flags;
+};
+
+/* Profile number is an integer between 0 and 255. */
+#define TOMOYO_MAX_PROFILES 256
+
+/* Ignore "allow_read" directive in exception policy. */
+#define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1
+/*
+ * This domain was unable to create a new domain at tomoyo_find_next_domain()
+ * because the name of the domain to be created was too long or
+ * it could not allocate memory.
+ * More than one process continued execve() without domain transition.
+ */
+#define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED        2
+
+/*
+ * Structure for "allow_read/write", "allow_execute", "allow_read",
+ * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
+ * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar",
+ * "allow_truncate", "allow_symlink" and "allow_rewrite" directive.
+ */
+struct tomoyo_single_path_acl_record {
+       struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */
+       u16 perm;
+       /* Pointer to single pathname. */
+       const struct tomoyo_path_info *filename;
+};
+
+/* Structure for "allow_rename" and "allow_link" directive. */
+struct tomoyo_double_path_acl_record {
+       struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */
+       u8 perm;
+       /* Pointer to single pathname. */
+       const struct tomoyo_path_info *filename1;
+       /* Pointer to single pathname. */
+       const struct tomoyo_path_info *filename2;
+};
+
+/* Keywords for ACLs. */
+#define TOMOYO_KEYWORD_ALIAS                     "alias "
+#define TOMOYO_KEYWORD_ALLOW_READ                "allow_read "
+#define TOMOYO_KEYWORD_DELETE                    "delete "
+#define TOMOYO_KEYWORD_DENY_REWRITE              "deny_rewrite "
+#define TOMOYO_KEYWORD_FILE_PATTERN              "file_pattern "
+#define TOMOYO_KEYWORD_INITIALIZE_DOMAIN         "initialize_domain "
+#define TOMOYO_KEYWORD_KEEP_DOMAIN               "keep_domain "
+#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN      "no_initialize_domain "
+#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN            "no_keep_domain "
+#define TOMOYO_KEYWORD_SELECT                    "select "
+#define TOMOYO_KEYWORD_UNDELETE                  "undelete "
+#define TOMOYO_KEYWORD_USE_PROFILE               "use_profile "
+#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ  "ignore_global_allow_read"
+/* A domain definition starts with <kernel>. */
+#define TOMOYO_ROOT_NAME                         "<kernel>"
+#define TOMOYO_ROOT_NAME_LEN                     (sizeof(TOMOYO_ROOT_NAME) - 1)
+
+/* Index numbers for Access Controls. */
+#define TOMOYO_MAC_FOR_FILE                  0  /* domain_policy.conf */
+#define TOMOYO_MAX_ACCEPT_ENTRY              1
+#define TOMOYO_VERBOSE                       2
+#define TOMOYO_MAX_CONTROL_INDEX             3
+
+/* Structure for reading/writing policy via securityfs interfaces. */
+struct tomoyo_io_buffer {
+       int (*read) (struct tomoyo_io_buffer *);
+       int (*write) (struct tomoyo_io_buffer *);
+       /* Exclusive lock for this structure.   */
+       struct mutex io_sem;
+       /* The position currently reading from. */
+       struct list_head *read_var1;
+       /* Extra variables for reading.         */
+       struct list_head *read_var2;
+       /* The position currently writing to.   */
+       struct tomoyo_domain_info *write_var1;
+       /* The step for reading.                */
+       int read_step;
+       /* Buffer for reading.                  */
+       char *read_buf;
+       /* EOF flag for reading.                */
+       bool read_eof;
+       /* Read domain ACL of specified PID?    */
+       bool read_single_domain;
+       /* Extra variable for reading.          */
+       u8 read_bit;
+       /* Bytes available for reading.         */
+       int read_avail;
+       /* Size of read buffer.                 */
+       int readbuf_size;
+       /* Buffer for writing.                  */
+       char *write_buf;
+       /* Bytes available for writing.         */
+       int write_avail;
+       /* Size of write buffer.                */
+       int writebuf_size;
+};
+
+/* Check whether the domain has too many ACL entries to hold. */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
+/* Transactional sprintf() for policy dump. */
+bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+       __attribute__ ((format(printf, 2, 3)));
+/* Check whether the domainname is correct. */
+bool tomoyo_is_correct_domain(const unsigned char *domainname,
+                             const char *function);
+/* Check whether the token is correct. */
+bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
+                           const s8 pattern_type, const s8 end_type,
+                           const char *function);
+/* Check whether the token can be a domainname. */
+bool tomoyo_is_domain_def(const unsigned char *buffer);
+/* Check whether the given filename matches the given pattern. */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+                                const struct tomoyo_path_info *pattern);
+/* Read "alias" entry in exception policy. */
+bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
+/*
+ * Read "initialize_domain" and "no_initialize_domain" entry
+ * in exception policy.
+ */
+bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head);
+/* Read "keep_domain" and "no_keep_domain" entry in exception policy. */
+bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
+/* Read "file_pattern" entry in exception policy. */
+bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
+/* Read "allow_read" entry in exception policy. */
+bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
+/* Read "deny_rewrite" entry in exception policy. */
+bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head);
+/* Write domain policy violation warning message to console? */
+bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
+/* Convert double path operation to operation name. */
+const char *tomoyo_dp2keyword(const u8 operation);
+/* Get the last component of the given domainname. */
+const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
+/* Get warning message. */
+const char *tomoyo_get_msg(const bool is_enforce);
+/* Convert single path operation to operation name. */
+const char *tomoyo_sp2keyword(const u8 operation);
+/* Delete a domain. */
+int tomoyo_delete_domain(char *data);
+/* Create "alias" entry in exception policy. */
+int tomoyo_write_alias_policy(char *data, const bool is_delete);
+/*
+ * Create "initialize_domain" and "no_initialize_domain" entry
+ * in exception policy.
+ */
+int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
+                                          const bool is_delete);
+/* Create "keep_domain" and "no_keep_domain" entry in exception policy. */
+int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
+                                     const bool is_delete);
+/*
+ * Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
+ * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
+ * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar",
+ * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
+ * "allow_link" entry in domain policy.
+ */
+int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
+                            const bool is_delete);
+/* Create "allow_read" entry in exception policy. */
+int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
+/* Create "deny_rewrite" entry in exception policy. */
+int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
+/* Create "file_pattern" entry in exception policy. */
+int tomoyo_write_pattern_policy(char *data, const bool is_delete);
+/* Find a domain by the given name. */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+/* Find or create a domain by the given name. */
+struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
+                                                           domainname,
+                                                           const u8 profile);
+/* Undelete a domain. */
+struct tomoyo_domain_info *tomoyo_undelete_domain(const char *domainname);
+/* Check mode for specified functionality. */
+unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
+                               const u8 index);
+/* Allocate memory for structures. */
+void *tomoyo_alloc_acl_element(const u8 acl_type);
+/* Fill in "struct tomoyo_path_info" members. */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
+/* Run policy loader when /sbin/init starts. */
+void tomoyo_load_policy(const char *filename);
+/* Change "struct tomoyo_domain_info"->flags. */
+void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
+                           const bool is_delete, const u8 flags);
+
+/* strcmp() for "struct tomoyo_path_info" structure. */
+static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
+                                 const struct tomoyo_path_info *b)
+{
+       return a->hash != b->hash || strcmp(a->name, b->name);
+}
+
+/* Get type of an ACL entry. */
+static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr)
+{
+       return ptr->type & ~TOMOYO_ACL_DELETED;
+}
+
+/* Get type of an ACL entry. */
+static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr)
+{
+       return ptr->type;
+}
+
+/**
+ * tomoyo_is_valid - Check whether the character is a valid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is a valid character, false otherwise.
+ */
+static inline bool tomoyo_is_valid(const unsigned char c)
+{
+       return c > ' ' && c < 127;
+}
+
+/**
+ * tomoyo_is_invalid - Check whether the character is an invalid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an invalid character, false otherwise.
+ */
+static inline bool tomoyo_is_invalid(const unsigned char c)
+{
+       return c && (c <= ' ' || c >= 127);
+}
+
+/* The list for "struct tomoyo_domain_info". */
+extern struct list_head tomoyo_domain_list;
+extern struct rw_semaphore tomoyo_domain_list_lock;
+
+/* Lock for domain->acl_info_list. */
+extern struct rw_semaphore tomoyo_domain_acl_info_list_lock;
+
+/* Has /sbin/init started? */
+extern bool tomoyo_policy_loaded;
+
+/* The kernel's domain. */
+extern struct tomoyo_domain_info tomoyo_kernel_domain;
+
+/**
+ * list_for_each_cookie - iterate over a list with cookie.
+ * @pos:        the &struct list_head to use as a loop cursor.
+ * @cookie:     the &struct list_head to use as a cookie.
+ * @head:       the head for your list.
+ *
+ * Same with list_for_each() except that this primitive uses @cookie
+ * so that we can continue iteration.
+ * @cookie must be NULL when iteration starts, and @cookie will become
+ * NULL when iteration finishes.
+ */
+#define list_for_each_cookie(pos, cookie, head)                       \
+       for (({ if (!cookie)                                          \
+                                    cookie = head; }),               \
+            pos = (cookie)->next;                                    \
+            prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
+            (cookie) = pos, pos = pos->next)
+
+#endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
new file mode 100644 (file)
index 0000000..093a756
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * security/tomoyo/domain.c
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#include "common.h"
+#include "tomoyo.h"
+#include "realpath.h"
+#include <linux/binfmts.h>
+
+/* Variables definitions.*/
+
+/* The initial domain. */
+struct tomoyo_domain_info tomoyo_kernel_domain;
+
+/* The list for "struct tomoyo_domain_info". */
+LIST_HEAD(tomoyo_domain_list);
+DECLARE_RWSEM(tomoyo_domain_list_lock);
+
+/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
+struct tomoyo_domain_initializer_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *domainname;    /* This may be NULL */
+       const struct tomoyo_path_info *program;
+       bool is_deleted;
+       bool is_not;       /* True if this entry is "no_initialize_domain".  */
+       /* True if the domainname is tomoyo_get_last_name(). */
+       bool is_last_name;
+};
+
+/* Structure for "keep_domain" and "no_keep_domain" keyword. */
+struct tomoyo_domain_keeper_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *domainname;
+       const struct tomoyo_path_info *program;       /* This may be NULL */
+       bool is_deleted;
+       bool is_not;       /* True if this entry is "no_keep_domain".        */
+       /* True if the domainname is tomoyo_get_last_name(). */
+       bool is_last_name;
+};
+
+/* Structure for "alias" keyword. */
+struct tomoyo_alias_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *original_name;
+       const struct tomoyo_path_info *aliased_name;
+       bool is_deleted;
+};
+
+/**
+ * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ * @flags:     Flags to set or clear.
+ *
+ * Returns nothing.
+ */
+void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
+                           const bool is_delete, const u8 flags)
+{
+       /* We need to serialize because this is bitfield operation. */
+       static DEFINE_SPINLOCK(lock);
+       /***** CRITICAL SECTION START *****/
+       spin_lock(&lock);
+       if (!is_delete)
+               domain->flags |= flags;
+       else
+               domain->flags &= ~flags;
+       spin_unlock(&lock);
+       /***** CRITICAL SECTION END *****/
+}
+
+/**
+ * tomoyo_get_last_name - Get last component of a domainname.
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Returns the last component of the domainname.
+ */
+const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
+{
+       const char *cp0 = domain->domainname->name;
+       const char *cp1 = strrchr(cp0, ' ');
+
+       if (cp1)
+               return cp1 + 1;
+       return cp0;
+}
+
+/* The list for "struct tomoyo_domain_initializer_entry". */
+static LIST_HEAD(tomoyo_domain_initializer_list);
+static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
+
+/**
+ * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
+ *
+ * @domainname: The name of domain. May be NULL.
+ * @program:    The name of program.
+ * @is_not:     True if it is "no_initialize_domain" entry.
+ * @is_delete:  True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_domain_initializer_entry(const char *domainname,
+                                                 const char *program,
+                                                 const bool is_not,
+                                                 const bool is_delete)
+{
+       struct tomoyo_domain_initializer_entry *new_entry;
+       struct tomoyo_domain_initializer_entry *ptr;
+       const struct tomoyo_path_info *saved_program;
+       const struct tomoyo_path_info *saved_domainname = NULL;
+       int error = -ENOMEM;
+       bool is_last_name = false;
+
+       if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
+               return -EINVAL; /* No patterns allowed. */
+       if (domainname) {
+               if (!tomoyo_is_domain_def(domainname) &&
+                   tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
+                       is_last_name = true;
+               else if (!tomoyo_is_correct_domain(domainname, __func__))
+                       return -EINVAL;
+               saved_domainname = tomoyo_save_name(domainname);
+               if (!saved_domainname)
+                       return -ENOMEM;
+       }
+       saved_program = tomoyo_save_name(program);
+       if (!saved_program)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_initializer_list_lock);
+       list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+               if (ptr->is_not != is_not ||
+                   ptr->domainname != saved_domainname ||
+                   ptr->program != saved_program)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->domainname = saved_domainname;
+       new_entry->program = saved_program;
+       new_entry->is_not = is_not;
+       new_entry->is_last_name = is_last_name;
+       list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_domain_initializer_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_domain_initializer_list_lock);
+       list_for_each_cookie(pos, head->read_var2,
+                            &tomoyo_domain_initializer_list) {
+               const char *no;
+               const char *from = "";
+               const char *domain = "";
+               struct tomoyo_domain_initializer_entry *ptr;
+               ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
+                                 list);
+               if (ptr->is_deleted)
+                       continue;
+               no = ptr->is_not ? "no_" : "";
+               if (ptr->domainname) {
+                       from = " from ";
+                       domain = ptr->domainname->name;
+               }
+               if (!tomoyo_io_printf(head,
+                                     "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
+                                     "%s%s%s\n", no, ptr->program->name, from,
+                                     domain)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_domain_initializer_list_lock);
+       return done;
+}
+
+/**
+ * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_not:    True if it is "no_initialize_domain" entry.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
+                                          const bool is_delete)
+{
+       char *cp = strstr(data, " from ");
+
+       if (cp) {
+               *cp = '\0';
+               return tomoyo_update_domain_initializer_entry(cp + 6, data,
+                                                             is_not,
+                                                             is_delete);
+       }
+       return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
+                                                     is_delete);
+}
+
+/**
+ * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
+ *
+ * @domainname: The name of domain.
+ * @program:    The name of program.
+ * @last_name:  The last component of @domainname.
+ *
+ * Returns true if executing @program reinitializes domain transition,
+ * false otherwise.
+ */
+static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
+                                        domainname,
+                                        const struct tomoyo_path_info *program,
+                                        const struct tomoyo_path_info *
+                                        last_name)
+{
+       struct tomoyo_domain_initializer_entry *ptr;
+       bool flag = false;
+
+       down_read(&tomoyo_domain_initializer_list_lock);
+       list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
+               if (ptr->is_deleted)
+                       continue;
+               if (ptr->domainname) {
+                       if (!ptr->is_last_name) {
+                               if (ptr->domainname != domainname)
+                                       continue;
+                       } else {
+                               if (tomoyo_pathcmp(ptr->domainname, last_name))
+                                       continue;
+                       }
+               }
+               if (tomoyo_pathcmp(ptr->program, program))
+                       continue;
+               if (ptr->is_not) {
+                       flag = false;
+                       break;
+               }
+               flag = true;
+       }
+       up_read(&tomoyo_domain_initializer_list_lock);
+       return flag;
+}
+
+/* The list for "struct tomoyo_domain_keeper_entry". */
+static LIST_HEAD(tomoyo_domain_keeper_list);
+static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
+
+/**
+ * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
+ *
+ * @domainname: The name of domain.
+ * @program:    The name of program. May be NULL.
+ * @is_not:     True if it is "no_keep_domain" entry.
+ * @is_delete:  True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_domain_keeper_entry(const char *domainname,
+                                            const char *program,
+                                            const bool is_not,
+                                            const bool is_delete)
+{
+       struct tomoyo_domain_keeper_entry *new_entry;
+       struct tomoyo_domain_keeper_entry *ptr;
+       const struct tomoyo_path_info *saved_domainname;
+       const struct tomoyo_path_info *saved_program = NULL;
+       static DEFINE_MUTEX(lock);
+       int error = -ENOMEM;
+       bool is_last_name = false;
+
+       if (!tomoyo_is_domain_def(domainname) &&
+           tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
+               is_last_name = true;
+       else if (!tomoyo_is_correct_domain(domainname, __func__))
+               return -EINVAL;
+       if (program) {
+               if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
+                       return -EINVAL;
+               saved_program = tomoyo_save_name(program);
+               if (!saved_program)
+                       return -ENOMEM;
+       }
+       saved_domainname = tomoyo_save_name(domainname);
+       if (!saved_domainname)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_keeper_list_lock);
+       list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+               if (ptr->is_not != is_not ||
+                   ptr->domainname != saved_domainname ||
+                   ptr->program != saved_program)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->domainname = saved_domainname;
+       new_entry->program = saved_program;
+       new_entry->is_not = is_not;
+       new_entry->is_last_name = is_last_name;
+       list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_domain_keeper_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_not:    True if it is "no_keep_domain" entry.
+ * @is_delete: True if it is a delete request.
+ *
+ */
+int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
+                                     const bool is_delete)
+{
+       char *cp = strstr(data, " from ");
+
+       if (cp) {
+               *cp = '\0';
+               return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
+                                                        is_delete);
+       }
+       return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
+}
+
+/**
+ * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_domain_keeper_list_lock);
+       list_for_each_cookie(pos, head->read_var2,
+                            &tomoyo_domain_keeper_list) {
+               struct tomoyo_domain_keeper_entry *ptr;
+               const char *no;
+               const char *from = "";
+               const char *program = "";
+
+               ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
+               if (ptr->is_deleted)
+                       continue;
+               no = ptr->is_not ? "no_" : "";
+               if (ptr->program) {
+                       from = " from ";
+                       program = ptr->program->name;
+               }
+               if (!tomoyo_io_printf(head,
+                                     "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
+                                     "%s%s%s\n", no, program, from,
+                                     ptr->domainname->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_domain_keeper_list_lock);
+       return done;
+}
+
+/**
+ * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
+ *
+ * @domainname: The name of domain.
+ * @program:    The name of program.
+ * @last_name:  The last component of @domainname.
+ *
+ * Returns true if executing @program supresses domain transition,
+ * false otherwise.
+ */
+static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
+                                   const struct tomoyo_path_info *program,
+                                   const struct tomoyo_path_info *last_name)
+{
+       struct tomoyo_domain_keeper_entry *ptr;
+       bool flag = false;
+
+       down_read(&tomoyo_domain_keeper_list_lock);
+       list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+               if (ptr->is_deleted)
+                       continue;
+               if (!ptr->is_last_name) {
+                       if (ptr->domainname != domainname)
+                               continue;
+               } else {
+                       if (tomoyo_pathcmp(ptr->domainname, last_name))
+                               continue;
+               }
+               if (ptr->program && tomoyo_pathcmp(ptr->program, program))
+                       continue;
+               if (ptr->is_not) {
+                       flag = false;
+                       break;
+               }
+               flag = true;
+       }
+       up_read(&tomoyo_domain_keeper_list_lock);
+       return flag;
+}
+
+/* The list for "struct tomoyo_alias_entry". */
+static LIST_HEAD(tomoyo_alias_list);
+static DECLARE_RWSEM(tomoyo_alias_list_lock);
+
+/**
+ * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
+ *
+ * @original_name: The original program's real name.
+ * @aliased_name:  The symbolic program's symbolic link's name.
+ * @is_delete:     True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_alias_entry(const char *original_name,
+                                    const char *aliased_name,
+                                    const bool is_delete)
+{
+       struct tomoyo_alias_entry *new_entry;
+       struct tomoyo_alias_entry *ptr;
+       const struct tomoyo_path_info *saved_original_name;
+       const struct tomoyo_path_info *saved_aliased_name;
+       int error = -ENOMEM;
+
+       if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
+           !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
+               return -EINVAL; /* No patterns allowed. */
+       saved_original_name = tomoyo_save_name(original_name);
+       saved_aliased_name = tomoyo_save_name(aliased_name);
+       if (!saved_original_name || !saved_aliased_name)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_alias_list_lock);
+       list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+               if (ptr->original_name != saved_original_name ||
+                   ptr->aliased_name != saved_aliased_name)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->original_name = saved_original_name;
+       new_entry->aliased_name = saved_aliased_name;
+       list_add_tail(&new_entry->list, &tomoyo_alias_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_alias_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_alias_list_lock);
+       list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
+               struct tomoyo_alias_entry *ptr;
+
+               ptr = list_entry(pos, struct tomoyo_alias_entry, list);
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
+                                     ptr->original_name->name,
+                                     ptr->aliased_name->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_alias_list_lock);
+       return done;
+}
+
+/**
+ * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_alias_policy(char *data, const bool is_delete)
+{
+       char *cp = strchr(data, ' ');
+
+       if (!cp)
+               return -EINVAL;
+       *cp++ = '\0';
+       return tomoyo_update_alias_entry(data, cp, is_delete);
+}
+
+/* Domain create/delete/undelete handler. */
+
+/* #define TOMOYO_DEBUG_DOMAIN_UNDELETE */
+
+/**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns 0.
+ */
+int tomoyo_delete_domain(char *domainname)
+{
+       struct tomoyo_domain_info *domain;
+       struct tomoyo_path_info name;
+
+       name.name = domainname;
+       tomoyo_fill_path_info(&name);
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_list_lock);
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+       printk(KERN_DEBUG "tomoyo_delete_domain %s\n", domainname);
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               if (tomoyo_pathcmp(domain->domainname, &name))
+                       continue;
+               printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);
+       }
+#endif
+       /* Is there an active domain? */
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               struct tomoyo_domain_info *domain2;
+               /* Never delete tomoyo_kernel_domain */
+               if (domain == &tomoyo_kernel_domain)
+                       continue;
+               if (domain->is_deleted ||
+                   tomoyo_pathcmp(domain->domainname, &name))
+                       continue;
+               /* Mark already deleted domains as non undeletable. */
+               list_for_each_entry(domain2, &tomoyo_domain_list, list) {
+                       if (!domain2->is_deleted ||
+                           tomoyo_pathcmp(domain2->domainname, &name))
+                               continue;
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+                       if (domain2->is_deleted != 255)
+                               printk(KERN_DEBUG
+                                      "Marked %p as non undeletable\n",
+                                      domain2);
+#endif
+                       domain2->is_deleted = 255;
+               }
+               /* Delete and mark active domain as undeletable. */
+               domain->is_deleted = 1;
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+               printk(KERN_DEBUG "Marked %p as undeletable\n", domain);
+#endif
+               break;
+       }
+       up_write(&tomoyo_domain_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return 0;
+}
+
+/**
+ * tomoyo_undelete_domain - Undelete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ */
+struct tomoyo_domain_info *tomoyo_undelete_domain(const char *domainname)
+{
+       struct tomoyo_domain_info *domain;
+       struct tomoyo_domain_info *candidate_domain = NULL;
+       struct tomoyo_path_info name;
+
+       name.name = domainname;
+       tomoyo_fill_path_info(&name);
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_list_lock);
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+       printk(KERN_DEBUG "tomoyo_undelete_domain %s\n", domainname);
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               if (tomoyo_pathcmp(domain->domainname, &name))
+                       continue;
+               printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);
+       }
+#endif
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               if (tomoyo_pathcmp(&name, domain->domainname))
+                       continue;
+               if (!domain->is_deleted) {
+                       /* This domain is active. I can't undelete. */
+                       candidate_domain = NULL;
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+                       printk(KERN_DEBUG "%p is active. I can't undelete.\n",
+                              domain);
+#endif
+                       break;
+               }
+               /* Is this domain undeletable? */
+               if (domain->is_deleted == 1)
+                       candidate_domain = domain;
+       }
+       if (candidate_domain) {
+               candidate_domain->is_deleted = 0;
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+               printk(KERN_DEBUG "%p was undeleted.\n", candidate_domain);
+#endif
+       }
+       up_write(&tomoyo_domain_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return candidate_domain;
+}
+
+/**
+ * tomoyo_find_or_assign_new_domain - Create a domain.
+ *
+ * @domainname: The name of domain.
+ * @profile:    Profile number to assign if the domain was newly created.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ */
+struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
+                                                           domainname,
+                                                           const u8 profile)
+{
+       struct tomoyo_domain_info *domain = NULL;
+       const struct tomoyo_path_info *saved_domainname;
+
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_list_lock);
+       domain = tomoyo_find_domain(domainname);
+       if (domain)
+               goto out;
+       if (!tomoyo_is_correct_domain(domainname, __func__))
+               goto out;
+       saved_domainname = tomoyo_save_name(domainname);
+       if (!saved_domainname)
+               goto out;
+       /* Can I reuse memory of deleted domain? */
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               struct task_struct *p;
+               struct tomoyo_acl_info *ptr;
+               bool flag;
+               if (!domain->is_deleted ||
+                   domain->domainname != saved_domainname)
+                       continue;
+               flag = false;
+               /***** CRITICAL SECTION START *****/
+               read_lock(&tasklist_lock);
+               for_each_process(p) {
+                       if (tomoyo_real_domain(p) != domain)
+                               continue;
+                       flag = true;
+                       break;
+               }
+               read_unlock(&tasklist_lock);
+               /***** CRITICAL SECTION END *****/
+               if (flag)
+                       continue;
+#ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
+               printk(KERN_DEBUG "Reusing %p %s\n", domain,
+                      domain->domainname->name);
+#endif
+               list_for_each_entry(ptr, &domain->acl_info_list, list) {
+                       ptr->type |= TOMOYO_ACL_DELETED;
+               }
+               tomoyo_set_domain_flag(domain, true, domain->flags);
+               domain->profile = profile;
+               domain->quota_warned = false;
+               mb(); /* Avoid out-of-order execution. */
+               domain->is_deleted = 0;
+               goto out;
+       }
+       /* No memory reusable. Create using new memory. */
+       domain = tomoyo_alloc_element(sizeof(*domain));
+       if (domain) {
+               INIT_LIST_HEAD(&domain->acl_info_list);
+               domain->domainname = saved_domainname;
+               domain->profile = profile;
+               list_add_tail(&domain->list, &tomoyo_domain_list);
+       }
+ out:
+       up_write(&tomoyo_domain_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return domain;
+}
+
+/**
+ * tomoyo_find_next_domain - Find a domain.
+ *
+ * @bprm:           Pointer to "struct linux_binprm".
+ * @next_domain:    Pointer to pointer to "struct tomoyo_domain_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_find_next_domain(struct linux_binprm *bprm,
+                           struct tomoyo_domain_info **next_domain)
+{
+       /*
+        * This function assumes that the size of buffer returned by
+        * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
+        */
+       struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
+       struct tomoyo_domain_info *old_domain = tomoyo_domain();
+       struct tomoyo_domain_info *domain = NULL;
+       const char *old_domain_name = old_domain->domainname->name;
+       const char *original_name = bprm->filename;
+       char *new_domain_name = NULL;
+       char *real_program_name = NULL;
+       char *symlink_program_name = NULL;
+       const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
+       const bool is_enforce = (mode == 3);
+       int retval = -ENOMEM;
+       struct tomoyo_path_info r; /* real name */
+       struct tomoyo_path_info s; /* symlink name */
+       struct tomoyo_path_info l; /* last name */
+       static bool initialized;
+
+       if (!tmp)
+               goto out;
+
+       if (!initialized) {
+               /*
+                * Built-in initializers. This is needed because policies are
+                * not loaded until starting /sbin/init.
+                */
+               tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
+                                                      false, false);
+               tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
+                                                      false, false);
+               initialized = true;
+       }
+
+       /* Get tomoyo_realpath of program. */
+       retval = -ENOENT;
+       /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
+       real_program_name = tomoyo_realpath(original_name);
+       if (!real_program_name)
+               goto out;
+       /* Get tomoyo_realpath of symbolic link. */
+       symlink_program_name = tomoyo_realpath_nofollow(original_name);
+       if (!symlink_program_name)
+               goto out;
+
+       r.name = real_program_name;
+       tomoyo_fill_path_info(&r);
+       s.name = symlink_program_name;
+       tomoyo_fill_path_info(&s);
+       l.name = tomoyo_get_last_name(old_domain);
+       tomoyo_fill_path_info(&l);
+
+       /* Check 'alias' directive. */
+       if (tomoyo_pathcmp(&r, &s)) {
+               struct tomoyo_alias_entry *ptr;
+               /* Is this program allowed to be called via symbolic links? */
+               down_read(&tomoyo_alias_list_lock);
+               list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+                       if (ptr->is_deleted ||
+                           tomoyo_pathcmp(&r, ptr->original_name) ||
+                           tomoyo_pathcmp(&s, ptr->aliased_name))
+                               continue;
+                       memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
+                       strncpy(real_program_name, ptr->aliased_name->name,
+                               TOMOYO_MAX_PATHNAME_LEN - 1);
+                       tomoyo_fill_path_info(&r);
+                       break;
+               }
+               up_read(&tomoyo_alias_list_lock);
+       }
+
+       /* Check execute permission. */
+       retval = tomoyo_check_exec_perm(old_domain, &r, tmp);
+       if (retval < 0)
+               goto out;
+
+       new_domain_name = tmp->buffer;
+       if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+               /* Transit to the child of tomoyo_kernel_domain domain. */
+               snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
+                        TOMOYO_ROOT_NAME " " "%s", real_program_name);
+       } else if (old_domain == &tomoyo_kernel_domain &&
+                  !tomoyo_policy_loaded) {
+               /*
+                * Needn't to transit from kernel domain before starting
+                * /sbin/init. But transit from kernel domain if executing
+                * initializers because they might start before /sbin/init.
+                */
+               domain = old_domain;
+       } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+               /* Keep current domain. */
+               domain = old_domain;
+       } else {
+               /* Normal domain transition. */
+               snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
+                        "%s %s", old_domain_name, real_program_name);
+       }
+       if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+               goto done;
+       down_read(&tomoyo_domain_list_lock);
+       domain = tomoyo_find_domain(new_domain_name);
+       up_read(&tomoyo_domain_list_lock);
+       if (domain)
+               goto done;
+       if (is_enforce)
+               goto done;
+       domain = tomoyo_find_or_assign_new_domain(new_domain_name,
+                                                 old_domain->profile);
+ done:
+       if (domain)
+               goto out;
+       printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
+              new_domain_name);
+       if (is_enforce)
+               retval = -EPERM;
+       else
+               tomoyo_set_domain_flag(old_domain, false,
+                                      TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
+ out:
+       tomoyo_free(real_program_name);
+       tomoyo_free(symlink_program_name);
+       *next_domain = domain ? domain : old_domain;
+       tomoyo_free(tmp);
+       return retval;
+}
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
new file mode 100644 (file)
index 0000000..65f50c1
--- /dev/null
@@ -0,0 +1,1241 @@
+/*
+ * security/tomoyo/file.c
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#include "common.h"
+#include "tomoyo.h"
+#include "realpath.h"
+#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
+
+/* Structure for "allow_read" keyword. */
+struct tomoyo_globally_readable_file_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *filename;
+       bool is_deleted;
+};
+
+/* Structure for "file_pattern" keyword. */
+struct tomoyo_pattern_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *pattern;
+       bool is_deleted;
+};
+
+/* Structure for "deny_rewrite" keyword. */
+struct tomoyo_no_rewrite_entry {
+       struct list_head list;
+       const struct tomoyo_path_info *pattern;
+       bool is_deleted;
+};
+
+/* Keyword array for single path operations. */
+static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
+       [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
+       [TOMOYO_TYPE_EXECUTE_ACL]    = "execute",
+       [TOMOYO_TYPE_READ_ACL]       = "read",
+       [TOMOYO_TYPE_WRITE_ACL]      = "write",
+       [TOMOYO_TYPE_CREATE_ACL]     = "create",
+       [TOMOYO_TYPE_UNLINK_ACL]     = "unlink",
+       [TOMOYO_TYPE_MKDIR_ACL]      = "mkdir",
+       [TOMOYO_TYPE_RMDIR_ACL]      = "rmdir",
+       [TOMOYO_TYPE_MKFIFO_ACL]     = "mkfifo",
+       [TOMOYO_TYPE_MKSOCK_ACL]     = "mksock",
+       [TOMOYO_TYPE_MKBLOCK_ACL]    = "mkblock",
+       [TOMOYO_TYPE_MKCHAR_ACL]     = "mkchar",
+       [TOMOYO_TYPE_TRUNCATE_ACL]   = "truncate",
+       [TOMOYO_TYPE_SYMLINK_ACL]    = "symlink",
+       [TOMOYO_TYPE_REWRITE_ACL]    = "rewrite",
+};
+
+/* Keyword array for double path operations. */
+static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = {
+       [TOMOYO_TYPE_LINK_ACL]    = "link",
+       [TOMOYO_TYPE_RENAME_ACL]  = "rename",
+};
+
+/**
+ * tomoyo_sp2keyword - Get the name of single path operation.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of single path operation.
+ */
+const char *tomoyo_sp2keyword(const u8 operation)
+{
+       return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION)
+               ? tomoyo_sp_keyword[operation] : NULL;
+}
+
+/**
+ * tomoyo_dp2keyword - Get the name of double path operation.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of double path operation.
+ */
+const char *tomoyo_dp2keyword(const u8 operation)
+{
+       return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION)
+               ? tomoyo_dp_keyword[operation] : NULL;
+}
+
+/**
+ * tomoyo_strendswith - Check whether the token ends with the given token.
+ *
+ * @name: The token to check.
+ * @tail: The token to find.
+ *
+ * Returns true if @name ends with @tail, false otherwise.
+ */
+static bool tomoyo_strendswith(const char *name, const char *tail)
+{
+       int len;
+
+       if (!name || !tail)
+               return false;
+       len = strlen(name) - strlen(tail);
+       return len >= 0 && !strcmp(name + len, tail);
+}
+
+/**
+ * tomoyo_get_path - Get realpath.
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
+{
+       int error;
+       struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf));
+
+       if (!buf)
+               return NULL;
+       /* Reserve one byte for appending "/". */
+       error = tomoyo_realpath_from_path2(path, buf->body,
+                                          sizeof(buf->body) - 2);
+       if (!error) {
+               buf->head.name = buf->body;
+               tomoyo_fill_path_info(&buf->head);
+               return &buf->head;
+       }
+       tomoyo_free(buf);
+       return NULL;
+}
+
+/* Lock for domain->acl_info_list. */
+DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
+
+static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
+                                        const char *filename2,
+                                        struct tomoyo_domain_info *
+                                        const domain, const bool is_delete);
+static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
+                                        struct tomoyo_domain_info *
+                                        const domain, const bool is_delete);
+
+/* The list for "struct tomoyo_globally_readable_file_entry". */
+static LIST_HEAD(tomoyo_globally_readable_list);
+static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
+
+/**
+ * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
+ *
+ * @filename:  Filename unconditionally permitted to open() for reading.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_globally_readable_entry(const char *filename,
+                                                const bool is_delete)
+{
+       struct tomoyo_globally_readable_file_entry *new_entry;
+       struct tomoyo_globally_readable_file_entry *ptr;
+       const struct tomoyo_path_info *saved_filename;
+       int error = -ENOMEM;
+
+       if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
+               return -EINVAL;
+       saved_filename = tomoyo_save_name(filename);
+       if (!saved_filename)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_globally_readable_list_lock);
+       list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+               if (ptr->filename != saved_filename)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->filename = saved_filename;
+       list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_globally_readable_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
+ *
+ * @filename: The filename to check.
+ *
+ * Returns true if any domain can open @filename for reading, false otherwise.
+ */
+static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
+                                            filename)
+{
+       struct tomoyo_globally_readable_file_entry *ptr;
+       bool found = false;
+       down_read(&tomoyo_globally_readable_list_lock);
+       list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+               if (!ptr->is_deleted &&
+                   tomoyo_path_matches_pattern(filename, ptr->filename)) {
+                       found = true;
+                       break;
+               }
+       }
+       up_read(&tomoyo_globally_readable_list_lock);
+       return found;
+}
+
+/**
+ * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
+{
+       return tomoyo_update_globally_readable_entry(data, is_delete);
+}
+
+/**
+ * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_globally_readable_list_lock);
+       list_for_each_cookie(pos, head->read_var2,
+                            &tomoyo_globally_readable_list) {
+               struct tomoyo_globally_readable_file_entry *ptr;
+               ptr = list_entry(pos,
+                                struct tomoyo_globally_readable_file_entry,
+                                list);
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
+                                     ptr->filename->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_globally_readable_list_lock);
+       return done;
+}
+
+/* The list for "struct tomoyo_pattern_entry". */
+static LIST_HEAD(tomoyo_pattern_list);
+static DECLARE_RWSEM(tomoyo_pattern_list_lock);
+
+/**
+ * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
+ *
+ * @pattern:   Pathname pattern.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_file_pattern_entry(const char *pattern,
+                                           const bool is_delete)
+{
+       struct tomoyo_pattern_entry *new_entry;
+       struct tomoyo_pattern_entry *ptr;
+       const struct tomoyo_path_info *saved_pattern;
+       int error = -ENOMEM;
+
+       if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
+               return -EINVAL;
+       saved_pattern = tomoyo_save_name(pattern);
+       if (!saved_pattern)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_pattern_list_lock);
+       list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+               if (saved_pattern != ptr->pattern)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->pattern = saved_pattern;
+       list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_pattern_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_get_file_pattern - Get patterned pathname.
+ *
+ * @filename: The filename to find patterned pathname.
+ *
+ * Returns pointer to pathname pattern if matched, @filename otherwise.
+ */
+static const struct tomoyo_path_info *
+tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+{
+       struct tomoyo_pattern_entry *ptr;
+       const struct tomoyo_path_info *pattern = NULL;
+
+       down_read(&tomoyo_pattern_list_lock);
+       list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
+                       continue;
+               pattern = ptr->pattern;
+               if (tomoyo_strendswith(pattern->name, "/\\*")) {
+                       /* Do nothing. Try to find the better match. */
+               } else {
+                       /* This would be the better match. Use this. */
+                       break;
+               }
+       }
+       up_read(&tomoyo_pattern_list_lock);
+       if (pattern)
+               filename = pattern;
+       return filename;
+}
+
+/**
+ * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_pattern_policy(char *data, const bool is_delete)
+{
+       return tomoyo_update_file_pattern_entry(data, is_delete);
+}
+
+/**
+ * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_pattern_list_lock);
+       list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
+               struct tomoyo_pattern_entry *ptr;
+               ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n",
+                                     ptr->pattern->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_pattern_list_lock);
+       return done;
+}
+
+/* The list for "struct tomoyo_no_rewrite_entry". */
+static LIST_HEAD(tomoyo_no_rewrite_list);
+static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
+
+/**
+ * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
+ *
+ * @pattern:   Pathname pattern that are not rewritable by default.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_no_rewrite_entry(const char *pattern,
+                                         const bool is_delete)
+{
+       struct tomoyo_no_rewrite_entry *new_entry, *ptr;
+       const struct tomoyo_path_info *saved_pattern;
+       int error = -ENOMEM;
+
+       if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
+               return -EINVAL;
+       saved_pattern = tomoyo_save_name(pattern);
+       if (!saved_pattern)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_no_rewrite_list_lock);
+       list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+               if (ptr->pattern != saved_pattern)
+                       continue;
+               ptr->is_deleted = is_delete;
+               error = 0;
+               goto out;
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
+       if (!new_entry)
+               goto out;
+       new_entry->pattern = saved_pattern;
+       list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+       error = 0;
+ out:
+       up_write(&tomoyo_no_rewrite_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
+ *
+ * @filename: Filename to check.
+ *
+ * Returns true if @filename is specified by "deny_rewrite" directive,
+ * false otherwise.
+ */
+static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
+{
+       struct tomoyo_no_rewrite_entry *ptr;
+       bool found = false;
+
+       down_read(&tomoyo_no_rewrite_list_lock);
+       list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
+                       continue;
+               found = true;
+               break;
+       }
+       up_read(&tomoyo_no_rewrite_list_lock);
+       return found;
+}
+
+/**
+ * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
+{
+       return tomoyo_update_no_rewrite_entry(data, is_delete);
+}
+
+/**
+ * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
+{
+       struct list_head *pos;
+       bool done = true;
+
+       down_read(&tomoyo_no_rewrite_list_lock);
+       list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
+               struct tomoyo_no_rewrite_entry *ptr;
+               ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
+               if (ptr->is_deleted)
+                       continue;
+               if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n",
+                                     ptr->pattern->name)) {
+                       done = false;
+                       break;
+               }
+       }
+       up_read(&tomoyo_no_rewrite_list_lock);
+       return done;
+}
+
+/**
+ * tomoyo_update_file_acl - Update file's read/write/execute ACL.
+ *
+ * @filename:  Filename.
+ * @perm:      Permission (between 1 to 7).
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * This is legacy support interface for older policy syntax.
+ * Current policy syntax uses "allow_read/write" instead of "6",
+ * "allow_read" instead of "4", "allow_write" instead of "2",
+ * "allow_execute" instead of "1".
+ */
+static int tomoyo_update_file_acl(const char *filename, u8 perm,
+                                 struct tomoyo_domain_info * const domain,
+                                 const bool is_delete)
+{
+       if (perm > 7 || !perm) {
+               printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
+                      __func__, perm, filename);
+               return -EINVAL;
+       }
+       if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
+               /*
+                * Only 'allow_mkdir' and 'allow_rmdir' are valid for
+                * directory permissions.
+                */
+               return 0;
+       if (perm & 4)
+               tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename,
+                                             domain, is_delete);
+       if (perm & 2)
+               tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename,
+                                             domain, is_delete);
+       if (perm & 1)
+               tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL,
+                                             filename, domain, is_delete);
+       return 0;
+}
+
+/**
+ * tomoyo_check_single_path_acl2 - Check permission for single path operation.
+ *
+ * @domain:          Pointer to "struct tomoyo_domain_info".
+ * @filename:        Filename to check.
+ * @perm:            Permission.
+ * @may_use_pattern: True if patterned ACL is permitted.
+ *
+ * Returns 0 on success, -EPERM otherwise.
+ */
+static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
+                                        domain,
+                                        const struct tomoyo_path_info *
+                                        filename,
+                                        const u16 perm,
+                                        const bool may_use_pattern)
+{
+       struct tomoyo_acl_info *ptr;
+       int error = -EPERM;
+
+       down_read(&tomoyo_domain_acl_info_list_lock);
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_single_path_acl_record *acl;
+               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_single_path_acl_record,
+                                  head);
+               if (!(acl->perm & perm))
+                       continue;
+               if (may_use_pattern || !acl->filename->is_patterned) {
+                       if (!tomoyo_path_matches_pattern(filename,
+                                                        acl->filename))
+                               continue;
+               } else {
+                       continue;
+               }
+               error = 0;
+               break;
+       }
+       up_read(&tomoyo_domain_acl_info_list_lock);
+       return error;
+}
+
+/**
+ * tomoyo_check_file_acl - Check permission for opening files.
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @filename:  Filename to check.
+ * @operation: Mode ("read" or "write" or "read/write" or "execute").
+ *
+ * Returns 0 on success, -EPERM otherwise.
+ */
+static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
+                                const struct tomoyo_path_info *filename,
+                                const u8 operation)
+{
+       u16 perm = 0;
+
+       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
+               return 0;
+       if (operation == 6)
+               perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL;
+       else if (operation == 4)
+               perm = 1 << TOMOYO_TYPE_READ_ACL;
+       else if (operation == 2)
+               perm = 1 << TOMOYO_TYPE_WRITE_ACL;
+       else if (operation == 1)
+               perm = 1 << TOMOYO_TYPE_EXECUTE_ACL;
+       else
+               BUG();
+       return tomoyo_check_single_path_acl2(domain, filename, perm,
+                                            operation != 1);
+}
+
+/**
+ * tomoyo_check_file_perm2 - Check permission for opening files.
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @filename:  Filename to check.
+ * @perm:      Mode ("read" or "write" or "read/write" or "execute").
+ * @operation: Operation name passed used for verbose mode.
+ * @mode:      Access control mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
+                                  const struct tomoyo_path_info *filename,
+                                  const u8 perm, const char *operation,
+                                  const u8 mode)
+{
+       const bool is_enforce = (mode == 3);
+       const char *msg = "<unknown>";
+       int error = 0;
+
+       if (!filename)
+               return 0;
+       error = tomoyo_check_file_acl(domain, filename, perm);
+       if (error && perm == 4 &&
+           (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
+           && tomoyo_is_globally_readable_file(filename))
+               error = 0;
+       if (perm == 6)
+               msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL);
+       else if (perm == 4)
+               msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL);
+       else if (perm == 2)
+               msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL);
+       else if (perm == 1)
+               msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL);
+       else
+               BUG();
+       if (!error)
+               return 0;
+       if (tomoyo_verbose_mode(domain))
+               printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
+                      "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
+                      filename->name, tomoyo_get_last_name(domain));
+       if (is_enforce)
+               return error;
+       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
+               /* Don't use patterns for execute permission. */
+               const struct tomoyo_path_info *patterned_file = (perm != 1) ?
+                       tomoyo_get_file_pattern(filename) : filename;
+               tomoyo_update_file_acl(patterned_file->name, perm,
+                                      domain, false);
+       }
+       return 0;
+}
+
+/**
+ * tomoyo_write_file_policy - Update file related list.
+ *
+ * @data:      String to parse.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
+                            const bool is_delete)
+{
+       char *filename = strchr(data, ' ');
+       char *filename2;
+       unsigned int perm;
+       u8 type;
+
+       if (!filename)
+               return -EINVAL;
+       *filename++ = '\0';
+       if (sscanf(data, "%u", &perm) == 1)
+               return tomoyo_update_file_acl(filename, (u8) perm, domain,
+                                             is_delete);
+       if (strncmp(data, "allow_", 6))
+               goto out;
+       data += 6;
+       for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) {
+               if (strcmp(data, tomoyo_sp_keyword[type]))
+                       continue;
+               return tomoyo_update_single_path_acl(type, filename,
+                                                    domain, is_delete);
+       }
+       filename2 = strchr(filename, ' ');
+       if (!filename2)
+               goto out;
+       *filename2++ = '\0';
+       for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) {
+               if (strcmp(data, tomoyo_dp_keyword[type]))
+                       continue;
+               return tomoyo_update_double_path_acl(type, filename, filename2,
+                                                    domain, is_delete);
+       }
+ out:
+       return -EINVAL;
+}
+
+/**
+ * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list.
+ *
+ * @type:      Type of operation.
+ * @filename:  Filename.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
+                                        struct tomoyo_domain_info *
+                                        const domain, const bool is_delete)
+{
+       static const u16 rw_mask =
+               (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
+       const struct tomoyo_path_info *saved_filename;
+       struct tomoyo_acl_info *ptr;
+       struct tomoyo_single_path_acl_record *acl;
+       int error = -ENOMEM;
+       const u16 perm = 1 << type;
+
+       if (!domain)
+               return -EINVAL;
+       if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
+               return -EINVAL;
+       saved_filename = tomoyo_save_name(filename);
+       if (!saved_filename)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_acl_info_list_lock);
+       if (is_delete)
+               goto delete;
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_single_path_acl_record,
+                                  head);
+               if (acl->filename != saved_filename)
+                       continue;
+               /* Special case. Clear all bits if marked as deleted. */
+               if (ptr->type & TOMOYO_ACL_DELETED)
+                       acl->perm = 0;
+               acl->perm |= perm;
+               if ((acl->perm & rw_mask) == rw_mask)
+                       acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL;
+               else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+                       acl->perm |= rw_mask;
+               ptr->type &= ~TOMOYO_ACL_DELETED;
+               error = 0;
+               goto out;
+       }
+       /* Not found. Append it to the tail. */
+       acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
+       if (!acl)
+               goto out;
+       acl->perm = perm;
+       if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+               acl->perm |= rw_mask;
+       acl->filename = saved_filename;
+       list_add_tail(&acl->head.list, &domain->acl_info_list);
+       error = 0;
+       goto out;
+ delete:
+       error = -ENOENT;
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_single_path_acl_record,
+                                  head);
+               if (acl->filename != saved_filename)
+                       continue;
+               acl->perm &= ~perm;
+               if ((acl->perm & rw_mask) != rw_mask)
+                       acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL);
+               else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
+                       acl->perm &= ~rw_mask;
+               if (!acl->perm)
+                       ptr->type |= TOMOYO_ACL_DELETED;
+               error = 0;
+               break;
+       }
+ out:
+       up_write(&tomoyo_domain_acl_info_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list.
+ *
+ * @type:      Type of operation.
+ * @filename1: First filename.
+ * @filename2: Second filename.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
+                                        const char *filename2,
+                                        struct tomoyo_domain_info *
+                                        const domain, const bool is_delete)
+{
+       const struct tomoyo_path_info *saved_filename1;
+       const struct tomoyo_path_info *saved_filename2;
+       struct tomoyo_acl_info *ptr;
+       struct tomoyo_double_path_acl_record *acl;
+       int error = -ENOMEM;
+       const u8 perm = 1 << type;
+
+       if (!domain)
+               return -EINVAL;
+       if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
+           !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
+               return -EINVAL;
+       saved_filename1 = tomoyo_save_name(filename1);
+       saved_filename2 = tomoyo_save_name(filename2);
+       if (!saved_filename1 || !saved_filename2)
+               return -ENOMEM;
+       /***** EXCLUSIVE SECTION START *****/
+       down_write(&tomoyo_domain_acl_info_list_lock);
+       if (is_delete)
+               goto delete;
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_double_path_acl_record,
+                                  head);
+               if (acl->filename1 != saved_filename1 ||
+                   acl->filename2 != saved_filename2)
+                       continue;
+               /* Special case. Clear all bits if marked as deleted. */
+               if (ptr->type & TOMOYO_ACL_DELETED)
+                       acl->perm = 0;
+               acl->perm |= perm;
+               ptr->type &= ~TOMOYO_ACL_DELETED;
+               error = 0;
+               goto out;
+       }
+       /* Not found. Append it to the tail. */
+       acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
+       if (!acl)
+               goto out;
+       acl->perm = perm;
+       acl->filename1 = saved_filename1;
+       acl->filename2 = saved_filename2;
+       list_add_tail(&acl->head.list, &domain->acl_info_list);
+       error = 0;
+       goto out;
+ delete:
+       error = -ENOENT;
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_double_path_acl_record,
+                                  head);
+               if (acl->filename1 != saved_filename1 ||
+                   acl->filename2 != saved_filename2)
+                       continue;
+               acl->perm &= ~perm;
+               if (!acl->perm)
+                       ptr->type |= TOMOYO_ACL_DELETED;
+               error = 0;
+               break;
+       }
+ out:
+       up_write(&tomoyo_domain_acl_info_list_lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return error;
+}
+
+/**
+ * tomoyo_check_single_path_acl - Check permission for single path operation.
+ *
+ * @domain:   Pointer to "struct tomoyo_domain_info".
+ * @type:     Type of operation.
+ * @filename: Filename to check.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
+                                       const u8 type,
+                                       const struct tomoyo_path_info *filename)
+{
+       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
+               return 0;
+       return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1);
+}
+
+/**
+ * tomoyo_check_double_path_acl - Check permission for double path operation.
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @type:      Type of operation.
+ * @filename1: First filename to check.
+ * @filename2: Second filename to check.
+ *
+ * Returns 0 on success, -EPERM otherwise.
+ */
+static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
+                                       const u8 type,
+                                       const struct tomoyo_path_info *
+                                       filename1,
+                                       const struct tomoyo_path_info *
+                                       filename2)
+{
+       struct tomoyo_acl_info *ptr;
+       const u8 perm = 1 << type;
+       int error = -EPERM;
+
+       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
+               return 0;
+       down_read(&tomoyo_domain_acl_info_list_lock);
+       list_for_each_entry(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_double_path_acl_record *acl;
+               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
+                       continue;
+               acl = container_of(ptr, struct tomoyo_double_path_acl_record,
+                                  head);
+               if (!(acl->perm & perm))
+                       continue;
+               if (!tomoyo_path_matches_pattern(filename1, acl->filename1))
+                       continue;
+               if (!tomoyo_path_matches_pattern(filename2, acl->filename2))
+                       continue;
+               error = 0;
+               break;
+       }
+       up_read(&tomoyo_domain_acl_info_list_lock);
+       return error;
+}
+
+/**
+ * tomoyo_check_single_path_permission2 - Check permission for single path operation.
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @operation: Type of operation.
+ * @filename:  Filename to check.
+ * @mode:      Access control mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
+                                               const domain, u8 operation,
+                                               const struct tomoyo_path_info *
+                                               filename, const u8 mode)
+{
+       const char *msg;
+       int error;
+       const bool is_enforce = (mode == 3);
+
+       if (!mode)
+               return 0;
+ next:
+       error = tomoyo_check_single_path_acl(domain, operation, filename);
+       msg = tomoyo_sp2keyword(operation);
+       if (!error)
+               goto ok;
+       if (tomoyo_verbose_mode(domain))
+               printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
+                      tomoyo_get_msg(is_enforce), msg, filename->name,
+                      tomoyo_get_last_name(domain));
+       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
+               const char *name = tomoyo_get_file_pattern(filename)->name;
+               tomoyo_update_single_path_acl(operation, name, domain, false);
+       }
+       if (!is_enforce)
+               error = 0;
+ ok:
+       /*
+        * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
+        * we need to check "allow_rewrite" permission if the filename is
+        * specified by "deny_rewrite" keyword.
+        */
+       if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL &&
+           tomoyo_is_no_rewrite_file(filename)) {
+               operation = TOMOYO_TYPE_REWRITE_ACL;
+               goto next;
+       }
+       return error;
+}
+
+/**
+ * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write".
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @filename:  Filename to check.
+ * @perm:      Mode ("read" or "write" or "read/write").
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
+                          const char *filename, const u8 perm)
+{
+       struct tomoyo_path_info name;
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+
+       if (!mode)
+               return 0;
+       name.name = filename;
+       tomoyo_fill_path_info(&name);
+       return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode);
+}
+
+/**
+ * tomoyo_check_exec_perm - Check permission for "execute".
+ *
+ * @domain:   Pointer to "struct tomoyo_domain_info".
+ * @filename: Check permission for "execute".
+ * @tmp:      Buffer for temporary use.
+ *
+ * Returns 0 on success, negativevalue otherwise.
+ */
+int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+                          const struct tomoyo_path_info *filename,
+                          struct tomoyo_page_buffer *tmp)
+{
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+
+       if (!mode)
+               return 0;
+       return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
+}
+
+/**
+ * tomoyo_check_open_permission - Check permission for "read" and "write".
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @path:   Pointer to "struct path".
+ * @flag:   Flags for open().
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
+                                struct path *path, const int flag)
+{
+       const u8 acc_mode = ACC_MODE(flag);
+       int error = -ENOMEM;
+       struct tomoyo_path_info *buf;
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       const bool is_enforce = (mode == 3);
+
+       if (!mode || !path->mnt)
+               return 0;
+       if (acc_mode == 0)
+               return 0;
+       if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
+               /*
+                * I don't check directories here because mkdir() and rmdir()
+                * don't call me.
+                */
+               return 0;
+       buf = tomoyo_get_path(path);
+       if (!buf)
+               goto out;
+       error = 0;
+       /*
+        * If the filename is specified by "deny_rewrite" keyword,
+        * we need to check "allow_rewrite" permission when the filename is not
+        * opened for append mode or the filename is truncated at open time.
+        */
+       if ((acc_mode & MAY_WRITE) &&
+           ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
+           (tomoyo_is_no_rewrite_file(buf))) {
+               error = tomoyo_check_single_path_permission2(domain,
+                                                    TOMOYO_TYPE_REWRITE_ACL,
+                                                            buf, mode);
+       }
+       if (!error)
+               error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
+                                               mode);
+       if (!error && (flag & O_TRUNC))
+               error = tomoyo_check_single_path_permission2(domain,
+                                                    TOMOYO_TYPE_TRUNCATE_ACL,
+                                                            buf, mode);
+ out:
+       tomoyo_free(buf);
+       if (!is_enforce)
+               error = 0;
+       return error;
+}
+
+/**
+ * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink".
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @operation: Type of operation.
+ * @path:      Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
+                           const u8 operation, struct path *path)
+{
+       int error = -ENOMEM;
+       struct tomoyo_path_info *buf;
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       const bool is_enforce = (mode == 3);
+
+       if (!mode || !path->mnt)
+               return 0;
+       buf = tomoyo_get_path(path);
+       if (!buf)
+               goto out;
+       switch (operation) {
+       case TOMOYO_TYPE_MKDIR_ACL:
+       case TOMOYO_TYPE_RMDIR_ACL:
+               if (!buf->is_dir) {
+                       /*
+                        * tomoyo_get_path() reserves space for appending "/."
+                        */
+                       strcat((char *) buf->name, "/");
+                       tomoyo_fill_path_info(buf);
+               }
+       }
+       error = tomoyo_check_single_path_permission2(domain, operation, buf,
+                                                    mode);
+ out:
+       tomoyo_free(buf);
+       if (!is_enforce)
+               error = 0;
+       return error;
+}
+
+/**
+ * tomoyo_check_rewrite_permission - Check permission for "rewrite".
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @filp: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
+                                   struct file *filp)
+{
+       int error = -ENOMEM;
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       const bool is_enforce = (mode == 3);
+       struct tomoyo_path_info *buf;
+
+       if (!mode || !filp->f_path.mnt)
+               return 0;
+       buf = tomoyo_get_path(&filp->f_path);
+       if (!buf)
+               goto out;
+       if (!tomoyo_is_no_rewrite_file(buf)) {
+               error = 0;
+               goto out;
+       }
+       error = tomoyo_check_single_path_permission2(domain,
+                                                    TOMOYO_TYPE_REWRITE_ACL,
+                                                    buf, mode);
+ out:
+       tomoyo_free(buf);
+       if (!is_enforce)
+               error = 0;
+       return error;
+}
+
+/**
+ * tomoyo_check_2path_perm - Check permission for "rename" and "link".
+ *
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @operation: Type of operation.
+ * @path1:      Pointer to "struct path".
+ * @path2:      Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
+                           const u8 operation, struct path *path1,
+                           struct path *path2)
+{
+       int error = -ENOMEM;
+       struct tomoyo_path_info *buf1, *buf2;
+       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       const bool is_enforce = (mode == 3);
+       const char *msg;
+
+       if (!mode || !path1->mnt || !path2->mnt)
+               return 0;
+       buf1 = tomoyo_get_path(path1);
+       buf2 = tomoyo_get_path(path2);
+       if (!buf1 || !buf2)
+               goto out;
+       {
+               struct dentry *dentry = path1->dentry;
+               if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
+                       /*
+                        * tomoyo_get_path() reserves space for appending "/."
+                        */
+                       if (!buf1->is_dir) {
+                               strcat((char *) buf1->name, "/");
+                               tomoyo_fill_path_info(buf1);
+                       }
+                       if (!buf2->is_dir) {
+                               strcat((char *) buf2->name, "/");
+                               tomoyo_fill_path_info(buf2);
+                       }
+               }
+       }
+       error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2);
+       msg = tomoyo_dp2keyword(operation);
+       if (!error)
+               goto out;
+       if (tomoyo_verbose_mode(domain))
+               printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
+                      "denied for %s\n", tomoyo_get_msg(is_enforce),
+                      msg, buf1->name, buf2->name,
+                      tomoyo_get_last_name(domain));
+       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
+               const char *name1 = tomoyo_get_file_pattern(buf1)->name;
+               const char *name2 = tomoyo_get_file_pattern(buf2)->name;
+               tomoyo_update_double_path_acl(operation, name1, name2, domain,
+                                             false);
+       }
+ out:
+       tomoyo_free(buf1);
+       tomoyo_free(buf2);
+       if (!is_enforce)
+               error = 0;
+       return error;
+}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
new file mode 100644 (file)
index 0000000..d47f16b
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Get the canonicalized absolute pathnames. The basis for TOMOYO.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mount.h>
+#include <linux/mnt_namespace.h>
+#include "common.h"
+#include "realpath.h"
+
+/**
+ * tomoyo_encode: Convert binary string to ascii string.
+ *
+ * @buffer:  Buffer for ASCII string.
+ * @buflen:  Size of @buffer.
+ * @str:     Binary string.
+ *
+ * Returns 0 on success, -ENOMEM otherwise.
+ */
+int tomoyo_encode(char *buffer, int buflen, const char *str)
+{
+       while (1) {
+               const unsigned char c = *(unsigned char *) str++;
+
+               if (tomoyo_is_valid(c)) {
+                       if (--buflen <= 0)
+                               break;
+                       *buffer++ = (char) c;
+                       if (c != '\\')
+                               continue;
+                       if (--buflen <= 0)
+                               break;
+                       *buffer++ = (char) c;
+                       continue;
+               }
+               if (!c) {
+                       if (--buflen <= 0)
+                               break;
+                       *buffer = '\0';
+                       return 0;
+               }
+               buflen -= 4;
+               if (buflen <= 0)
+                       break;
+               *buffer++ = '\\';
+               *buffer++ = (c >> 6) + '0';
+               *buffer++ = ((c >> 3) & 7) + '0';
+               *buffer++ = (c & 7) + '0';
+       }
+       return -ENOMEM;
+}
+
+/**
+ * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
+ *
+ * @path:        Pointer to "struct path".
+ * @newname:     Pointer to buffer to return value in.
+ * @newname_len: Size of @newname.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ * Characters out of 0x20 < c < 0x7F range are converted to
+ * \ooo style octal string.
+ * Character \ is converted to \\ string.
+ */
+int tomoyo_realpath_from_path2(struct path *path, char *newname,
+                              int newname_len)
+{
+       int error = -ENOMEM;
+       struct dentry *dentry = path->dentry;
+       char *sp;
+
+       if (!dentry || !path->mnt || !newname || newname_len <= 2048)
+               return -EINVAL;
+       if (dentry->d_op && dentry->d_op->d_dname) {
+               /* For "socket:[\$]" and "pipe:[\$]". */
+               static const int offset = 1536;
+               sp = dentry->d_op->d_dname(dentry, newname + offset,
+                                          newname_len - offset);
+       } else {
+               /* Taken from d_namespace_path(). */
+               struct path root;
+               struct path ns_root = { };
+               struct path tmp;
+
+               read_lock(&current->fs->lock);
+               root = current->fs->root;
+               path_get(&root);
+               read_unlock(&current->fs->lock);
+               spin_lock(&vfsmount_lock);
+               if (root.mnt && root.mnt->mnt_ns)
+                       ns_root.mnt = mntget(root.mnt->mnt_ns->root);
+               if (ns_root.mnt)
+                       ns_root.dentry = dget(ns_root.mnt->mnt_root);
+               spin_unlock(&vfsmount_lock);
+               spin_lock(&dcache_lock);
+               tmp = ns_root;
+               sp = __d_path(path, &tmp, newname, newname_len);
+               spin_unlock(&dcache_lock);
+               path_put(&root);
+               path_put(&ns_root);
+       }
+       if (IS_ERR(sp))
+               error = PTR_ERR(sp);
+       else
+               error = tomoyo_encode(newname, sp - newname, sp);
+       /* Append trailing '/' if dentry is a directory. */
+       if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
+           && *newname) {
+               sp = newname + strlen(newname);
+               if (*(sp - 1) != '/') {
+                       if (sp < newname + newname_len - 4) {
+                               *sp++ = '/';
+                               *sp = '\0';
+                       } else {
+                               error = -ENOMEM;
+                       }
+               }
+       }
+       if (error)
+               printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
+       return error;
+}
+
+/**
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns the realpath of the given @path on success, NULL otherwise.
+ *
+ * These functions use tomoyo_alloc(), so the caller must call tomoyo_free()
+ * if these functions didn't return NULL.
+ */
+char *tomoyo_realpath_from_path(struct path *path)
+{
+       char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer));
+
+       BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
+                    <= TOMOYO_MAX_PATHNAME_LEN - 1);
+       if (!buf)
+               return NULL;
+       if (tomoyo_realpath_from_path2(path, buf,
+                                      TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
+               return buf;
+       tomoyo_free(buf);
+       return NULL;
+}
+
+/**
+ * tomoyo_realpath - Get realpath of a pathname.
+ *
+ * @pathname: The pathname to solve.
+ *
+ * Returns the realpath of @pathname on success, NULL otherwise.
+ */
+char *tomoyo_realpath(const char *pathname)
+{
+       struct nameidata nd;
+
+       if (pathname && path_lookup(pathname, LOOKUP_FOLLOW, &nd) == 0) {
+               char *buf = tomoyo_realpath_from_path(&nd.path);
+               path_put(&nd.path);
+               return buf;
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_realpath_nofollow - Get realpath of a pathname.
+ *
+ * @pathname: The pathname to solve.
+ *
+ * Returns the realpath of @pathname on success, NULL otherwise.
+ */
+char *tomoyo_realpath_nofollow(const char *pathname)
+{
+       struct nameidata nd;
+
+       if (pathname && path_lookup(pathname, 0, &nd) == 0) {
+               char *buf = tomoyo_realpath_from_path(&nd.path);
+               path_put(&nd.path);
+               return buf;
+       }
+       return NULL;
+}
+
+/* Memory allocated for non-string data. */
+static unsigned int tomoyo_allocated_memory_for_elements;
+/* Quota for holding non-string data. */
+static unsigned int tomoyo_quota_for_elements;
+
+/**
+ * tomoyo_alloc_element - Allocate permanent memory for structures.
+ *
+ * @size: Size in bytes.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ *
+ * Memory has to be zeroed.
+ * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ */
+void *tomoyo_alloc_element(const unsigned int size)
+{
+       static char *buf;
+       static DEFINE_MUTEX(lock);
+       static unsigned int buf_used_len = PATH_MAX;
+       char *ptr = NULL;
+       /*Assumes sizeof(void *) >= sizeof(long) is true. */
+       const unsigned int word_aligned_size
+               = roundup(size, max(sizeof(void *), sizeof(long)));
+       if (word_aligned_size > PATH_MAX)
+               return NULL;
+       /***** EXCLUSIVE SECTION START *****/
+       mutex_lock(&lock);
+       if (buf_used_len + word_aligned_size > PATH_MAX) {
+               if (!tomoyo_quota_for_elements ||
+                   tomoyo_allocated_memory_for_elements
+                   + PATH_MAX <= tomoyo_quota_for_elements)
+                       ptr = kzalloc(PATH_MAX, GFP_KERNEL);
+               if (!ptr) {
+                       printk(KERN_WARNING "ERROR: Out of memory "
+                              "for tomoyo_alloc_element().\n");
+                       if (!tomoyo_policy_loaded)
+                               panic("MAC Initialization failed.\n");
+               } else {
+                       buf = ptr;
+                       tomoyo_allocated_memory_for_elements += PATH_MAX;
+                       buf_used_len = word_aligned_size;
+                       ptr = buf;
+               }
+       } else if (word_aligned_size) {
+               int i;
+               ptr = buf + buf_used_len;
+               buf_used_len += word_aligned_size;
+               for (i = 0; i < word_aligned_size; i++) {
+                       if (!ptr[i])
+                               continue;
+                       printk(KERN_ERR "WARNING: Reserved memory was tainted! "
+                              "The system might go wrong.\n");
+                       ptr[i] = '\0';
+               }
+       }
+       mutex_unlock(&lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return ptr;
+}
+
+/* Memory allocated for string data in bytes. */
+static unsigned int tomoyo_allocated_memory_for_savename;
+/* Quota for holding string data in bytes. */
+static unsigned int tomoyo_quota_for_savename;
+
+/*
+ * TOMOYO uses this hash only when appending a string into the string
+ * table. Frequency of appending strings is very low. So we don't need
+ * large (e.g. 64k) hash size. 256 will be sufficient.
+ */
+#define TOMOYO_MAX_HASH 256
+
+/* Structure for string data. */
+struct tomoyo_name_entry {
+       struct list_head list;
+       struct tomoyo_path_info entry;
+};
+
+/* Structure for available memory region. */
+struct tomoyo_free_memory_block_list {
+       struct list_head list;
+       char *ptr;             /* Pointer to a free area. */
+       int len;               /* Length of the area.     */
+};
+
+/*
+ * The list for "struct tomoyo_name_entry".
+ *
+ * This list is updated only inside tomoyo_save_name(), thus
+ * no global mutex exists.
+ */
+static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_save_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ *
+ * The RAM is shared, so NEVER try to modify or kfree() the returned name.
+ */
+const struct tomoyo_path_info *tomoyo_save_name(const char *name)
+{
+       static LIST_HEAD(fmb_list);
+       static DEFINE_MUTEX(lock);
+       struct tomoyo_name_entry *ptr;
+       unsigned int hash;
+       /* fmb contains available size in bytes.
+          fmb is removed from the fmb_list when fmb->len becomes 0. */
+       struct tomoyo_free_memory_block_list *fmb;
+       int len;
+       char *cp;
+
+       if (!name)
+               return NULL;
+       len = strlen(name) + 1;
+       if (len > TOMOYO_MAX_PATHNAME_LEN) {
+               printk(KERN_WARNING "ERROR: Name too long "
+                      "for tomoyo_save_name().\n");
+               return NULL;
+       }
+       hash = full_name_hash((const unsigned char *) name, len - 1);
+       /***** EXCLUSIVE SECTION START *****/
+       mutex_lock(&lock);
+       list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
+                            list) {
+               if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
+                       goto out;
+       }
+       list_for_each_entry(fmb, &fmb_list, list) {
+               if (len <= fmb->len)
+                       goto ready;
+       }
+       if (!tomoyo_quota_for_savename ||
+           tomoyo_allocated_memory_for_savename + PATH_MAX
+           <= tomoyo_quota_for_savename)
+               cp = kzalloc(PATH_MAX, GFP_KERNEL);
+       else
+               cp = NULL;
+       fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
+       if (!cp || !fmb) {
+               kfree(cp);
+               kfree(fmb);
+               printk(KERN_WARNING "ERROR: Out of memory "
+                      "for tomoyo_save_name().\n");
+               if (!tomoyo_policy_loaded)
+                       panic("MAC Initialization failed.\n");
+               ptr = NULL;
+               goto out;
+       }
+       tomoyo_allocated_memory_for_savename += PATH_MAX;
+       list_add(&fmb->list, &fmb_list);
+       fmb->ptr = cp;
+       fmb->len = PATH_MAX;
+ ready:
+       ptr = tomoyo_alloc_element(sizeof(*ptr));
+       if (!ptr)
+               goto out;
+       ptr->entry.name = fmb->ptr;
+       memmove(fmb->ptr, name, len);
+       tomoyo_fill_path_info(&ptr->entry);
+       fmb->ptr += len;
+       fmb->len -= len;
+       list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
+       if (fmb->len == 0) {
+               list_del(&fmb->list);
+               kfree(fmb);
+       }
+ out:
+       mutex_unlock(&lock);
+       /***** EXCLUSIVE SECTION END *****/
+       return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_realpath_init - Initialize realpath related code.
+ */
+void __init tomoyo_realpath_init(void)
+{
+       int i;
+
+       BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
+       for (i = 0; i < TOMOYO_MAX_HASH; i++)
+               INIT_LIST_HEAD(&tomoyo_name_list[i]);
+       INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+       tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
+       list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+       down_read(&tomoyo_domain_list_lock);
+       if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+               panic("Can't register tomoyo_kernel_domain");
+       up_read(&tomoyo_domain_list_lock);
+}
+
+/* Memory allocated for temporary purpose. */
+static atomic_t tomoyo_dynamic_memory_size;
+
+/**
+ * tomoyo_alloc - Allocate memory for temporary purpose.
+ *
+ * @size: Size in bytes.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ */
+void *tomoyo_alloc(const size_t size)
+{
+       void *p = kzalloc(size, GFP_KERNEL);
+       if (p)
+               atomic_add(ksize(p), &tomoyo_dynamic_memory_size);
+       return p;
+}
+
+/**
+ * tomoyo_free - Release memory allocated by tomoyo_alloc().
+ *
+ * @p: Pointer returned by tomoyo_alloc(). May be NULL.
+ *
+ * Returns nothing.
+ */
+void tomoyo_free(const void *p)
+{
+       if (p) {
+               atomic_sub(ksize(p), &tomoyo_dynamic_memory_size);
+               kfree(p);
+       }
+}
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage in bytes.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns memory usage.
+ */
+int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+       if (!head->read_eof) {
+               const unsigned int shared
+                       = tomoyo_allocated_memory_for_savename;
+               const unsigned int private
+                       = tomoyo_allocated_memory_for_elements;
+               const unsigned int dynamic
+                       = atomic_read(&tomoyo_dynamic_memory_size);
+               char buffer[64];
+
+               memset(buffer, 0, sizeof(buffer));
+               if (tomoyo_quota_for_savename)
+                       snprintf(buffer, sizeof(buffer) - 1,
+                                "   (Quota: %10u)",
+                                tomoyo_quota_for_savename);
+               else
+                       buffer[0] = '\0';
+               tomoyo_io_printf(head, "Shared:  %10u%s\n", shared, buffer);
+               if (tomoyo_quota_for_elements)
+                       snprintf(buffer, sizeof(buffer) - 1,
+                                "   (Quota: %10u)",
+                                tomoyo_quota_for_elements);
+               else
+                       buffer[0] = '\0';
+               tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer);
+               tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic);
+               tomoyo_io_printf(head, "Total:   %10u\n",
+                                shared + private + dynamic);
+               head->read_eof = true;
+       }
+       return 0;
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       unsigned int size;
+
+       if (sscanf(data, "Shared: %u", &size) == 1)
+               tomoyo_quota_for_savename = size;
+       else if (sscanf(data, "Private: %u", &size) == 1)
+               tomoyo_quota_for_elements = size;
+       return 0;
+}
diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h
new file mode 100644 (file)
index 0000000..7ec9fc9
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * security/tomoyo/realpath.h
+ *
+ * Get the canonicalized absolute pathnames. The basis for TOMOYO.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#ifndef _SECURITY_TOMOYO_REALPATH_H
+#define _SECURITY_TOMOYO_REALPATH_H
+
+struct path;
+struct tomoyo_path_info;
+struct tomoyo_io_buffer;
+
+/* Convert binary string to ascii string. */
+int tomoyo_encode(char *buffer, int buflen, const char *str);
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+int tomoyo_realpath_from_path2(struct path *path, char *newname,
+                              int newname_len);
+
+/*
+ * Returns realpath(3) of the given pathname but ignores chroot'ed root.
+ * These functions use tomoyo_alloc(), so the caller must call tomoyo_free()
+ * if these functions didn't return NULL.
+ */
+char *tomoyo_realpath(const char *pathname);
+/*
+ * Same with tomoyo_realpath() except that it doesn't follow the final symlink.
+ */
+char *tomoyo_realpath_nofollow(const char *pathname);
+/* Same with tomoyo_realpath() except that the pathname is already solved. */
+char *tomoyo_realpath_from_path(struct path *path);
+
+/*
+ * Allocate memory for ACL entry.
+ * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ */
+void *tomoyo_alloc_element(const unsigned int size);
+
+/*
+ * Keep the given name on the RAM.
+ * The RAM is shared, so NEVER try to modify or kfree() the returned name.
+ */
+const struct tomoyo_path_info *tomoyo_save_name(const char *name);
+
+/* Allocate memory for temporary use (e.g. permission checks). */
+void *tomoyo_alloc(const size_t size);
+
+/* Free memory allocated by tomoyo_alloc(). */
+void tomoyo_free(const void *p);
+
+/* Check for memory usage. */
+int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
+
+/* Set memory quota. */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
+
+/* Initialize realpath related code. */
+void __init tomoyo_realpath_init(void);
+
+#endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
new file mode 100644 (file)
index 0000000..3eeeae1
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#include <linux/security.h>
+#include "common.h"
+#include "tomoyo.h"
+#include "realpath.h"
+
+static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
+                              gfp_t gfp)
+{
+       /*
+        * Since "struct tomoyo_domain_info *" is a sharable pointer,
+        * we don't need to duplicate.
+        */
+       new->security = old->security;
+       return 0;
+}
+
+static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
+{
+       /*
+        * Do only if this function is called for the first time of an execve
+        * operation.
+        */
+       if (bprm->cred_prepared)
+               return 0;
+       /*
+        * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
+        * for the first time.
+        */
+       if (!tomoyo_policy_loaded)
+               tomoyo_load_policy(bprm->filename);
+       /*
+        * Tell tomoyo_bprm_check_security() is called for the first time of an
+        * execve operation.
+        */
+       bprm->cred->security = NULL;
+       return 0;
+}
+
+static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
+{
+       struct tomoyo_domain_info *domain = bprm->cred->security;
+
+       /*
+        * Execute permission is checked against pathname passed to do_execve()
+        * using current domain.
+        */
+       if (!domain) {
+               struct tomoyo_domain_info *next_domain = NULL;
+               int retval = tomoyo_find_next_domain(bprm, &next_domain);
+
+               if (!retval)
+                       bprm->cred->security = next_domain;
+               return retval;
+       }
+       /*
+        * Read permission is checked against interpreters using next domain.
+        * '1' is the result of open_to_namei_flags(O_RDONLY).
+        */
+       return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1);
+}
+
+#ifdef CONFIG_SYSCTL
+
+static int tomoyo_prepend(char **buffer, int *buflen, const char *str)
+{
+       int namelen = strlen(str);
+
+       if (*buflen < namelen)
+               return -ENOMEM;
+       *buflen -= namelen;
+       *buffer -= namelen;
+       memcpy(*buffer, str, namelen);
+       return 0;
+}
+
+/**
+ * tomoyo_sysctl_path - return the realpath of a ctl_table.
+ * @table: pointer to "struct ctl_table".
+ *
+ * Returns realpath(3) of the @table on success.
+ * Returns NULL on failure.
+ *
+ * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
+ * if this function didn't return NULL.
+ */
+static char *tomoyo_sysctl_path(struct ctl_table *table)
+{
+       int buflen = TOMOYO_MAX_PATHNAME_LEN;
+       char *buf = tomoyo_alloc(buflen);
+       char *end = buf + buflen;
+       int error = -ENOMEM;
+
+       if (!buf)
+               return NULL;
+
+       *--end = '\0';
+       buflen--;
+       while (table) {
+               char num[32];
+               const char *sp = table->procname;
+
+               if (!sp) {
+                       memset(num, 0, sizeof(num));
+                       snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name);
+                       sp = num;
+               }
+               if (tomoyo_prepend(&end, &buflen, sp) ||
+                   tomoyo_prepend(&end, &buflen, "/"))
+                       goto out;
+               table = table->parent;
+       }
+       if (tomoyo_prepend(&end, &buflen, "/proc/sys"))
+               goto out;
+       error = tomoyo_encode(buf, end - buf, end);
+ out:
+       if (!error)
+               return buf;
+       tomoyo_free(buf);
+       return NULL;
+}
+
+static int tomoyo_sysctl(struct ctl_table *table, int op)
+{
+       int error;
+       char *name;
+
+       op &= MAY_READ | MAY_WRITE;
+       if (!op)
+               return 0;
+       name = tomoyo_sysctl_path(table);
+       if (!name)
+               return -ENOMEM;
+       error = tomoyo_check_file_perm(tomoyo_domain(), name, op);
+       tomoyo_free(name);
+       return error;
+}
+#endif
+
+static int tomoyo_path_truncate(struct path *path, loff_t length,
+                               unsigned int time_attrs)
+{
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_TRUNCATE_ACL,
+                                      path);
+}
+
+static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
+{
+       struct path path = { parent->mnt, dentry };
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_UNLINK_ACL,
+                                      &path);
+}
+
+static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
+                            int mode)
+{
+       struct path path = { parent->mnt, dentry };
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_MKDIR_ACL,
+                                      &path);
+}
+
+static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
+{
+       struct path path = { parent->mnt, dentry };
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_RMDIR_ACL,
+                                      &path);
+}
+
+static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
+                              const char *old_name)
+{
+       struct path path = { parent->mnt, dentry };
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_SYMLINK_ACL,
+                                      &path);
+}
+
+static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
+                            int mode, unsigned int dev)
+{
+       struct path path = { parent->mnt, dentry };
+       int type = TOMOYO_TYPE_CREATE_ACL;
+
+       switch (mode & S_IFMT) {
+       case S_IFCHR:
+               type = TOMOYO_TYPE_MKCHAR_ACL;
+               break;
+       case S_IFBLK:
+               type = TOMOYO_TYPE_MKBLOCK_ACL;
+               break;
+       case S_IFIFO:
+               type = TOMOYO_TYPE_MKFIFO_ACL;
+               break;
+       case S_IFSOCK:
+               type = TOMOYO_TYPE_MKSOCK_ACL;
+               break;
+       }
+       return tomoyo_check_1path_perm(tomoyo_domain(),
+                                      type, &path);
+}
+
+static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
+                           struct dentry *new_dentry)
+{
+       struct path path1 = { new_dir->mnt, old_dentry };
+       struct path path2 = { new_dir->mnt, new_dentry };
+       return tomoyo_check_2path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_LINK_ACL,
+                                      &path1, &path2);
+}
+
+static int tomoyo_path_rename(struct path *old_parent,
+                             struct dentry *old_dentry,
+                             struct path *new_parent,
+                             struct dentry *new_dentry)
+{
+       struct path path1 = { old_parent->mnt, old_dentry };
+       struct path path2 = { new_parent->mnt, new_dentry };
+       return tomoyo_check_2path_perm(tomoyo_domain(),
+                                      TOMOYO_TYPE_RENAME_ACL,
+                                      &path1, &path2);
+}
+
+static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
+               return tomoyo_check_rewrite_permission(tomoyo_domain(), file);
+       return 0;
+}
+
+static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
+{
+       int flags = f->f_flags;
+
+       if ((flags + 1) & O_ACCMODE)
+               flags++;
+       flags |= f->f_flags & (O_APPEND | O_TRUNC);
+       /* Don't check read permission here if called from do_execve(). */
+       if (current->in_execve)
+               return 0;
+       return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
+}
+
+static struct security_operations tomoyo_security_ops = {
+       .name                = "tomoyo",
+       .cred_prepare        = tomoyo_cred_prepare,
+       .bprm_set_creds      = tomoyo_bprm_set_creds,
+       .bprm_check_security = tomoyo_bprm_check_security,
+#ifdef CONFIG_SYSCTL
+       .sysctl              = tomoyo_sysctl,
+#endif
+       .file_fcntl          = tomoyo_file_fcntl,
+       .dentry_open         = tomoyo_dentry_open,
+       .path_truncate       = tomoyo_path_truncate,
+       .path_unlink         = tomoyo_path_unlink,
+       .path_mkdir          = tomoyo_path_mkdir,
+       .path_rmdir          = tomoyo_path_rmdir,
+       .path_symlink        = tomoyo_path_symlink,
+       .path_mknod          = tomoyo_path_mknod,
+       .path_link           = tomoyo_path_link,
+       .path_rename         = tomoyo_path_rename,
+};
+
+static int __init tomoyo_init(void)
+{
+       struct cred *cred = (struct cred *) current_cred();
+
+       if (!security_module_enable(&tomoyo_security_ops))
+               return 0;
+       /* register ourselves with the security framework */
+       if (register_security(&tomoyo_security_ops))
+               panic("Failure registering TOMOYO Linux");
+       printk(KERN_INFO "TOMOYO Linux initialized\n");
+       cred->security = &tomoyo_kernel_domain;
+       tomoyo_realpath_init();
+       return 0;
+}
+
+security_initcall(tomoyo_init);
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h
new file mode 100644 (file)
index 0000000..a0c8f6e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * security/tomoyo/tomoyo.h
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2009  NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre   2009/02/01
+ *
+ */
+
+#ifndef _SECURITY_TOMOYO_TOMOYO_H
+#define _SECURITY_TOMOYO_TOMOYO_H
+
+struct tomoyo_path_info;
+struct path;
+struct inode;
+struct linux_binprm;
+struct pt_regs;
+struct tomoyo_page_buffer;
+
+int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
+                          const char *filename, const u8 perm);
+int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+                          const struct tomoyo_path_info *filename,
+                          struct tomoyo_page_buffer *buf);
+int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
+                                struct path *path, const int flag);
+int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
+                           const u8 operation, struct path *path);
+int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain,
+                           const u8 operation, struct path *path1,
+                           struct path *path2);
+int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
+                                   struct file *filp);
+int tomoyo_find_next_domain(struct linux_binprm *bprm,
+                           struct tomoyo_domain_info **next_domain);
+
+/* Index numbers for Access Controls. */
+
+#define TOMOYO_TYPE_SINGLE_PATH_ACL                 0
+#define TOMOYO_TYPE_DOUBLE_PATH_ACL                 1
+
+/* Index numbers for File Controls. */
+
+/*
+ * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
+ * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
+ * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
+ * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
+ * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
+ * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
+ */
+
+#define TOMOYO_TYPE_READ_WRITE_ACL    0
+#define TOMOYO_TYPE_EXECUTE_ACL       1
+#define TOMOYO_TYPE_READ_ACL          2
+#define TOMOYO_TYPE_WRITE_ACL         3
+#define TOMOYO_TYPE_CREATE_ACL        4
+#define TOMOYO_TYPE_UNLINK_ACL        5
+#define TOMOYO_TYPE_MKDIR_ACL         6
+#define TOMOYO_TYPE_RMDIR_ACL         7
+#define TOMOYO_TYPE_MKFIFO_ACL        8
+#define TOMOYO_TYPE_MKSOCK_ACL        9
+#define TOMOYO_TYPE_MKBLOCK_ACL      10
+#define TOMOYO_TYPE_MKCHAR_ACL       11
+#define TOMOYO_TYPE_TRUNCATE_ACL     12
+#define TOMOYO_TYPE_SYMLINK_ACL      13
+#define TOMOYO_TYPE_REWRITE_ACL      14
+#define TOMOYO_MAX_SINGLE_PATH_OPERATION 15
+
+#define TOMOYO_TYPE_LINK_ACL         0
+#define TOMOYO_TYPE_RENAME_ACL       1
+#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2
+
+#define TOMOYO_DOMAINPOLICY          0
+#define TOMOYO_EXCEPTIONPOLICY       1
+#define TOMOYO_DOMAIN_STATUS         2
+#define TOMOYO_PROCESS_STATUS        3
+#define TOMOYO_MEMINFO               4
+#define TOMOYO_SELFDOMAIN            5
+#define TOMOYO_VERSION               6
+#define TOMOYO_PROFILE               7
+#define TOMOYO_MANAGER               8
+
+extern struct tomoyo_domain_info tomoyo_kernel_domain;
+
+static inline struct tomoyo_domain_info *tomoyo_domain(void)
+{
+       return current_cred()->security;
+}
+
+/* Caller holds tasklist_lock spinlock. */
+static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
+                                                           *task)
+{
+       /***** CRITICAL SECTION START *****/
+       const struct cred *cred = get_task_cred(task);
+       struct tomoyo_domain_info *domain = cred->security;
+
+       put_cred(cred);
+       return domain;
+       /***** CRITICAL SECTION END *****/
+}
+
+#endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */
index 200aca1faa7112f0413f3cd92ab0a55cec48f588..1eceb85287c5f8197a25fe4a326c25b5dbf8e5be 100644 (file)
@@ -60,6 +60,8 @@ source "sound/aoa/Kconfig"
 
 source "sound/arm/Kconfig"
 
+source "sound/atmel/Kconfig"
+
 source "sound/spi/Kconfig"
 
 source "sound/mips/Kconfig"
index c76d70716fa537edccbe4ceada9b3eea1fbfa9f4..ec467decfa7913d19b663fc57ecde40be21093d2 100644 (file)
@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
-       sparc/ spi/ parisc/ pcmcia/ mips/ soc/
+       sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
index ee64f5de896617b1f17dbb4b5a7064eef257b552..6065b0344e23ce888a2ce5eea1015c35165e0c66 100644 (file)
@@ -34,10 +34,12 @@ struct gpio_methods {
        void (*set_headphone)(struct gpio_runtime *rt, int on);
        void (*set_speakers)(struct gpio_runtime *rt, int on);
        void (*set_lineout)(struct gpio_runtime *rt, int on);
+       void (*set_master)(struct gpio_runtime *rt, int on);
 
        int (*get_headphone)(struct gpio_runtime *rt);
        int (*get_speakers)(struct gpio_runtime *rt);
        int (*get_lineout)(struct gpio_runtime *rt);
+       int (*get_master)(struct gpio_runtime *rt);
 
        void (*set_hw_reset)(struct gpio_runtime *rt, int on);
 
index 617850463582fc682696969659bcda553ec02eb6..0fa3855b4790e30753b7b8ea4fb29644a6e8cd1f 100644 (file)
@@ -23,9 +23,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
                /* cannot be EEXIST due to usage in aoa_fabric_register */
                return -EBUSY;
 
-       alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card));
-       if (!alsa_card)
-               return -ENOMEM;
+       err = snd_card_create(index, name, mod, sizeof(struct aoa_card),
+                             &alsa_card);
+       if (err < 0)
+               return err;
        aoa_card = alsa_card->private_data;
        aoa_card->alsa_card = alsa_card;
        alsa_card->dev = dev;
index c93ad5dec66b54d7e50f10b98a06cd0ac9c5e5a8..de8e03afa97b2e09d8602be884a56f252dcf3069 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include "../aoa.h"
 
-/* TODO: these are 20 global variables
+/* TODO: these are lots of global variables
  * that aren't used on most machines...
  * Move them into a dynamically allocated
  * structure and use that.
@@ -23,6 +23,7 @@
 /* these are the GPIO numbers (register addresses as offsets into
  * the GPIO space) */
 static int headphone_mute_gpio;
+static int master_mute_gpio;
 static int amp_mute_gpio;
 static int lineout_mute_gpio;
 static int hw_reset_gpio;
@@ -32,6 +33,7 @@ static int linein_detect_gpio;
 
 /* see the SWITCH_GPIO macro */
 static int headphone_mute_gpio_activestate;
+static int master_mute_gpio_activestate;
 static int amp_mute_gpio_activestate;
 static int lineout_mute_gpio_activestate;
 static int hw_reset_gpio_activestate;
@@ -156,6 +158,7 @@ static int ftr_gpio_get_##name(struct gpio_runtime *rt)             \
 FTR_GPIO(headphone, 0);
 FTR_GPIO(amp, 1);
 FTR_GPIO(lineout, 2);
+FTR_GPIO(master, 3);
 
 static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
 {
@@ -172,6 +175,8 @@ static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
                          hw_reset_gpio, v);
 }
 
+static struct gpio_methods methods;
+
 static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
 {
        int saved;
@@ -181,6 +186,8 @@ static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
        ftr_gpio_set_headphone(rt, 0);
        ftr_gpio_set_amp(rt, 0);
        ftr_gpio_set_lineout(rt, 0);
+       if (methods.set_master)
+               ftr_gpio_set_master(rt, 0);
        rt->implementation_private = saved;
 }
 
@@ -193,6 +200,8 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
        ftr_gpio_set_headphone(rt, (s>>0)&1);
        ftr_gpio_set_amp(rt, (s>>1)&1);
        ftr_gpio_set_lineout(rt, (s>>2)&1);
+       if (methods.set_master)
+               ftr_gpio_set_master(rt, (s>>3)&1);
 }
 
 static void ftr_handle_notify(struct work_struct *work)
@@ -231,6 +240,12 @@ static void ftr_gpio_init(struct gpio_runtime *rt)
        get_gpio("hw-reset", "audio-hw-reset",
                 &hw_reset_gpio,
                 &hw_reset_gpio_activestate);
+       if (get_gpio("master-mute", NULL,
+                    &master_mute_gpio,
+                    &master_mute_gpio_activestate)) {
+               methods.set_master = ftr_gpio_set_master;
+               methods.get_master = ftr_gpio_get_master;
+       }
 
        headphone_detect_node = get_gpio("headphone-detect", NULL,
                                         &headphone_detect_gpio,
index ad60f5d10e82543195e17e843c62e39d7d0aa367..fbf5c933baa4aa1487e9f2559210ac61f262be07 100644 (file)
@@ -1,16 +1,14 @@
 /*
- * Apple Onboard Audio driver -- layout fabric
+ * Apple Onboard Audio driver -- layout/machine id fabric
  *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
  *
  * GPL v2, can be found in COPYING.
  *
  *
- * This fabric module looks for sound codecs
- * based on the layout-id property in the device tree.
- *
+ * This fabric module looks for sound codecs based on the
+ * layout-id or device-id property in the device tree.
  */
-
 #include <asm/prom.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -63,7 +61,7 @@ struct codec_connect_info {
 #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF        (1<<0)
 
 struct layout {
-       unsigned int layout_id;
+       unsigned int layout_id, device_id;
        struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
        int flags;
 
@@ -111,6 +109,10 @@ MODULE_ALIAS("sound-layout-96");
 MODULE_ALIAS("sound-layout-98");
 MODULE_ALIAS("sound-layout-100");
 
+MODULE_ALIAS("aoa-device-id-14");
+MODULE_ALIAS("aoa-device-id-22");
+MODULE_ALIAS("aoa-device-id-35");
+
 /* onyx with all but microphone connected */
 static struct codec_connection onyx_connections_nomic[] = {
        {
@@ -518,6 +520,27 @@ static struct layout layouts[] = {
                .connections = onyx_connections_noheadphones,
          },
        },
+       /* PowerMac3,4 */
+       { .device_id = 14,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_noline,
+         },
+       },
+       /* PowerMac3,6 */
+       { .device_id = 22,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_all,
+         },
+       },
+       /* PowerBook5,2 */
+       { .device_id = 35,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_all,
+         },
+       },
        {}
 };
 
@@ -526,7 +549,7 @@ static struct layout *find_layout_by_id(unsigned int id)
        struct layout *l;
 
        l = layouts;
-       while (l->layout_id) {
+       while (l->codecs[0].name) {
                if (l->layout_id == id)
                        return l;
                l++;
@@ -534,6 +557,19 @@ static struct layout *find_layout_by_id(unsigned int id)
        return NULL;
 }
 
+static struct layout *find_layout_by_device(unsigned int id)
+{
+       struct layout *l;
+
+       l = layouts;
+       while (l->codecs[0].name) {
+               if (l->device_id == id)
+                       return l;
+               l++;
+       }
+       return NULL;
+}
+
 static void use_layout(struct layout *l)
 {
        int i;
@@ -564,6 +600,7 @@ struct layout_dev {
        struct snd_kcontrol *headphone_ctrl;
        struct snd_kcontrol *lineout_ctrl;
        struct snd_kcontrol *speaker_ctrl;
+       struct snd_kcontrol *master_ctrl;
        struct snd_kcontrol *headphone_detected_ctrl;
        struct snd_kcontrol *lineout_detected_ctrl;
 
@@ -615,6 +652,7 @@ static struct snd_kcontrol_new n##_ctl = {                          \
 AMP_CONTROL(headphone, "Headphone Switch");
 AMP_CONTROL(speakers, "Speakers Switch");
 AMP_CONTROL(lineout, "Line-Out Switch");
+AMP_CONTROL(master, "Master Switch");
 
 static int detect_choice_get(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
@@ -855,6 +893,11 @@ static void layout_attached_codec(struct aoa_codec *codec)
        lineout = codec->gpio->methods->get_detect(codec->gpio,
                                                   AOA_NOTIFY_LINE_OUT);
 
+       if (codec->gpio->methods->set_master) {
+               ctl = snd_ctl_new1(&master_ctl, codec->gpio);
+               ldev->master_ctrl = ctl;
+               aoa_snd_ctl_add(ctl);
+       }
        while (cc->connected) {
                if (cc->connected & CC_SPEAKERS) {
                        if (headphones <= 0 && lineout <= 0)
@@ -938,8 +981,8 @@ static struct aoa_fabric layout_fabric = {
 static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 {
        struct device_node *sound = NULL;
-       const unsigned int *layout_id;
-       struct layout *layout;
+       const unsigned int *id;
+       struct layout *layout = NULL;
        struct layout_dev *ldev = NULL;
        int err;
 
@@ -952,15 +995,18 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
                if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
                        break;
        }
-       if (!sound) return -ENODEV;
+       if (!sound)
+               return -ENODEV;
 
-       layout_id = of_get_property(sound, "layout-id", NULL);
-       if (!layout_id)
-               goto outnodev;
-       printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
-              *layout_id);
+       id = of_get_property(sound, "layout-id", NULL);
+       if (id) {
+               layout = find_layout_by_id(*id);
+       } else {
+               id = of_get_property(sound, "device-id", NULL);
+               if (id)
+                       layout = find_layout_by_device(*id);
+       }
 
-       layout = find_layout_by_id(*layout_id);
        if (!layout) {
                printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
                goto outnodev;
@@ -976,6 +1022,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        ldev->layout = layout;
        ldev->gpio.node = sound->parent;
        switch (layout->layout_id) {
+       case 0:  /* anything with device_id, not layout_id */
        case 41: /* that unknown machine no one seems to have */
        case 51: /* PowerBook5,4 */
        case 58: /* Mac Mini */
index be468edf3ecb990ba68b4117808a2ebdf55472ce..418c84c99d6946d8cb4982569ada0542c1327dfa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * i2sbus driver
  *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
  *
  * GPL v2, can be found in COPYING.
  */
@@ -186,13 +186,25 @@ static int i2sbus_add_dev(struct macio_dev *macio,
                }
        }
        if (i == 1) {
-               const u32 *layout_id =
-                       of_get_property(sound, "layout-id", NULL);
-               if (layout_id) {
-                       layout = *layout_id;
+               const u32 *id = of_get_property(sound, "layout-id", NULL);
+
+               if (id) {
+                       layout = *id;
                        snprintf(dev->sound.modalias, 32,
                                 "sound-layout-%d", layout);
                        ok = 1;
+               } else {
+                       id = of_get_property(sound, "device-id", NULL);
+                       /*
+                        * We probably cannot handle all device-id machines,
+                        * so restrict to those we do handle for now.
+                        */
+                       if (id && (*id == 22 || *id == 14 || *id == 35)) {
+                               snprintf(dev->sound.modalias, 32,
+                                        "aoa-device-id-%d", *id);
+                               ok = 1;
+                               layout = -1;
+                       }
                }
        }
        /* for the time being, until we can handle non-layout-id
index f8e6de48d816a49d4451b88b8417069ae1062510..885683a3b0bdf084985328151d35308d4ebb5afb 100644 (file)
@@ -11,17 +11,6 @@ menuconfig SND_ARM
 
 if SND_ARM
 
-config SND_SA11XX_UDA1341
-       tristate "SA11xx UDA1341TS driver (iPaq H3600)"
-       depends on ARCH_SA1100 && L3
-       select SND_PCM
-       help
-         Say Y here if you have a Compaq iPaq H3x00 handheld computer
-         and want to use its Philips UDA 1341 audio chip.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-sa11xx-uda1341.
-
 config SND_ARMAACI
        tristate "ARM PrimeCell PL041 AC Link support"
        depends on ARM_AMBA
index 2054de11de8a2140ce7f4052c0233ba5fb183fb6..5a549ed6c8aa500bc4a202ec3ac20206f5fa038a 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for ALSA
 #
 
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o 
-snd-sa11xx-uda1341-objs                := sa11xx-uda1341.o
-
 obj-$(CONFIG_SND_ARMAACI)      += snd-aaci.o
 snd-aaci-objs                  := aaci.o devdma.o
 
index 772901e41ecb5fe86d83633e0e2137847233a745..7fbd68fab944e08ecba5bd4424331007198705e2 100644 (file)
@@ -995,10 +995,11 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
 {
        struct aaci *aaci;
        struct snd_card *card;
+       int err;
 
-       card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                           THIS_MODULE, sizeof(struct aaci));
-       if (card == NULL)
+       err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                             THIS_MODULE, sizeof(struct aaci), &card);
+       if (err < 0)
                return NULL;
 
        card->private_free = aaci_free_card;
index 35afd0c33be58b1a74b1e1be7685bd88dd65a801..2e6355f4cbb926d888f7c2b5711512354ba2890e 100644 (file)
@@ -31,6 +31,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
 static volatile long gsr_bits;
 static struct clk *ac97_clk;
 static struct clk *ac97conf_clk;
+static int reset_gpio;
 
 /*
  * Beware PXA27x bugs:
@@ -42,6 +43,45 @@ static struct clk *ac97conf_clk;
  * 1 jiffy timeout if interrupt never comes).
  */
 
+enum {
+       RESETGPIO_FORCE_HIGH,
+       RESETGPIO_FORCE_LOW,
+       RESETGPIO_NORMAL_ALTFUNC
+};
+
+/**
+ * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA
+ * @mode: chosen action
+ *
+ * As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line
+ * must be done to insure proper work of AC97 reset line.  This function
+ * computes the correct gpio_mode for further use by reset functions, and
+ * applied the change through pxa_gpio_mode.
+ */
+static void set_resetgpio_mode(int resetgpio_action)
+{
+       int mode = 0;
+
+       if (reset_gpio)
+               switch (resetgpio_action) {
+               case RESETGPIO_NORMAL_ALTFUNC:
+                       if (reset_gpio == 113)
+                               mode = 113 | GPIO_OUT | GPIO_DFLT_LOW;
+                       if (reset_gpio == 95)
+                               mode = 95 | GPIO_ALT_FN_1_OUT;
+                       break;
+               case RESETGPIO_FORCE_LOW:
+                       mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW;
+                       break;
+               case RESETGPIO_FORCE_HIGH:
+                       mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH;
+                       break;
+               };
+
+       if (mode)
+               pxa_gpio_mode(mode);
+}
+
 unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        unsigned short val = -1;
@@ -137,10 +177,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
 
        /* warm reset broken on Bulverde,
           so manually keep AC97 reset high */
-       pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+       set_resetgpio_mode(RESETGPIO_FORCE_HIGH);
        udelay(10);
        GCR |= GCR_WARM_RST;
-       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+       set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
        udelay(500);
 }
 
@@ -308,8 +348,8 @@ int pxa2xx_ac97_hw_resume(void)
                pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
        }
        if (cpu_is_pxa27x()) {
-               /* Use GPIO 113 as AC97 Reset on Bulverde */
-               pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+               /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */
+               set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
        }
        clk_enable(ac97_clk);
        return 0;
@@ -320,6 +360,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
 int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
 {
        int ret;
+       struct pxa2xx_ac97_platform_data *pdata = dev->dev.platform_data;
+
+       if (pdata) {
+               switch (pdata->reset_gpio) {
+               case 95:
+               case 113:
+                       reset_gpio = pdata->reset_gpio;
+                       break;
+               case 0:
+                       reset_gpio = 113;
+                       break;
+               case -1:
+                       break;
+               default:
+                       dev_err(&dev->dev, "Invalid reset GPIO %d\n",
+                               pdata->reset_gpio);
+               }
+       } else {
+               if (cpu_is_pxa27x())
+                       reset_gpio = 113;
+       }
 
        if (cpu_is_pxa25x() || cpu_is_pxa27x()) {
                pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
@@ -330,7 +391,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
 
        if (cpu_is_pxa27x()) {
                /* Use GPIO 113 as AC97 Reset on Bulverde */
-               pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+               set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
                ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
                if (IS_ERR(ac97conf_clk)) {
                        ret = PTR_ERR(ac97conf_clk);
index 85cf591d4e11d594d96ac970ec1bed41d473bbb2..7ed100c80a5f752a7768cc11d152eb1e01471a8c 100644 (file)
@@ -173,10 +173,9 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
        struct snd_ac97_template ac97_template;
        int ret;
 
-       ret = -ENOMEM;
-       card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                           THIS_MODULE, 0);
-       if (!card)
+       ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                             THIS_MODULE, 0, &card);
+       if (ret < 0)
                goto err;
 
        card->dev = &dev->dev;
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
deleted file mode 100644 (file)
index 1dcd51d..0000000
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- *  Driver for Philips UDA1341TS on Compaq iPAQ H3600 soundcard
- *  Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License.
- * 
- * History:
- *
- * 2002-03-13   Tomas Kasparek  initial release - based on h3600-uda1341.c from OSS
- * 2002-03-20   Tomas Kasparek  playback over ALSA is working
- * 2002-03-28   Tomas Kasparek  playback over OSS emulation is working
- * 2002-03-29   Tomas Kasparek  basic capture is working (native ALSA)
- * 2002-03-29   Tomas Kasparek  capture is working (OSS emulation)
- * 2002-04-04   Tomas Kasparek  better rates handling (allow non-standard rates)
- * 2003-02-14   Brian Avery     fixed full duplex mode, other updates
- * 2003-02-20   Tomas Kasparek  merged updates by Brian (except HAL)
- * 2003-04-19   Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel
- *                              working suspend and resume
- * 2003-04-28   Tomas Kasparek  updated work by Jaroslav to compile it under 2.5.x again
- *                              merged HAL layer (patches from Brian)
- */
-
-/***************************************************************************************************
-*
-* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
-* available in the Alsa doc section on the website             
-* 
-* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
-* We are using  SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
-* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
-* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
-* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
-* is a mem loc that always decodes to 0's w/ no off chip access.
-*
-* Some alsa terminology:
-*      frame => num_channels * sample_size  e.g stereo 16 bit is 2 * 16 = 32 bytes
-*      period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
-*             buffer and 4 periods in the runtime structure this means we'll get an int every 256
-*             bytes or 4 times per buffer.
-*             A number of the sizes are in frames rather than bytes, use frames_to_bytes and
-*             bytes_to_frames to convert.  The easiest way to tell the units is to look at the
-*             type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
-*             
-*      Notes about the pointer fxn:
-*      The pointer fxn needs to return the offset into the dma buffer in frames.
-*      Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
-*
-*      Notes about pause/resume
-*      Implementing this would be complicated so it's skipped.  The problem case is:
-*      A full duplex connection is going, then play is paused. At this point you need to start xmitting
-*      0's to keep the record active which means you cant just freeze the dma and resume it later you'd
-*      need to save off the dma info, and restore it properly on a resume.  Yeach!
-*
-*      Notes about transfer methods:
-*      The async write calls fail.  I probably need to implement something else to support them?
-* 
-***************************************************************************************************/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include <mach/hardware.h>
-#include <mach/h3600.h>
-#include <asm/mach-types.h>
-#include <asm/dma.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-
-#include <linux/l3/l3.h>
-
-#undef DEBUG_MODE
-#undef DEBUG_FUNCTION_NAMES
-#include <sound/uda1341.h>
-
-/*
- * FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels?
- * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this
- * module for Familiar 0.6.1
- */
-
-/* {{{ Type definitions */
-
-MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
-MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
-
-static char *id;       /* ID for this card */
-
-module_param(id, charp, 0444);
-MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
-
-struct audio_stream {
-       char *id;               /* identification string */
-       int stream_id;          /* numeric identification */    
-       dma_device_t dma_dev;   /* device identifier for DMA */
-#ifdef HH_VERSION
-       dmach_t dmach;          /* dma channel identification */
-#else
-       dma_regs_t *dma_regs;   /* points to our DMA registers */
-#endif
-       unsigned int active:1;  /* we are using this stream for transfer now */
-       int period;             /* current transfer period */
-       int periods;            /* current count of periods registerd in the DMA engine */
-       int tx_spin;            /* are we recoding - flag used to do DMA trans. for sync */
-       unsigned int old_offset;
-       spinlock_t dma_lock;    /* for locking in DMA operations (see dma-sa1100.c in the kernel) */
-       struct snd_pcm_substream *stream;
-};
-
-struct sa11xx_uda1341 {
-       struct snd_card *card;
-       struct l3_client *uda1341;
-       struct snd_pcm *pcm;
-       long samplerate;
-       struct audio_stream s[2];       /* playback & capture */
-};
-
-static unsigned int rates[] = {
-       8000,  10666, 10985, 14647,
-       16000, 21970, 22050, 24000,
-       29400, 32000, 44100, 48000,
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-       .count  = ARRAY_SIZE(rates),
-       .list   = rates,
-       .mask   = 0,
-};
-
-static struct platform_device *device;
-
-/* }}} */
-
-/* {{{ Clock and sample rate stuff */
-
-/*
- * Stop-gap solution until rest of hh.org HAL stuff is merged.
- */
-#define GPIO_H3600_CLK_SET0            GPIO_GPIO (12)
-#define GPIO_H3600_CLK_SET1            GPIO_GPIO (13)
-
-#ifdef CONFIG_SA1100_H3XXX
-#define        clr_sa11xx_uda1341_egpio(x)     clr_h3600_egpio(x)
-#define set_sa11xx_uda1341_egpio(x)    set_h3600_egpio(x)
-#else
-#error This driver could serve H3x00 handhelds only!
-#endif
-
-static void sa11xx_uda1341_set_audio_clock(long val)
-{
-       switch (val) {
-       case 24000: case 32000: case 48000:     /* 00: 12.288 MHz */
-               GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
-               break;
-
-       case 22050: case 29400: case 44100:     /* 01: 11.2896 MHz */
-               GPSR = GPIO_H3600_CLK_SET0;
-               GPCR = GPIO_H3600_CLK_SET1;
-               break;
-
-       case 8000: case 10666: case 16000:      /* 10: 4.096 MHz */
-               GPCR = GPIO_H3600_CLK_SET0;
-               GPSR = GPIO_H3600_CLK_SET1;
-               break;
-
-       case 10985: case 14647: case 21970:     /* 11: 5.6245 MHz */
-               GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
-               break;
-       }
-}
-
-static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, long rate)
-{
-       int clk_div = 0;
-       int clk=0;
-
-       /* We don't want to mess with clocks when frames are in flight */
-       Ser4SSCR0 &= ~SSCR0_SSE;
-       /* wait for any frame to complete */
-       udelay(125);
-
-       /*
-        * We have the following clock sources:
-        * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
-        * Those can be divided either by 256, 384 or 512.
-        * This makes up 12 combinations for the following samplerates...
-        */
-       if (rate >= 48000)
-               rate = 48000;
-       else if (rate >= 44100)
-               rate = 44100;
-       else if (rate >= 32000)
-               rate = 32000;
-       else if (rate >= 29400)
-               rate = 29400;
-       else if (rate >= 24000)
-               rate = 24000;
-       else if (rate >= 22050)
-               rate = 22050;
-       else if (rate >= 21970)
-               rate = 21970;
-       else if (rate >= 16000)
-               rate = 16000;
-       else if (rate >= 14647)
-               rate = 14647;
-       else if (rate >= 10985)
-               rate = 10985;
-       else if (rate >= 10666)
-               rate = 10666;
-       else
-               rate = 8000;
-
-       /* Set the external clock generator */
-       
-       sa11xx_uda1341_set_audio_clock(rate);
-
-       /* Select the clock divisor */
-       switch (rate) {
-       case 8000:
-       case 10985:
-       case 22050:
-       case 24000:
-               clk = F512;
-               clk_div = SSCR0_SerClkDiv(16);
-               break;
-       case 16000:
-       case 21970:
-       case 44100:
-       case 48000:
-               clk = F256;
-               clk_div = SSCR0_SerClkDiv(8);
-               break;
-       case 10666:
-       case 14647:
-       case 29400:
-       case 32000:
-               clk = F384;
-               clk_div = SSCR0_SerClkDiv(12);
-               break;
-       }
-
-       /* FMT setting should be moved away when other FMTs are added (FIXME) */
-       l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
-       
-       l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);        
-       Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
-       sa11xx_uda1341->samplerate = rate;
-}
-
-/* }}} */
-
-/* {{{ HW init and shutdown */
-
-static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341)
-{
-       unsigned long flags;
-
-       /* Setup DMA stuff */
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out";
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr;
-
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in";
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
-       sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd;
-
-       /* Initialize the UDA1341 internal state */
-       
-       /* Setup the uarts */
-       local_irq_save(flags);
-       GAFR |= (GPIO_SSP_CLK);
-       GPDR &= ~(GPIO_SSP_CLK);
-       Ser4SSCR0 = 0;
-       Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
-       Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
-       Ser4SSCR0 |= SSCR0_SSE;
-       local_irq_restore(flags);
-
-       /* Enable the audio power */
-
-       clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
-       set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
-       set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-       /* Wait for the UDA1341 to wake up */
-       mdelay(1); //FIXME - was removed by Perex - Why?
-
-       /* Initialize the UDA1341 internal state */
-       l3_open(sa11xx_uda1341->uda1341);
-       
-       /* external clock configuration (after l3_open - regs must be initialized */
-       sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate);
-
-       /* Wait for the UDA1341 to wake up */
-       set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
-       mdelay(1);      
-
-       /* make the left and right channels unswapped (flip the WS latch) */
-       Ser4SSDR = 0;
-
-       clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-}
-
-static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341)
-{
-       /* mute on */
-       set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-       
-       /* disable the audio power and all signals leading to the audio chip */
-       l3_close(sa11xx_uda1341->uda1341);
-       Ser4SSCR0 = 0;
-       clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
-
-       /* power off and mute off */
-       /* FIXME - is muting off necesary??? */
-
-       clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
-       clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-}
-
-/* }}} */
-
-/* {{{ DMA staff */
-
-/*
- * these are the address and sizes used to fill the xmit buffer
- * so we can get a clock in record only mode
- */
-#define FORCE_CLOCK_ADDR               (dma_addr_t)FLUSH_BASE_PHYS
-#define FORCE_CLOCK_SIZE               4096 // was 2048
-
-// FIXME Why this value exactly - wrote comment
-#define DMA_BUF_SIZE   8176    /* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */
-
-#ifdef HH_VERSION
-
-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *, int))
-{
-       int ret;
-
-       ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev);
-       if (ret < 0) {
-               printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
-               return ret;
-       }
-       sa1100_dma_set_callback(s->dmach, callback);
-       return 0;
-}
-
-static inline void audio_dma_free(struct audio_stream *s)
-{
-       sa1100_free_dma(s->dmach);
-       s->dmach = -1;
-}
-
-#else
-
-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *))
-{
-       int ret;
-
-       ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs);
-       if (ret < 0)
-               printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
-       return ret;
-}
-
-static void audio_dma_free(struct audio_stream *s)
-{
-       sa1100_free_dma(s->dma_regs);
-       s->dma_regs = 0;
-}
-
-#endif
-
-static u_int audio_get_dma_pos(struct audio_stream *s)
-{
-       struct snd_pcm_substream *substream = s->stream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int offset;
-       unsigned long flags;
-       dma_addr_t addr;
-       
-       // this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
-       spin_lock_irqsave(&s->dma_lock, flags);
-#ifdef HH_VERSION      
-       sa1100_dma_get_current(s->dmach, NULL, &addr);
-#else
-       addr = sa1100_get_dma_pos((s)->dma_regs);
-#endif
-       offset = addr - runtime->dma_addr;
-       spin_unlock_irqrestore(&s->dma_lock, flags);
-       
-       offset = bytes_to_frames(runtime,offset);
-       if (offset >= runtime->buffer_size)
-               offset = 0;
-
-       return offset;
-}
-
-/*
- * this stops the dma and clears the dma ptrs
- */
-static void audio_stop_dma(struct audio_stream *s)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&s->dma_lock, flags); 
-       s->active = 0;
-       s->period = 0;
-       /* this stops the dma channel and clears the buffer ptrs */
-#ifdef HH_VERSION
-       sa1100_dma_flush_all(s->dmach);
-#else
-       sa1100_clear_dma(s->dma_regs);  
-#endif
-       spin_unlock_irqrestore(&s->dma_lock, flags);
-}
-
-static void audio_process_dma(struct audio_stream *s)
-{
-       struct snd_pcm_substream *substream = s->stream;
-       struct snd_pcm_runtime *runtime;
-       unsigned int dma_size;          
-       unsigned int offset;
-       int ret;
-                
-       /* we are requested to process synchronization DMA transfer */
-       if (s->tx_spin) {
-               if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))
-                       return;
-               /* fill the xmit dma buffers and return */
-#ifdef HH_VERSION
-               sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
-#else
-               while (1) {
-                       ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
-                       if (ret)
-                               return;   
-               }
-#endif
-               return;
-       }
-
-       /* must be set here - only valid for running streams, not for forced_clock dma fills  */
-       runtime = substream->runtime;
-       while (s->active && s->periods < runtime->periods) {
-               dma_size = frames_to_bytes(runtime, runtime->period_size);
-               if (s->old_offset) {
-                       /* a little trick, we need resume from old position */
-                       offset = frames_to_bytes(runtime, s->old_offset - 1);
-                       s->old_offset = 0;
-                       s->periods = 0;
-                       s->period = offset / dma_size;
-                       offset %= dma_size;
-                       dma_size = dma_size - offset;
-                       if (!dma_size)
-                               continue;               /* special case */
-               } else {
-                       offset = dma_size * s->period;
-                       snd_BUG_ON(dma_size > DMA_BUF_SIZE);
-               }
-#ifdef HH_VERSION
-               ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
-               if (ret)
-                       return; //FIXME
-#else
-               ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
-               if (ret) {
-                       printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
-                       return;
-               }
-#endif
-
-               s->period++;
-               s->period %= runtime->periods;
-               s->periods++;
-       }
-}
-
-#ifdef HH_VERSION
-static void audio_dma_callback(void *data, int size)
-#else
-static void audio_dma_callback(void *data)
-#endif
-{
-       struct audio_stream *s = data;
-        
-       /* 
-        * If we are getting a callback for an active stream then we inform
-        * the PCM middle layer we've finished a period
-        */
-       if (s->active)
-               snd_pcm_period_elapsed(s->stream);
-
-       spin_lock(&s->dma_lock);
-       if (!s->tx_spin && s->periods > 0)
-               s->periods--;
-       audio_process_dma(s);
-       spin_unlock(&s->dma_lock);
-}
-
-/* }}} */
-
-/* {{{ PCM setting */
-
-/* {{{ trigger & timer */
-
-static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-       int stream_id = substream->pstr->stream;
-       struct audio_stream *s = &chip->s[stream_id];
-       struct audio_stream *s1 = &chip->s[stream_id ^ 1];
-       int err = 0;
-
-       /* note local interrupts are already disabled in the midlevel code */
-       spin_lock(&s->dma_lock);
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* now we need to make sure a record only stream has a clock */
-               if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
-                       /* we need to force fill the xmit DMA with zeros */
-                       s1->tx_spin = 1;
-                       audio_process_dma(s1);
-               }
-               /* this case is when you were recording then you turn on a
-                * playback stream so we stop (also clears it) the dma first,
-                * clear the sync flag and then we let it turned on
-                */             
-               else {
-                       s->tx_spin = 0;
-               }
-
-               /* requested stream startup */
-               s->active = 1;
-               audio_process_dma(s);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               /* requested stream shutdown */
-               audio_stop_dma(s);
-               
-               /*
-                * now we need to make sure a record only stream has a clock
-                * so if we're stopping a playback with an active capture
-                * we need to turn the 0 fill dma on for the xmit side
-                */
-               if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {
-                       /* we need to force fill the xmit DMA with zeros */
-                       s->tx_spin = 1;
-                       audio_process_dma(s);
-               }
-               /*
-                * we killed a capture only stream, so we should also kill
-                * the zero fill transmit
-                */
-               else {
-                       if (s1->tx_spin) {
-                               s1->tx_spin = 0;
-                               audio_stop_dma(s1);
-                       }
-               }
-               
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               s->active = 0;
-#ifdef HH_VERSION              
-               sa1100_dma_stop(s->dmach);
-#else
-               //FIXME - DMA API
-#endif         
-               s->old_offset = audio_get_dma_pos(s) + 1;
-#ifdef HH_VERSION              
-               sa1100_dma_flush_all(s->dmach);
-#else
-               //FIXME - DMA API
-#endif         
-               s->periods = 0;
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-               s->active = 1;
-               s->tx_spin = 0;
-               audio_process_dma(s);
-               if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
-                       s1->tx_spin = 1;
-                       audio_process_dma(s1);
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-#ifdef HH_VERSION              
-               sa1100_dma_stop(s->dmach);
-#else
-               //FIXME - DMA API
-#endif
-               s->active = 0;
-               if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
-                       if (s1->active) {
-                               s->tx_spin = 1;
-                               s->old_offset = audio_get_dma_pos(s) + 1;
-#ifdef HH_VERSION                              
-                               sa1100_dma_flush_all(s->dmach);
-#else
-                               //FIXME - DMA API
-#endif                         
-                               audio_process_dma(s);
-                       }
-               } else {
-                       if (s1->tx_spin) {
-                               s1->tx_spin = 0;
-#ifdef HH_VERSION                              
-                               sa1100_dma_flush_all(s1->dmach);
-#else
-                               //FIXME - DMA API
-#endif                         
-                       }
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               s->active = 1;
-               if (s->old_offset) {
-                       s->tx_spin = 0;
-                       audio_process_dma(s);
-                       break;
-               }
-               if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
-                       s1->tx_spin = 1;
-                       audio_process_dma(s1);
-               }
-#ifdef HH_VERSION              
-               sa1100_dma_resume(s->dmach);
-#else
-               //FIXME - DMA API
-#endif
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-       spin_unlock(&s->dma_lock);      
-       return err;
-}
-
-static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream)
-{
-       struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct audio_stream *s = &chip->s[substream->pstr->stream];
-        
-       /* set requested samplerate */
-       sa11xx_uda1341_set_samplerate(chip, runtime->rate);
-
-       /* set requestd format when available */
-       /* set FMT here !!! FIXME */
-
-       s->period = 0;
-       s->periods = 0;
-        
-       return 0;
-}
-
-static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream)
-{
-       struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-       return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
-}
-
-/* }}} */
-
-static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =
-{
-       .info                   = (SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                                  SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .rates                  = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-                                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
-                                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-                                  SNDRV_PCM_RATE_KNOT),
-       .rate_min               = 8000,
-       .rate_max               = 48000,
-       .channels_min           = 2,
-       .channels_max           = 2,
-       .buffer_bytes_max       = 64*1024,
-       .period_bytes_min       = 64,
-       .period_bytes_max       = DMA_BUF_SIZE,
-       .periods_min            = 2,
-       .periods_max            = 255,
-       .fifo_size              = 0,
-};
-
-static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =
-{
-       .info                   = (SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                                  SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .rates                  = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-                                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
-                                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-                                  SNDRV_PCM_RATE_KNOT),
-       .rate_min               = 8000,
-       .rate_max               = 48000,
-       .channels_min           = 2,
-       .channels_max           = 2,
-       .buffer_bytes_max       = 64*1024,
-       .period_bytes_min       = 64,
-       .period_bytes_max       = DMA_BUF_SIZE,
-       .periods_min            = 2,
-       .periods_max            = 255,
-       .fifo_size              = 0,
-};
-
-static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)
-{
-       struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int stream_id = substream->pstr->stream;
-       int err;
-
-       chip->s[stream_id].stream = substream;
-
-       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
-               runtime->hw = snd_sa11xx_uda1341_playback;
-       else
-               runtime->hw = snd_sa11xx_uda1341_capture;
-       if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-               return err;
-       if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
-               return err;
-        
-       return 0;
-}
-
-static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)
-{
-       struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-
-       chip->s[substream->pstr->stream].stream = NULL;
-       return 0;
-}
-
-/* {{{ HW params & free */
-
-static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *hw_params)
-{
-        
-       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-}
-
-static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-/* }}} */
-
-static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {
-       .open                   = snd_card_sa11xx_uda1341_open,
-       .close                  = snd_card_sa11xx_uda1341_close,
-       .ioctl                  = snd_pcm_lib_ioctl,
-       .hw_params              = snd_sa11xx_uda1341_hw_params,
-       .hw_free                = snd_sa11xx_uda1341_hw_free,
-       .prepare                = snd_sa11xx_uda1341_prepare,
-       .trigger                = snd_sa11xx_uda1341_trigger,
-       .pointer                = snd_sa11xx_uda1341_pointer,
-};
-
-static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {
-       .open                   = snd_card_sa11xx_uda1341_open,
-       .close                  = snd_card_sa11xx_uda1341_close,
-       .ioctl                  = snd_pcm_lib_ioctl,
-       .hw_params              = snd_sa11xx_uda1341_hw_params,
-       .hw_free                = snd_sa11xx_uda1341_hw_free,
-       .prepare                = snd_sa11xx_uda1341_prepare,
-       .trigger                = snd_sa11xx_uda1341_trigger,
-       .pointer                = snd_sa11xx_uda1341_pointer,
-};
-
-static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)
-{
-       struct snd_pcm *pcm;
-       int err;
-
-       if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)
-               return err;
-
-       /*
-        * this sets up our initial buffers and sets the dma_type to isa.
-        * isa works but I'm not sure why (or if) it's the right choice
-        * this may be too large, trying it for now
-        */
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 
-                                             snd_dma_isa_data(),
-                                             64*1024, 64*1024);
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
-       pcm->private_data = sa11xx_uda1341;
-       pcm->info_flags = 0;
-       strcpy(pcm->name, "UDA1341 PCM");
-
-       sa11xx_uda1341_audio_init(sa11xx_uda1341);
-
-       /* setup DMA controller */
-       audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);
-       audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);
-
-       sa11xx_uda1341->pcm = pcm;
-
-       return 0;
-}
-
-/* }}} */
-
-/* {{{ module init & exit */
-
-#ifdef CONFIG_PM
-
-static int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,
-                                     pm_message_t state)
-{
-       struct snd_card *card = platform_get_drvdata(devptr);
-       struct sa11xx_uda1341 *chip = card->private_data;
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       snd_pcm_suspend_all(chip->pcm);
-#ifdef HH_VERSION
-       sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
-       sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
-#else
-       //FIXME
-#endif
-       l3_command(chip->uda1341, CMD_SUSPEND, NULL);
-       sa11xx_uda1341_audio_shutdown(chip);
-
-       return 0;
-}
-
-static int snd_sa11xx_uda1341_resume(struct platform_device *devptr)
-{
-       struct snd_card *card = platform_get_drvdata(devptr);
-       struct sa11xx_uda1341 *chip = card->private_data;
-
-       sa11xx_uda1341_audio_init(chip);
-       l3_command(chip->uda1341, CMD_RESUME, NULL);
-#ifdef HH_VERSION      
-       sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
-       sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
-#else
-       //FIXME
-#endif
-       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-       return 0;
-}
-#endif /* COMFIG_PM */
-
-void snd_sa11xx_uda1341_free(struct snd_card *card)
-{
-       struct sa11xx_uda1341 *chip = card->private_data;
-
-       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
-       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)
-{
-       int err;
-       struct snd_card *card;
-       struct sa11xx_uda1341 *chip;
-
-       /* register the soundcard */
-       card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));
-       if (card == NULL)
-               return -ENOMEM;
-
-       chip = card->private_data;
-       spin_lock_init(&chip->s[0].dma_lock);
-       spin_lock_init(&chip->s[1].dma_lock);
-
-       card->private_free = snd_sa11xx_uda1341_free;
-       chip->card = card;
-       chip->samplerate = AUDIO_RATE_DEFAULT;
-
-       // mixer
-       if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))
-               goto nodev;
-
-       // PCM
-       if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)
-               goto nodev;
-        
-       strcpy(card->driver, "UDA1341");
-       strcpy(card->shortname, "H3600 UDA1341TS");
-       sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
-        
-       snd_card_set_dev(card, &devptr->dev);
-
-       if ((err = snd_card_register(card)) == 0) {
-               printk( KERN_INFO "iPAQ audio support initialized\n" );
-               platform_set_drvdata(devptr, card);
-               return 0;
-       }
-        
- nodev:
-       snd_card_free(card);
-       return err;
-}
-
-static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)
-{
-       snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
-       return 0;
-}
-
-#define SA11XX_UDA1341_DRIVER  "sa11xx_uda1341"
-
-static struct platform_driver sa11xx_uda1341_driver = {
-       .probe          = sa11xx_uda1341_probe,
-       .remove         = __devexit_p(sa11xx_uda1341_remove),
-#ifdef CONFIG_PM
-       .suspend        = snd_sa11xx_uda1341_suspend,
-       .resume         = snd_sa11xx_uda1341_resume,
-#endif
-       .driver         = {
-               .name   = SA11XX_UDA1341_DRIVER,
-       },
-};
-
-static int __init sa11xx_uda1341_init(void)
-{
-       int err;
-
-       if (!machine_is_h3xxx())
-               return -ENODEV;
-       if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
-               return err;
-       device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
-       if (!IS_ERR(device)) {
-               if (platform_get_drvdata(device))
-                       return 0;
-               platform_device_unregister(device);
-               err = -ENODEV;
-       } else
-               err = PTR_ERR(device);
-       platform_driver_unregister(&sa11xx_uda1341_driver);
-       return err;
-}
-
-static void __exit sa11xx_uda1341_exit(void)
-{
-       platform_device_unregister(device);
-       platform_driver_unregister(&sa11xx_uda1341_driver);
-}
-
-module_init(sa11xx_uda1341_init);
-module_exit(sa11xx_uda1341_exit);
-
-/* }}} */
-
-/*
- * Local variables:
- * indent-tabs-mode: t
- * End:
- */
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig
new file mode 100644 (file)
index 0000000..6c228a9
--- /dev/null
@@ -0,0 +1,19 @@
+menu "Atmel devices (AVR32 and AT91)"
+       depends on AVR32 || ARCH_AT91
+
+config SND_ATMEL_ABDAC
+       tristate "Atmel Audio Bitstream DAC (ABDAC) driver"
+       select SND_PCM
+       depends on DW_DMAC && AVR32
+       help
+         ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC).
+
+config SND_ATMEL_AC97C
+       tristate "Atmel AC97 Controller (AC97C) driver"
+       select SND_PCM
+       select SND_AC97_CODEC
+       depends on DW_DMAC && AVR32
+       help
+         ALSA sound driver for the Atmel AC97 controller.
+
+endmenu
diff --git a/sound/atmel/Makefile b/sound/atmel/Makefile
new file mode 100644 (file)
index 0000000..219dcfa
--- /dev/null
@@ -0,0 +1,5 @@
+snd-atmel-abdac-objs           := abdac.o
+snd-atmel-ac97c-objs           := ac97c.o
+
+obj-$(CONFIG_SND_ATMEL_ABDAC)  += snd-atmel-abdac.o
+obj-$(CONFIG_SND_ATMEL_AC97C)  += snd-atmel-ac97c.o
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
new file mode 100644 (file)
index 0000000..28b3c7f
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC)
+ *
+ * Copyright (C) 2006-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/bitmap.h>
+#include <linux/dw_dmac.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/atmel-abdac.h>
+
+/* DAC register offsets */
+#define DAC_DATA                                0x0000
+#define DAC_CTRL                                0x0008
+#define DAC_INT_MASK                            0x000c
+#define DAC_INT_EN                              0x0010
+#define DAC_INT_DIS                             0x0014
+#define DAC_INT_CLR                             0x0018
+#define DAC_INT_STATUS                          0x001c
+
+/* Bitfields in CTRL */
+#define DAC_SWAP_OFFSET                         30
+#define DAC_SWAP_SIZE                           1
+#define DAC_EN_OFFSET                           31
+#define DAC_EN_SIZE                             1
+
+/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
+#define DAC_UNDERRUN_OFFSET                     28
+#define DAC_UNDERRUN_SIZE                       1
+#define DAC_TX_READY_OFFSET                     29
+#define DAC_TX_READY_SIZE                       1
+
+/* Bit manipulation macros */
+#define DAC_BIT(name)                                  \
+       (1 << DAC_##name##_OFFSET)
+#define DAC_BF(name, value)                            \
+       (((value) & ((1 << DAC_##name##_SIZE) - 1))     \
+        << DAC_##name##_OFFSET)
+#define DAC_BFEXT(name, value)                         \
+       (((value) >> DAC_##name##_OFFSET)               \
+        & ((1 << DAC_##name##_SIZE) - 1))
+#define DAC_BFINS(name, value, old)                    \
+       (((old) & ~(((1 << DAC_##name##_SIZE) - 1)      \
+                   << DAC_##name##_OFFSET))            \
+        | DAC_BF(name, value))
+
+/* Register access macros */
+#define dac_readl(port, reg)                           \
+       __raw_readl((port)->regs + DAC_##reg)
+#define dac_writel(port, reg, value)                   \
+       __raw_writel((value), (port)->regs + DAC_##reg)
+
+/*
+ * ABDAC supports a maximum of 6 different rates from a generic clock. The
+ * generic clock has a power of two divider, which gives 6 steps from 192 kHz
+ * to 5112 Hz.
+ */
+#define MAX_NUM_RATES  6
+/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */
+#define RATE_MAX       192000
+#define RATE_MIN       5112
+
+enum {
+       DMA_READY = 0,
+};
+
+struct atmel_abdac_dma {
+       struct dma_chan         *chan;
+       struct dw_cyclic_desc   *cdesc;
+};
+
+struct atmel_abdac {
+       struct clk                              *pclk;
+       struct clk                              *sample_clk;
+       struct platform_device                  *pdev;
+       struct atmel_abdac_dma                  dma;
+
+       struct snd_pcm_hw_constraint_list       constraints_rates;
+       struct snd_pcm_substream                *substream;
+       struct snd_card                         *card;
+       struct snd_pcm                          *pcm;
+
+       void __iomem                            *regs;
+       unsigned long                           flags;
+       unsigned int                            rates[MAX_NUM_RATES];
+       unsigned int                            rates_num;
+       int                                     irq;
+};
+
+#define get_dac(card) ((struct atmel_abdac *)(card)->private_data)
+
+/* This function is called by the DMA driver. */
+static void atmel_abdac_dma_period_done(void *arg)
+{
+       struct atmel_abdac *dac = arg;
+       snd_pcm_period_elapsed(dac->substream);
+}
+
+static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
+               struct snd_pcm_substream *substream,
+               enum dma_data_direction direction)
+{
+       struct dma_chan                 *chan = dac->dma.chan;
+       struct dw_cyclic_desc           *cdesc;
+       struct snd_pcm_runtime          *runtime = substream->runtime;
+       unsigned long                   buffer_len, period_len;
+
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-halfword-aligned buffers or lengths.
+        */
+       if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
+               dev_dbg(&dac->pdev->dev, "too complex transfer\n");
+               return -EINVAL;
+       }
+
+       buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
+       period_len = frames_to_bytes(runtime, runtime->period_size);
+
+       cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
+                       period_len, DMA_TO_DEVICE);
+       if (IS_ERR(cdesc)) {
+               dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
+               return PTR_ERR(cdesc);
+       }
+
+       cdesc->period_callback = atmel_abdac_dma_period_done;
+       cdesc->period_callback_param = dac;
+
+       dac->dma.cdesc = cdesc;
+
+       set_bit(DMA_READY, &dac->flags);
+
+       return 0;
+}
+
+static struct snd_pcm_hardware atmel_abdac_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP
+                                 | SNDRV_PCM_INFO_MMAP_VALID
+                                 | SNDRV_PCM_INFO_INTERLEAVED
+                                 | SNDRV_PCM_INFO_BLOCK_TRANSFER
+                                 | SNDRV_PCM_INFO_RESUME
+                                 | SNDRV_PCM_INFO_PAUSE),
+       .formats                = (SNDRV_PCM_FMTBIT_S16_BE),
+       .rates                  = (SNDRV_PCM_RATE_KNOT),
+       .rate_min               = RATE_MIN,
+       .rate_max               = RATE_MAX,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 64 * 4096,
+       .period_bytes_min       = 4096,
+       .period_bytes_max       = 4096,
+       .periods_min            = 4,
+       .periods_max            = 64,
+};
+
+static int atmel_abdac_open(struct snd_pcm_substream *substream)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+
+       dac->substream = substream;
+       atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1];
+       atmel_abdac_hw.rate_min = dac->rates[0];
+       substream->runtime->hw = atmel_abdac_hw;
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates);
+}
+
+static int atmel_abdac_close(struct snd_pcm_substream *substream)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+       dac->substream = NULL;
+       return 0;
+}
+
+static int atmel_abdac_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+       int retval;
+
+       retval = snd_pcm_lib_malloc_pages(substream,
+                       params_buffer_bytes(hw_params));
+       if (retval < 0)
+               return retval;
+       /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+       if (retval == 1)
+               if (test_and_clear_bit(DMA_READY, &dac->flags))
+                       dw_dma_cyclic_free(dac->dma.chan);
+
+       return retval;
+}
+
+static int atmel_abdac_hw_free(struct snd_pcm_substream *substream)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+       if (test_and_clear_bit(DMA_READY, &dac->flags))
+               dw_dma_cyclic_free(dac->dma.chan);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_abdac_prepare(struct snd_pcm_substream *substream)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+       int retval;
+
+       retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate);
+       if (retval)
+               return retval;
+
+       if (!test_bit(DMA_READY, &dac->flags))
+               retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE);
+
+       return retval;
+}
+
+static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+       int retval = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+       case SNDRV_PCM_TRIGGER_START:
+               clk_enable(dac->sample_clk);
+               retval = dw_dma_cyclic_start(dac->dma.chan);
+               if (retval)
+                       goto out;
+               dac_writel(dac, CTRL, DAC_BIT(EN));
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+       case SNDRV_PCM_TRIGGER_STOP:
+               dw_dma_cyclic_stop(dac->dma.chan);
+               dac_writel(dac, DATA, 0);
+               dac_writel(dac, CTRL, 0);
+               clk_disable(dac->sample_clk);
+               break;
+       default:
+               retval = -EINVAL;
+               break;
+       }
+out:
+       return retval;
+}
+
+static snd_pcm_uframes_t
+atmel_abdac_pointer(struct snd_pcm_substream *substream)
+{
+       struct atmel_abdac      *dac = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime  *runtime = substream->runtime;
+       snd_pcm_uframes_t       frames;
+       unsigned long           bytes;
+
+       bytes = dw_dma_get_src_addr(dac->dma.chan);
+       bytes -= runtime->dma_addr;
+
+       frames = bytes_to_frames(runtime, bytes);
+       if (frames >= runtime->buffer_size)
+               frames -= runtime->buffer_size;
+
+       return frames;
+}
+
+static irqreturn_t abdac_interrupt(int irq, void *dev_id)
+{
+       struct atmel_abdac *dac = dev_id;
+       u32 status;
+
+       status = dac_readl(dac, INT_STATUS);
+       if (status & DAC_BIT(UNDERRUN)) {
+               dev_err(&dac->pdev->dev, "underrun detected\n");
+               dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
+       } else {
+               dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n",
+                       status);
+               dac_writel(dac, INT_CLR, status);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct snd_pcm_ops atmel_abdac_ops = {
+       .open           = atmel_abdac_open,
+       .close          = atmel_abdac_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = atmel_abdac_hw_params,
+       .hw_free        = atmel_abdac_hw_free,
+       .prepare        = atmel_abdac_prepare,
+       .trigger        = atmel_abdac_trigger,
+       .pointer        = atmel_abdac_pointer,
+};
+
+static int __devinit atmel_abdac_pcm_new(struct atmel_abdac *dac)
+{
+       struct snd_pcm_hardware hw = atmel_abdac_hw;
+       struct snd_pcm *pcm;
+       int retval;
+
+       retval = snd_pcm_new(dac->card, dac->card->shortname,
+                       dac->pdev->id, 1, 0, &pcm);
+       if (retval)
+               return retval;
+
+       strcpy(pcm->name, dac->card->shortname);
+       pcm->private_data = dac;
+       pcm->info_flags = 0;
+       dac->pcm = pcm;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops);
+
+       retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                       &dac->pdev->dev, hw.periods_min * hw.period_bytes_min,
+                       hw.buffer_bytes_max);
+
+       return retval;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct dw_dma_slave *dws = slave;
+
+       if (dws->dma_dev == chan->device->dev) {
+               chan->private = dws;
+               return true;
+       } else
+               return false;
+}
+
+static int set_sample_rates(struct atmel_abdac *dac)
+{
+       long new_rate = RATE_MAX;
+       int retval = -EINVAL;
+       int index = 0;
+
+       /* we start at 192 kHz and work our way down to 5112 Hz */
+       while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) {
+               new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate);
+               if (new_rate < 0)
+                       break;
+               /* make sure we are below the ABDAC clock */
+               if (new_rate <= clk_get_rate(dac->pclk)) {
+                       dac->rates[index] = new_rate / 256;
+                       index++;
+               }
+               /* divide by 256 and then by two to get next rate */
+               new_rate /= 256 * 2;
+       }
+
+       if (index) {
+               int i;
+
+               /* reverse array, smallest go first */
+               for (i = 0; i < (index / 2); i++) {
+                       unsigned int tmp = dac->rates[index - 1 - i];
+                       dac->rates[index - 1 - i] = dac->rates[i];
+                       dac->rates[i] = tmp;
+               }
+
+               dac->constraints_rates.count = index;
+               dac->constraints_rates.list = dac->rates;
+               dac->constraints_rates.mask = 0;
+               dac->rates_num = index;
+
+               retval = 0;
+       }
+
+       return retval;
+}
+
+static int __devinit atmel_abdac_probe(struct platform_device *pdev)
+{
+       struct snd_card         *card;
+       struct atmel_abdac      *dac;
+       struct resource         *regs;
+       struct atmel_abdac_pdata        *pdata;
+       struct clk              *pclk;
+       struct clk              *sample_clk;
+       int                     retval;
+       int                     irq;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_dbg(&pdev->dev, "no memory resource\n");
+               return -ENXIO;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_dbg(&pdev->dev, "could not get IRQ number\n");
+               return irq;
+       }
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "no platform data\n");
+               return -ENXIO;
+       }
+
+       pclk = clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(pclk)) {
+               dev_dbg(&pdev->dev, "no peripheral clock\n");
+               return PTR_ERR(pclk);
+       }
+       sample_clk = clk_get(&pdev->dev, "sample_clk");
+       if (IS_ERR(pclk)) {
+               dev_dbg(&pdev->dev, "no sample clock\n");
+               retval = PTR_ERR(pclk);
+               goto out_put_pclk;
+       }
+       clk_enable(pclk);
+
+       retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                       THIS_MODULE, sizeof(struct atmel_abdac), &card);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not create sound card device\n");
+               goto out_put_sample_clk;
+       }
+
+       dac = get_dac(card);
+
+       dac->irq = irq;
+       dac->card = card;
+       dac->pclk = pclk;
+       dac->sample_clk = sample_clk;
+       dac->pdev = pdev;
+
+       retval = set_sample_rates(dac);
+       if (retval < 0) {
+               dev_dbg(&pdev->dev, "could not set supported rates\n");
+               goto out_free_card;
+       }
+
+       dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!dac->regs) {
+               dev_dbg(&pdev->dev, "could not remap register memory\n");
+               goto out_free_card;
+       }
+
+       /* make sure the DAC is silent and disabled */
+       dac_writel(dac, DATA, 0);
+       dac_writel(dac, CTRL, 0);
+
+       retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not request irq\n");
+               goto out_unmap_regs;
+       }
+
+       snd_card_set_dev(card, &pdev->dev);
+
+       if (pdata->dws.dma_dev) {
+               struct dw_dma_slave *dws = &pdata->dws;
+               dma_cap_mask_t mask;
+
+               dws->tx_reg = regs->start + DAC_DATA;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+
+               dac->dma.chan = dma_request_channel(mask, filter, dws);
+       }
+       if (!pdata->dws.dma_dev || !dac->dma.chan) {
+               dev_dbg(&pdev->dev, "DMA not available\n");
+               retval = -ENODEV;
+               goto out_unset_card_dev;
+       }
+
+       strcpy(card->driver, "Atmel ABDAC");
+       strcpy(card->shortname, "Atmel ABDAC");
+       sprintf(card->longname, "Atmel Audio Bitstream DAC");
+
+       retval = atmel_abdac_pcm_new(dac);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n");
+               goto out_release_dma;
+       }
+
+       retval = snd_card_register(card);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register sound card\n");
+               goto out_release_dma;
+       }
+
+       platform_set_drvdata(pdev, card);
+
+       dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
+                       dac->regs, dac->dma.chan->dev->device.bus_id);
+
+       return retval;
+
+out_release_dma:
+       dma_release_channel(dac->dma.chan);
+       dac->dma.chan = NULL;
+out_unset_card_dev:
+       snd_card_set_dev(card, NULL);
+       free_irq(irq, dac);
+out_unmap_regs:
+       iounmap(dac->regs);
+out_free_card:
+       snd_card_free(card);
+out_put_sample_clk:
+       clk_put(sample_clk);
+       clk_disable(pclk);
+out_put_pclk:
+       clk_put(pclk);
+       return retval;
+}
+
+#ifdef CONFIG_PM
+static int atmel_abdac_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_abdac *dac = card->private_data;
+
+       dw_dma_cyclic_stop(dac->dma.chan);
+       clk_disable(dac->sample_clk);
+       clk_disable(dac->pclk);
+
+       return 0;
+}
+
+static int atmel_abdac_resume(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_abdac *dac = card->private_data;
+
+       clk_enable(dac->pclk);
+       clk_enable(dac->sample_clk);
+       if (test_bit(DMA_READY, &dac->flags))
+               dw_dma_cyclic_start(dac->dma.chan);
+
+       return 0;
+}
+#else
+#define atmel_abdac_suspend NULL
+#define atmel_abdac_resume NULL
+#endif
+
+static int __devexit atmel_abdac_remove(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_abdac *dac = get_dac(card);
+
+       clk_put(dac->sample_clk);
+       clk_disable(dac->pclk);
+       clk_put(dac->pclk);
+
+       dma_release_channel(dac->dma.chan);
+       dac->dma.chan = NULL;
+       snd_card_set_dev(card, NULL);
+       iounmap(dac->regs);
+       free_irq(dac->irq, dac);
+       snd_card_free(card);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver atmel_abdac_driver = {
+       .remove         = __devexit_p(atmel_abdac_remove),
+       .driver         = {
+               .name   = "atmel_abdac",
+       },
+       .suspend        = atmel_abdac_suspend,
+       .resume         = atmel_abdac_resume,
+};
+
+static int __init atmel_abdac_init(void)
+{
+       return platform_driver_probe(&atmel_abdac_driver,
+                       atmel_abdac_probe);
+}
+module_init(atmel_abdac_init);
+
+static void __exit atmel_abdac_exit(void)
+{
+       platform_driver_unregister(&atmel_abdac_driver);
+}
+module_exit(atmel_abdac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
new file mode 100644 (file)
index 0000000..dd72e00
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ * Driver for the Atmel AC97C controller
+ *
+ * Copyright (C) 2005-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/bitmap.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/atmel-ac97c.h>
+#include <sound/memalloc.h>
+
+#include <linux/dw_dmac.h>
+
+#include "ac97c.h"
+
+enum {
+       DMA_TX_READY = 0,
+       DMA_RX_READY,
+       DMA_TX_CHAN_PRESENT,
+       DMA_RX_CHAN_PRESENT,
+};
+
+/* Serialize access to opened variable */
+static DEFINE_MUTEX(opened_mutex);
+
+struct atmel_ac97c_dma {
+       struct dma_chan                 *rx_chan;
+       struct dma_chan                 *tx_chan;
+};
+
+struct atmel_ac97c {
+       struct clk                      *pclk;
+       struct platform_device          *pdev;
+       struct atmel_ac97c_dma          dma;
+
+       struct snd_pcm_substream        *playback_substream;
+       struct snd_pcm_substream        *capture_substream;
+       struct snd_card                 *card;
+       struct snd_pcm                  *pcm;
+       struct snd_ac97                 *ac97;
+       struct snd_ac97_bus             *ac97_bus;
+
+       u64                             cur_format;
+       unsigned int                    cur_rate;
+       unsigned long                   flags;
+       /* Serialize access to opened variable */
+       spinlock_t                      lock;
+       void __iomem                    *regs;
+       int                             opened;
+       int                             reset_pin;
+};
+
+#define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
+
+#define ac97c_writel(chip, reg, val)                   \
+       __raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg)                         \
+       __raw_readl((chip)->regs + AC97C_##reg)
+
+/* This function is called by the DMA driver. */
+static void atmel_ac97c_dma_playback_period_done(void *arg)
+{
+       struct atmel_ac97c *chip = arg;
+       snd_pcm_period_elapsed(chip->playback_substream);
+}
+
+static void atmel_ac97c_dma_capture_period_done(void *arg)
+{
+       struct atmel_ac97c *chip = arg;
+       snd_pcm_period_elapsed(chip->capture_substream);
+}
+
+static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
+               struct snd_pcm_substream *substream,
+               enum dma_data_direction direction)
+{
+       struct dma_chan                 *chan;
+       struct dw_cyclic_desc           *cdesc;
+       struct snd_pcm_runtime          *runtime = substream->runtime;
+       unsigned long                   buffer_len, period_len;
+
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-halfword-aligned buffers or lengths.
+        */
+       if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
+               dev_dbg(&chip->pdev->dev, "too complex transfer\n");
+               return -EINVAL;
+       }
+
+       if (direction == DMA_TO_DEVICE)
+               chan = chip->dma.tx_chan;
+       else
+               chan = chip->dma.rx_chan;
+
+       buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
+       period_len = frames_to_bytes(runtime, runtime->period_size);
+
+       cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
+                       period_len, direction);
+       if (IS_ERR(cdesc)) {
+               dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
+               return PTR_ERR(cdesc);
+       }
+
+       if (direction == DMA_TO_DEVICE) {
+               cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
+               set_bit(DMA_TX_READY, &chip->flags);
+       } else {
+               cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
+               set_bit(DMA_RX_READY, &chip->flags);
+       }
+
+       cdesc->period_callback_param = chip;
+
+       return 0;
+}
+
+static struct snd_pcm_hardware atmel_ac97c_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP
+                                 | SNDRV_PCM_INFO_MMAP_VALID
+                                 | SNDRV_PCM_INFO_INTERLEAVED
+                                 | SNDRV_PCM_INFO_BLOCK_TRANSFER
+                                 | SNDRV_PCM_INFO_JOINT_DUPLEX
+                                 | SNDRV_PCM_INFO_RESUME
+                                 | SNDRV_PCM_INFO_PAUSE),
+       .formats                = (SNDRV_PCM_FMTBIT_S16_BE
+                                 | SNDRV_PCM_FMTBIT_S16_LE),
+       .rates                  = (SNDRV_PCM_RATE_CONTINUOUS),
+       .rate_min               = 4000,
+       .rate_max               = 48000,
+       .channels_min           = 1,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 64 * 4096,
+       .period_bytes_min       = 4096,
+       .period_bytes_max       = 4096,
+       .periods_min            = 4,
+       .periods_max            = 64,
+};
+
+static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       mutex_lock(&opened_mutex);
+       chip->opened++;
+       runtime->hw = atmel_ac97c_hw;
+       if (chip->cur_rate) {
+               runtime->hw.rate_min = chip->cur_rate;
+               runtime->hw.rate_max = chip->cur_rate;
+       }
+       if (chip->cur_format)
+               runtime->hw.formats = (1ULL << chip->cur_format);
+       mutex_unlock(&opened_mutex);
+       chip->playback_substream = substream;
+       return 0;
+}
+
+static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       mutex_lock(&opened_mutex);
+       chip->opened++;
+       runtime->hw = atmel_ac97c_hw;
+       if (chip->cur_rate) {
+               runtime->hw.rate_min = chip->cur_rate;
+               runtime->hw.rate_max = chip->cur_rate;
+       }
+       if (chip->cur_format)
+               runtime->hw.formats = (1ULL << chip->cur_format);
+       mutex_unlock(&opened_mutex);
+       chip->capture_substream = substream;
+       return 0;
+}
+
+static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+
+       mutex_lock(&opened_mutex);
+       chip->opened--;
+       if (!chip->opened) {
+               chip->cur_rate = 0;
+               chip->cur_format = 0;
+       }
+       mutex_unlock(&opened_mutex);
+
+       chip->playback_substream = NULL;
+
+       return 0;
+}
+
+static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+
+       mutex_lock(&opened_mutex);
+       chip->opened--;
+       if (!chip->opened) {
+               chip->cur_rate = 0;
+               chip->cur_format = 0;
+       }
+       mutex_unlock(&opened_mutex);
+
+       chip->capture_substream = NULL;
+
+       return 0;
+}
+
+static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       int retval;
+
+       retval = snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+       if (retval < 0)
+               return retval;
+       /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+       if (retval == 1)
+               if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+                       dw_dma_cyclic_free(chip->dma.tx_chan);
+
+       /* Set restrictions to params. */
+       mutex_lock(&opened_mutex);
+       chip->cur_rate = params_rate(hw_params);
+       chip->cur_format = params_format(hw_params);
+       mutex_unlock(&opened_mutex);
+
+       return retval;
+}
+
+static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       int retval;
+
+       retval = snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+       if (retval < 0)
+               return retval;
+       /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+       if (retval == 1)
+               if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+                       dw_dma_cyclic_free(chip->dma.rx_chan);
+
+       /* Set restrictions to params. */
+       mutex_lock(&opened_mutex);
+       chip->cur_rate = params_rate(hw_params);
+       chip->cur_format = params_format(hw_params);
+       mutex_unlock(&opened_mutex);
+
+       return retval;
+}
+
+static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+               dw_dma_cyclic_free(chip->dma.tx_chan);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+               dw_dma_cyclic_free(chip->dma.rx_chan);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long word = 0;
+       int retval;
+
+       /* assign channels to AC97C channel A */
+       switch (runtime->channels) {
+       case 1:
+               word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+               break;
+       case 2:
+               word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+                       | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+               break;
+       default:
+               /* TODO: support more than two channels */
+               return -EINVAL;
+               break;
+       }
+       ac97c_writel(chip, OCA, word);
+
+       /* configure sample format and size */
+       word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+
+       switch (runtime->format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               word |= AC97C_CMR_CEM_LITTLE;
+               break;
+       case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
+       default:
+               word &= ~(AC97C_CMR_CEM_LITTLE);
+               break;
+       }
+
+       ac97c_writel(chip, CAMR, word);
+
+       /* set variable rate if needed */
+       if (runtime->rate != 48000) {
+               word = ac97c_readl(chip, MR);
+               word |= AC97C_MR_VRA;
+               ac97c_writel(chip, MR, word);
+       } else {
+               word = ac97c_readl(chip, MR);
+               word &= ~(AC97C_MR_VRA);
+               ac97c_writel(chip, MR, word);
+       }
+
+       retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
+                       runtime->rate);
+       if (retval)
+               dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
+                               runtime->rate);
+
+       if (!test_bit(DMA_TX_READY, &chip->flags))
+               retval = atmel_ac97c_prepare_dma(chip, substream,
+                               DMA_TO_DEVICE);
+
+       return retval;
+}
+
+static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long word = 0;
+       int retval;
+
+       /* assign channels to AC97C channel A */
+       switch (runtime->channels) {
+       case 1:
+               word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+               break;
+       case 2:
+               word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+                       | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+               break;
+       default:
+               /* TODO: support more than two channels */
+               return -EINVAL;
+               break;
+       }
+       ac97c_writel(chip, ICA, word);
+
+       /* configure sample format and size */
+       word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+
+       switch (runtime->format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               word |= AC97C_CMR_CEM_LITTLE;
+               break;
+       case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
+       default:
+               word &= ~(AC97C_CMR_CEM_LITTLE);
+               break;
+       }
+
+       ac97c_writel(chip, CAMR, word);
+
+       /* set variable rate if needed */
+       if (runtime->rate != 48000) {
+               word = ac97c_readl(chip, MR);
+               word |= AC97C_MR_VRA;
+               ac97c_writel(chip, MR, word);
+       } else {
+               word = ac97c_readl(chip, MR);
+               word &= ~(AC97C_MR_VRA);
+               ac97c_writel(chip, MR, word);
+       }
+
+       retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
+                       runtime->rate);
+       if (retval)
+               dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
+                               runtime->rate);
+
+       if (!test_bit(DMA_RX_READY, &chip->flags))
+               retval = atmel_ac97c_prepare_dma(chip, substream,
+                               DMA_FROM_DEVICE);
+
+       return retval;
+}
+
+static int
+atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       unsigned long camr;
+       int retval = 0;
+
+       camr = ac97c_readl(chip, CAMR);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+       case SNDRV_PCM_TRIGGER_START:
+               retval = dw_dma_cyclic_start(chip->dma.tx_chan);
+               if (retval)
+                       goto out;
+               camr |= AC97C_CMR_CENA;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+       case SNDRV_PCM_TRIGGER_STOP:
+               dw_dma_cyclic_stop(chip->dma.tx_chan);
+               if (chip->opened <= 1)
+                       camr &= ~AC97C_CMR_CENA;
+               break;
+       default:
+               retval = -EINVAL;
+               goto out;
+       }
+
+       ac97c_writel(chip, CAMR, camr);
+out:
+       return retval;
+}
+
+static int
+atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+       unsigned long camr;
+       int retval = 0;
+
+       camr = ac97c_readl(chip, CAMR);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+       case SNDRV_PCM_TRIGGER_START:
+               retval = dw_dma_cyclic_start(chip->dma.rx_chan);
+               if (retval)
+                       goto out;
+               camr |= AC97C_CMR_CENA;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+       case SNDRV_PCM_TRIGGER_STOP:
+               dw_dma_cyclic_stop(chip->dma.rx_chan);
+               if (chip->opened <= 1)
+                       camr &= ~AC97C_CMR_CENA;
+               break;
+       default:
+               retval = -EINVAL;
+               break;
+       }
+
+       ac97c_writel(chip, CAMR, camr);
+out:
+       return retval;
+}
+
+static snd_pcm_uframes_t
+atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c      *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime  *runtime = substream->runtime;
+       snd_pcm_uframes_t       frames;
+       unsigned long           bytes;
+
+       bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+       bytes -= runtime->dma_addr;
+
+       frames = bytes_to_frames(runtime, bytes);
+       if (frames >= runtime->buffer_size)
+               frames -= runtime->buffer_size;
+       return frames;
+}
+
+static snd_pcm_uframes_t
+atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
+{
+       struct atmel_ac97c      *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime  *runtime = substream->runtime;
+       snd_pcm_uframes_t       frames;
+       unsigned long           bytes;
+
+       bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+       bytes -= runtime->dma_addr;
+
+       frames = bytes_to_frames(runtime, bytes);
+       if (frames >= runtime->buffer_size)
+               frames -= runtime->buffer_size;
+       return frames;
+}
+
+static struct snd_pcm_ops atmel_ac97_playback_ops = {
+       .open           = atmel_ac97c_playback_open,
+       .close          = atmel_ac97c_playback_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = atmel_ac97c_playback_hw_params,
+       .hw_free        = atmel_ac97c_playback_hw_free,
+       .prepare        = atmel_ac97c_playback_prepare,
+       .trigger        = atmel_ac97c_playback_trigger,
+       .pointer        = atmel_ac97c_playback_pointer,
+};
+
+static struct snd_pcm_ops atmel_ac97_capture_ops = {
+       .open           = atmel_ac97c_capture_open,
+       .close          = atmel_ac97c_capture_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = atmel_ac97c_capture_hw_params,
+       .hw_free        = atmel_ac97c_capture_hw_free,
+       .prepare        = atmel_ac97c_capture_prepare,
+       .trigger        = atmel_ac97c_capture_trigger,
+       .pointer        = atmel_ac97c_capture_pointer,
+};
+
+static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
+{
+       struct snd_pcm          *pcm;
+       struct snd_pcm_hardware hw = atmel_ac97c_hw;
+       int                     capture, playback, retval;
+
+       capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+       playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+
+       retval = snd_pcm_new(chip->card, chip->card->shortname,
+                       chip->pdev->id, playback, capture, &pcm);
+       if (retval)
+               return retval;
+
+       if (capture)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                               &atmel_ac97_capture_ops);
+       if (playback)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                               &atmel_ac97_playback_ops);
+
+       retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                       &chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
+                       hw.buffer_bytes_max);
+       if (retval)
+               return retval;
+
+       pcm->private_data = chip;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, chip->card->shortname);
+       chip->pcm = pcm;
+
+       return 0;
+}
+
+static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
+{
+       struct snd_ac97_template template;
+       memset(&template, 0, sizeof(template));
+       template.private_data = chip;
+       return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+}
+
+static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
+               unsigned short val)
+{
+       struct atmel_ac97c *chip = get_chip(ac97);
+       unsigned long word;
+       int timeout = 40;
+
+       word = (reg & 0x7f) << 16 | val;
+
+       do {
+               if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
+                       ac97c_writel(chip, COTHR, word);
+                       return;
+               }
+               udelay(1);
+       } while (--timeout);
+
+       dev_dbg(&chip->pdev->dev, "codec write timeout\n");
+}
+
+static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
+               unsigned short reg)
+{
+       struct atmel_ac97c *chip = get_chip(ac97);
+       unsigned long word;
+       int timeout = 40;
+       int write = 10;
+
+       word = (0x80 | (reg & 0x7f)) << 16;
+
+       if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
+               ac97c_readl(chip, CORHR);
+
+retry_write:
+       timeout = 40;
+
+       do {
+               if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
+                       ac97c_writel(chip, COTHR, word);
+                       goto read_reg;
+               }
+               udelay(10);
+       } while (--timeout);
+
+       if (!--write)
+               goto timed_out;
+       goto retry_write;
+
+read_reg:
+       do {
+               if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
+                       unsigned short val = ac97c_readl(chip, CORHR);
+                       return val;
+               }
+               udelay(10);
+       } while (--timeout);
+
+       if (!--write)
+               goto timed_out;
+       goto retry_write;
+
+timed_out:
+       dev_dbg(&chip->pdev->dev, "codec read timeout\n");
+       return 0xffff;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct dw_dma_slave *dws = slave;
+
+       if (dws->dma_dev == chan->device->dev) {
+               chan->private = dws;
+               return true;
+       } else
+               return false;
+}
+
+static void atmel_ac97c_reset(struct atmel_ac97c *chip)
+{
+       ac97c_writel(chip, MR, AC97C_MR_WRST);
+
+       if (gpio_is_valid(chip->reset_pin)) {
+               gpio_set_value(chip->reset_pin, 0);
+               /* AC97 v2.2 specifications says minimum 1 us. */
+               udelay(10);
+               gpio_set_value(chip->reset_pin, 1);
+       }
+
+       udelay(1);
+       ac97c_writel(chip, MR, AC97C_MR_ENA);
+}
+
+static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
+{
+       struct snd_card                 *card;
+       struct atmel_ac97c              *chip;
+       struct resource                 *regs;
+       struct ac97c_platform_data      *pdata;
+       struct clk                      *pclk;
+       static struct snd_ac97_bus_ops  ops = {
+               .write  = atmel_ac97c_write,
+               .read   = atmel_ac97c_read,
+       };
+       int                             retval;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_dbg(&pdev->dev, "no memory resource\n");
+               return -ENXIO;
+       }
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "no platform data\n");
+               return -ENXIO;
+       }
+
+       pclk = clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(pclk)) {
+               dev_dbg(&pdev->dev, "no peripheral clock\n");
+               return PTR_ERR(pclk);
+       }
+       clk_enable(pclk);
+
+       retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                       THIS_MODULE, sizeof(struct atmel_ac97c), &card);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not create sound card device\n");
+               goto err_snd_card_new;
+       }
+
+       chip = get_chip(card);
+
+       spin_lock_init(&chip->lock);
+
+       strcpy(card->driver, "Atmel AC97C");
+       strcpy(card->shortname, "Atmel AC97C");
+       sprintf(card->longname, "Atmel AC97 controller");
+
+       chip->card = card;
+       chip->pclk = pclk;
+       chip->pdev = pdev;
+       chip->regs = ioremap(regs->start, regs->end - regs->start + 1);
+
+       if (!chip->regs) {
+               dev_dbg(&pdev->dev, "could not remap register memory\n");
+               goto err_ioremap;
+       }
+
+       if (gpio_is_valid(pdata->reset_pin)) {
+               if (gpio_request(pdata->reset_pin, "reset_pin")) {
+                       dev_dbg(&pdev->dev, "reset pin not available\n");
+                       chip->reset_pin = -ENODEV;
+               } else {
+                       gpio_direction_output(pdata->reset_pin, 1);
+                       chip->reset_pin = pdata->reset_pin;
+               }
+       }
+
+       snd_card_set_dev(card, &pdev->dev);
+
+       retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
+               goto err_ac97_bus;
+       }
+
+       atmel_ac97c_reset(chip);
+
+       retval = atmel_ac97c_mixer_new(chip);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
+               goto err_ac97_bus;
+       }
+
+       if (pdata->rx_dws.dma_dev) {
+               struct dw_dma_slave *dws = &pdata->rx_dws;
+               dma_cap_mask_t mask;
+
+               dws->rx_reg = regs->start + AC97C_CARHR + 2;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+
+               chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
+
+               dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
+                                       chip->dma.rx_chan->dev->device.bus_id);
+               set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+       }
+
+       if (pdata->tx_dws.dma_dev) {
+               struct dw_dma_slave *dws = &pdata->tx_dws;
+               dma_cap_mask_t mask;
+
+               dws->tx_reg = regs->start + AC97C_CATHR + 2;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+
+               chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
+
+               dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
+                                       chip->dma.tx_chan->dev->device.bus_id);
+               set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+       }
+
+       if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
+                       !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
+               dev_dbg(&pdev->dev, "DMA not available\n");
+               retval = -ENODEV;
+               goto err_dma;
+       }
+
+       retval = atmel_ac97c_pcm_new(chip);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
+               goto err_dma;
+       }
+
+       retval = snd_card_register(card);
+       if (retval) {
+               dev_dbg(&pdev->dev, "could not register sound card\n");
+               goto err_ac97_bus;
+       }
+
+       platform_set_drvdata(pdev, card);
+
+       dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
+                       chip->regs);
+
+       return 0;
+
+err_dma:
+       if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+               dma_release_channel(chip->dma.rx_chan);
+       if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+               dma_release_channel(chip->dma.tx_chan);
+       clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+       clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+       chip->dma.rx_chan = NULL;
+       chip->dma.tx_chan = NULL;
+err_ac97_bus:
+       snd_card_set_dev(card, NULL);
+
+       if (gpio_is_valid(chip->reset_pin))
+               gpio_free(chip->reset_pin);
+
+       iounmap(chip->regs);
+err_ioremap:
+       snd_card_free(card);
+err_snd_card_new:
+       clk_disable(pclk);
+       clk_put(pclk);
+       return retval;
+}
+
+#ifdef CONFIG_PM
+static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_ac97c *chip = card->private_data;
+
+       if (test_bit(DMA_RX_READY, &chip->flags))
+               dw_dma_cyclic_stop(chip->dma.rx_chan);
+       if (test_bit(DMA_TX_READY, &chip->flags))
+               dw_dma_cyclic_stop(chip->dma.tx_chan);
+       clk_disable(chip->pclk);
+
+       return 0;
+}
+
+static int atmel_ac97c_resume(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_ac97c *chip = card->private_data;
+
+       clk_enable(chip->pclk);
+       if (test_bit(DMA_RX_READY, &chip->flags))
+               dw_dma_cyclic_start(chip->dma.rx_chan);
+       if (test_bit(DMA_TX_READY, &chip->flags))
+               dw_dma_cyclic_start(chip->dma.tx_chan);
+
+       return 0;
+}
+#else
+#define atmel_ac97c_suspend NULL
+#define atmel_ac97c_resume NULL
+#endif
+
+static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct atmel_ac97c *chip = get_chip(card);
+
+       if (gpio_is_valid(chip->reset_pin))
+               gpio_free(chip->reset_pin);
+
+       clk_disable(chip->pclk);
+       clk_put(chip->pclk);
+       iounmap(chip->regs);
+
+       if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+               dma_release_channel(chip->dma.rx_chan);
+       if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+               dma_release_channel(chip->dma.tx_chan);
+       clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+       clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+       chip->dma.rx_chan = NULL;
+       chip->dma.tx_chan = NULL;
+
+       snd_card_set_dev(card, NULL);
+       snd_card_free(card);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver atmel_ac97c_driver = {
+       .remove         = __devexit_p(atmel_ac97c_remove),
+       .driver         = {
+               .name   = "atmel_ac97c",
+       },
+       .suspend        = atmel_ac97c_suspend,
+       .resume         = atmel_ac97c_resume,
+};
+
+static int __init atmel_ac97c_init(void)
+{
+       return platform_driver_probe(&atmel_ac97c_driver,
+                       atmel_ac97c_probe);
+}
+module_init(atmel_ac97c_init);
+
+static void __exit atmel_ac97c_exit(void)
+{
+       platform_driver_unregister(&atmel_ac97c_driver);
+}
+module_exit(atmel_ac97c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
diff --git a/sound/atmel/ac97c.h b/sound/atmel/ac97c.h
new file mode 100644 (file)
index 0000000..c17bd58
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Register definitions for the Atmel AC97C controller
+ *
+ * Copyright (C) 2005-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __SOUND_ATMEL_AC97C_H
+#define __SOUND_ATMEL_AC97C_H
+
+#define AC97C_MR               0x08
+#define AC97C_ICA              0x10
+#define AC97C_OCA              0x14
+#define AC97C_CARHR            0x20
+#define AC97C_CATHR            0x24
+#define AC97C_CASR             0x28
+#define AC97C_CAMR             0x2c
+#define AC97C_CBRHR            0x30
+#define AC97C_CBTHR            0x34
+#define AC97C_CBSR             0x38
+#define AC97C_CBMR             0x3c
+#define AC97C_CORHR            0x40
+#define AC97C_COTHR            0x44
+#define AC97C_COSR             0x48
+#define AC97C_COMR             0x4c
+#define AC97C_SR               0x50
+#define AC97C_IER              0x54
+#define AC97C_IDR              0x58
+#define AC97C_IMR              0x5c
+#define AC97C_VERSION          0xfc
+
+#define AC97C_CATPR            PDC_TPR
+#define AC97C_CATCR            PDC_TCR
+#define AC97C_CATNPR           PDC_TNPR
+#define AC97C_CATNCR           PDC_TNCR
+#define AC97C_CARPR            PDC_RPR
+#define AC97C_CARCR            PDC_RCR
+#define AC97C_CARNPR           PDC_RNPR
+#define AC97C_CARNCR           PDC_RNCR
+#define AC97C_PTCR             PDC_PTCR
+
+#define AC97C_MR_ENA           (1 << 0)
+#define AC97C_MR_WRST          (1 << 1)
+#define AC97C_MR_VRA           (1 << 2)
+
+#define AC97C_CSR_TXRDY                (1 << 0)
+#define AC97C_CSR_UNRUN                (1 << 2)
+#define AC97C_CSR_RXRDY                (1 << 4)
+#define AC97C_CSR_ENDTX                (1 << 10)
+#define AC97C_CSR_ENDRX                (1 << 14)
+
+#define AC97C_CMR_SIZE_20      (0 << 16)
+#define AC97C_CMR_SIZE_18      (1 << 16)
+#define AC97C_CMR_SIZE_16      (2 << 16)
+#define AC97C_CMR_SIZE_10      (3 << 16)
+#define AC97C_CMR_CEM_LITTLE   (1 << 18)
+#define AC97C_CMR_CEM_BIG      (0 << 18)
+#define AC97C_CMR_CENA         (1 << 21)
+#define AC97C_CMR_DMAEN                (1 << 22)
+
+#define AC97C_SR_CAEVT         (1 << 3)
+
+#define AC97C_CH_ASSIGN(slot, channel)                                 \
+       (AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
+#define AC97C_CHANNEL_NONE     0x0
+#define AC97C_CHANNEL_A                0x1
+#define AC97C_CHANNEL_B                0x2
+
+#endif /* __SOUND_ATMEL_AC97C_H */
index 195cafc5a55342df53e01a4ecb361a37db178dbd..a70ee7f1ed9832ed3ef3b4463376786dd2500234 100644 (file)
@@ -99,9 +99,6 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
        if (hw == NULL)
                return -ENODEV;
 
-       if (!hw->ops.open)
-               return -ENXIO;
-
        if (!try_module_get(hw->card->module))
                return -EFAULT;
 
@@ -113,6 +110,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
                        err = -EBUSY;
                        break;
                }
+               if (!hw->ops.open) {
+                       err = 0;
+                       break;
+               }
                err = hw->ops.open(hw, file);
                if (err >= 0)
                        break;
@@ -151,7 +152,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
 
 static int snd_hwdep_release(struct inode *inode, struct file * file)
 {
-       int err = -ENXIO;
+       int err = 0;
        struct snd_hwdep *hw = file->private_data;
        struct module *mod = hw->card->module;
 
index 0d5520c415d3ad77258221cc4ebbdc25f6799def..fd56afe846ed6321d71e328147a5659423e2bce2 100644 (file)
@@ -121,31 +121,44 @@ static inline int init_info_for_card(struct snd_card *card)
 #endif
 
 /**
- *  snd_card_new - create and initialize a soundcard structure
+ *  snd_card_create - create and initialize a soundcard structure
  *  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
  *  @xid: card identification (ASCII string)
  *  @module: top level module for locking
  *  @extra_size: allocate this extra size after the main soundcard structure
+ *  @card_ret: the pointer to store the created card instance
  *
  *  Creates and initializes a soundcard structure.
  *
- *  Returns kmallocated snd_card structure. Creates the ALSA control interface
- *  (which is blocked until snd_card_register function is called).
+ *  The function allocates snd_card instance via kzalloc with the given
+ *  space for the driver to use freely.  The allocated struct is stored
+ *  in the given card_ret pointer.
+ *
+ *  Returns zero if successful or a negative error code.
  */
-struct snd_card *snd_card_new(int idx, const char *xid,
-                        struct module *module, int extra_size)
+int snd_card_create(int idx, const char *xid,
+                   struct module *module, int extra_size,
+                   struct snd_card **card_ret)
 {
        struct snd_card *card;
        int err, idx2;
 
+       if (snd_BUG_ON(!card_ret))
+               return -EINVAL;
+       *card_ret = NULL;
+
        if (extra_size < 0)
                extra_size = 0;
        card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
-       if (card == NULL)
-               return NULL;
+       if (!card)
+               return -ENOMEM;
        if (xid) {
-               if (!snd_info_check_reserved_words(xid))
+               if (!snd_info_check_reserved_words(xid)) {
+                       snd_printk(KERN_ERR
+                                  "given id string '%s' is reserved.\n", xid);
+                       err = -EBUSY;
                        goto __error;
+               }
                strlcpy(card->id, xid, sizeof(card->id));
        }
        err = 0;
@@ -195,6 +208,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
        INIT_LIST_HEAD(&card->controls);
        INIT_LIST_HEAD(&card->ctl_files);
        spin_lock_init(&card->files_lock);
+       INIT_LIST_HEAD(&card->files_list);
        init_waitqueue_head(&card->shutdown_sleep);
 #ifdef CONFIG_PM
        mutex_init(&card->power_lock);
@@ -202,26 +216,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
 #endif
        /* the control interface cannot be accessed from the user space until */
        /* snd_cards_bitmask and snd_cards are set with snd_card_register */
-       if ((err = snd_ctl_create(card)) < 0) {
-               snd_printd("unable to register control minors\n");
+       err = snd_ctl_create(card);
+       if (err < 0) {
+               snd_printk(KERN_ERR "unable to register control minors\n");
                goto __error;
        }
-       if ((err = snd_info_card_create(card)) < 0) {
-               snd_printd("unable to create card info\n");
+       err = snd_info_card_create(card);
+       if (err < 0) {
+               snd_printk(KERN_ERR "unable to create card info\n");
                goto __error_ctl;
        }
        if (extra_size > 0)
                card->private_data = (char *)card + sizeof(struct snd_card);
-       return card;
+       *card_ret = card;
+       return 0;
 
       __error_ctl:
        snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
       __error:
        kfree(card);
-       return NULL;
+       return err;
 }
-
-EXPORT_SYMBOL(snd_card_new);
+EXPORT_SYMBOL(snd_card_create);
 
 /* return non-zero if a card is already locked */
 int snd_card_locked(int card)
@@ -259,6 +275,7 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
        list_for_each_entry(_df, &shutdown_files, shutdown_list) {
                if (_df->file == file) {
                        df = _df;
+                       list_del_init(&df->shutdown_list);
                        break;
                }
        }
@@ -347,8 +364,7 @@ int snd_card_disconnect(struct snd_card *card)
        /* phase 2: replace file->f_op with special dummy operations */
        
        spin_lock(&card->files_lock);
-       mfile = card->files;
-       while (mfile) {
+       list_for_each_entry(mfile, &card->files_list, list) {
                file = mfile->file;
 
                /* it's critical part, use endless loop */
@@ -361,8 +377,6 @@ int snd_card_disconnect(struct snd_card *card)
 
                mfile->file->f_op = &snd_shutdown_f_ops;
                fops_get(mfile->file->f_op);
-               
-               mfile = mfile->next;
        }
        spin_unlock(&card->files_lock); 
 
@@ -442,7 +456,7 @@ int snd_card_free_when_closed(struct snd_card *card)
                return ret;
 
        spin_lock(&card->files_lock);
-       if (card->files == NULL)
+       if (list_empty(&card->files_list))
                free_now = 1;
        else
                card->free_on_last_close = 1;
@@ -462,7 +476,7 @@ int snd_card_free(struct snd_card *card)
                return ret;
 
        /* wait, until all devices are ready for the free operation */
-       wait_event(card->shutdown_sleep, card->files == NULL);
+       wait_event(card->shutdown_sleep, list_empty(&card->files_list));
        snd_card_do_free(card);
        return 0;
 }
@@ -809,15 +823,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
                return -ENOMEM;
        mfile->file = file;
        mfile->disconnected_f_op = NULL;
-       mfile->next = NULL;
        spin_lock(&card->files_lock);
        if (card->shutdown) {
                spin_unlock(&card->files_lock);
                kfree(mfile);
                return -ENODEV;
        }
-       mfile->next = card->files;
-       card->files = mfile;
+       list_add(&mfile->list, &card->files_list);
        spin_unlock(&card->files_lock);
        return 0;
 }
@@ -839,29 +851,20 @@ EXPORT_SYMBOL(snd_card_file_add);
  */
 int snd_card_file_remove(struct snd_card *card, struct file *file)
 {
-       struct snd_monitor_file *mfile, *pfile = NULL;
+       struct snd_monitor_file *mfile, *found = NULL;
        int last_close = 0;
 
        spin_lock(&card->files_lock);
-       mfile = card->files;
-       while (mfile) {
+       list_for_each_entry(mfile, &card->files_list, list) {
                if (mfile->file == file) {
-                       if (pfile)
-                               pfile->next = mfile->next;
-                       else
-                               card->files = mfile->next;
+                       list_del(&mfile->list);
+                       if (mfile->disconnected_f_op)
+                               fops_put(mfile->disconnected_f_op);
+                       found = mfile;
                        break;
                }
-               pfile = mfile;
-               mfile = mfile->next;
-       }
-       if (mfile && mfile->disconnected_f_op) {
-               fops_put(mfile->disconnected_f_op);
-               spin_lock(&shutdown_lock);
-               list_del(&mfile->shutdown_list);
-               spin_unlock(&shutdown_lock);
        }
-       if (card->files == NULL)
+       if (list_empty(&card->files_list))
                last_close = 1;
        spin_unlock(&card->files_lock);
        if (last_close) {
@@ -869,11 +872,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
                if (card->free_on_last_close)
                        snd_card_do_free(card);
        }
-       if (!mfile) {
+       if (!found) {
                snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
                return -ENOENT;
        }
-       kfree(mfile);
+       kfree(found);
        return 0;
 }
 
index 077a85262c1c2592c8323b6f249fc645aaf5ecc7..c8254c667c6247cef5e402161b0b1ef076782a5e 100644 (file)
 #include <sound/jack.h>
 #include <sound/core.h>
 
+static int jack_types[] = {
+       SW_HEADPHONE_INSERT,
+       SW_MICROPHONE_INSERT,
+       SW_LINEOUT_INSERT,
+       SW_JACK_PHYSICAL_INSERT,
+       SW_VIDEOOUT_INSERT,
+};
+
 static int snd_jack_dev_free(struct snd_device *device)
 {
        struct snd_jack *jack = device->device_data;
@@ -79,6 +87,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 {
        struct snd_jack *jack;
        int err;
+       int i;
        static struct snd_device_ops ops = {
                .dev_free = snd_jack_dev_free,
                .dev_register = snd_jack_dev_register,
@@ -100,18 +109,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 
        jack->type = type;
 
-       if (type & SND_JACK_HEADPHONE)
-               input_set_capability(jack->input_dev, EV_SW,
-                                    SW_HEADPHONE_INSERT);
-       if (type & SND_JACK_LINEOUT)
-               input_set_capability(jack->input_dev, EV_SW,
-                                    SW_LINEOUT_INSERT);
-       if (type & SND_JACK_MICROPHONE)
-               input_set_capability(jack->input_dev, EV_SW,
-                                    SW_MICROPHONE_INSERT);
-       if (type & SND_JACK_MECHANICAL)
-               input_set_capability(jack->input_dev, EV_SW,
-                                    SW_JACK_PHYSICAL_INSERT);
+       for (i = 0; i < ARRAY_SIZE(jack_types); i++)
+               if (type & (1 << i))
+                       input_set_capability(jack->input_dev, EV_SW,
+                                            jack_types[i]);
 
        err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
        if (err < 0)
@@ -154,21 +155,17 @@ EXPORT_SYMBOL(snd_jack_set_parent);
  */
 void snd_jack_report(struct snd_jack *jack, int status)
 {
+       int i;
+
        if (!jack)
                return;
 
-       if (jack->type & SND_JACK_HEADPHONE)
-               input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
-                                   status & SND_JACK_HEADPHONE);
-       if (jack->type & SND_JACK_LINEOUT)
-               input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
-                                   status & SND_JACK_LINEOUT);
-       if (jack->type & SND_JACK_MICROPHONE)
-               input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
-                                   status & SND_JACK_MICROPHONE);
-       if (jack->type & SND_JACK_MECHANICAL)
-               input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT,
-                                   status & SND_JACK_MECHANICAL);
+       for (i = 0; i < ARRAY_SIZE(jack_types); i++) {
+               int testbit = 1 << i;
+               if (jack->type & testbit)
+                       input_report_switch(jack->input_dev, jack_types[i],
+                                           status & testbit);
+       }
 
        input_sync(jack->input_dev);
 }
index 38524f615d9428fc5f8614e9e6b5752eb430fc14..a9710e0c97afe74e800660fe1697c9d100c18539 100644 (file)
@@ -95,12 +95,14 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
 {
        const struct snd_pci_quirk *q;
 
-       for (q = list; q->subvendor; q++)
-               if (q->subvendor == pci->subsystem_vendor &&
-                   (!q->subdevice || q->subdevice == pci->subsystem_device))
+       for (q = list; q->subvendor; q++) {
+               if (q->subvendor != pci->subsystem_vendor)
+                       continue;
+               if (!q->subdevice ||
+                   (pci->subsystem_device & q->subdevice_mask) == q->subdevice)
                        return q;
+       }
        return NULL;
 }
-
 EXPORT_SYMBOL(snd_pci_quirk_lookup);
 #endif
index 699d2890535ccb9a5280ce6173980308602d6c26..2864cefb773c0af4323fceb6929f2ac3337424a0 100644 (file)
@@ -1160,9 +1160,11 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk("pcm_oss: write: recovering from XRUN\n");
+                               printk(KERN_DEBUG "pcm_oss: write: "
+                                      "recovering from XRUN\n");
                        else
-                               printk("pcm_oss: write: recovering from SUSPEND\n");
+                               printk(KERN_DEBUG "pcm_oss: write: "
+                                      "recovering from SUSPEND\n");
 #endif
                        ret = snd_pcm_oss_prepare(substream);
                        if (ret < 0)
@@ -1196,9 +1198,11 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk("pcm_oss: read: recovering from XRUN\n");
+                               printk(KERN_DEBUG "pcm_oss: read: "
+                                      "recovering from XRUN\n");
                        else
-                               printk("pcm_oss: read: recovering from SUSPEND\n");
+                               printk(KERN_DEBUG "pcm_oss: read: "
+                                      "recovering from SUSPEND\n");
 #endif
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
                        if (ret < 0)
@@ -1242,9 +1246,11 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk("pcm_oss: writev: recovering from XRUN\n");
+                               printk(KERN_DEBUG "pcm_oss: writev: "
+                                      "recovering from XRUN\n");
                        else
-                               printk("pcm_oss: writev: recovering from SUSPEND\n");
+                               printk(KERN_DEBUG "pcm_oss: writev: "
+                                      "recovering from SUSPEND\n");
 #endif
                        ret = snd_pcm_oss_prepare(substream);
                        if (ret < 0)
@@ -1278,9 +1284,11 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk("pcm_oss: readv: recovering from XRUN\n");
+                               printk(KERN_DEBUG "pcm_oss: readv: "
+                                      "recovering from XRUN\n");
                        else
-                               printk("pcm_oss: readv: recovering from SUSPEND\n");
+                               printk(KERN_DEBUG "pcm_oss: readv: "
+                                      "recovering from SUSPEND\n");
 #endif
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
                        if (ret < 0)
@@ -1533,7 +1541,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&runtime->sleep, &wait);
 #ifdef OSS_DEBUG
-       printk("sync1: size = %li\n", size);
+       printk(KERN_DEBUG "sync1: size = %li\n", size);
 #endif
        while (1) {
                result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@@ -1590,7 +1598,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                mutex_lock(&runtime->oss.params_lock);
                if (runtime->oss.buffer_used > 0) {
 #ifdef OSS_DEBUG
-                       printk("sync: buffer_used\n");
+                       printk(KERN_DEBUG "sync: buffer_used\n");
 #endif
                        size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
                        snd_pcm_format_set_silence(format,
@@ -1603,7 +1611,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                        }
                } else if (runtime->oss.period_ptr > 0) {
 #ifdef OSS_DEBUG
-                       printk("sync: period_ptr\n");
+                       printk(KERN_DEBUG "sync: period_ptr\n");
 #endif
                        size = runtime->oss.period_bytes - runtime->oss.period_ptr;
                        snd_pcm_format_set_silence(format,
@@ -1952,7 +1960,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
        int err, cmd;
 
 #ifdef OSS_DEBUG
-       printk("pcm_oss: trigger = 0x%x\n", trigger);
+       printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
 #endif
        
        psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -2170,7 +2178,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
        }
 
 #ifdef OSS_DEBUG
-       printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
+       printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
+              "fragstotal = %i, fragsize = %i\n",
+              info.bytes, info.fragments, info.fragstotal, info.fragsize);
 #endif
        if (copy_to_user(_info, &info, sizeof(info)))
                return -EFAULT;
@@ -2473,7 +2483,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
        if (((cmd >> 8) & 0xff) != 'P')
                return -EINVAL;
 #ifdef OSS_DEBUG
-       printk("pcm_oss: ioctl = 0x%x\n", cmd);
+       printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
 #endif
        switch (cmd) {
        case SNDCTL_DSP_RESET:
@@ -2627,7 +2637,8 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
 #else
        {
                ssize_t res = snd_pcm_oss_read1(substream, buf, count);
-               printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
+               printk(KERN_DEBUG "pcm_oss: read %li bytes "
+                      "(returned %li bytes)\n", (long)count, (long)res);
                return res;
        }
 #endif
@@ -2646,7 +2657,8 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
        substream->f_flags = file->f_flags & O_NONBLOCK;
        result = snd_pcm_oss_write1(substream, buf, count);
 #ifdef OSS_DEBUG
-       printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
+       printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
+              (long)count, (long)result);
 #endif
        return result;
 }
@@ -2720,7 +2732,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
        int err;
 
 #ifdef OSS_DEBUG
-       printk("pcm_oss: mmap begin\n");
+       printk(KERN_DEBUG "pcm_oss: mmap begin\n");
 #endif
        pcm_oss_file = file->private_data;
        switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@@ -2770,7 +2782,8 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
 #ifdef OSS_DEBUG
-       printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
+       printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
+              runtime->oss.mmap_bytes);
 #endif
        /* In mmap mode we never stop */
        runtime->stop_threshold = runtime->boundary;
index ca2f4c39be46e43e3dbb104b5ea1f0e3cc6684b3..b9afab6037115db1e5f6ab08f9836c4262047e2a 100644 (file)
@@ -176,9 +176,9 @@ static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_
 #endif
 
 #ifdef PLUGIN_DEBUG
-#define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
+#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
 #else
-#define pdprintf( fmt, args... ) 
+#define pdprintf(fmt, args...)
 #endif
 
 #endif                         /* __PCM_PLUGIN_H */
index 192a433a240309bd1ce4e977cfa3c6f34d646a85..145931a9ff302fa6b696a137b1036d8a125c540a 100644 (file)
@@ -667,7 +667,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                spin_lock_init(&substream->self_group.lock);
                INIT_LIST_HEAD(&substream->self_group.substreams);
                list_add_tail(&substream->link_list, &substream->self_group.substreams);
-               spin_lock_init(&substream->timer_lock);
                atomic_set(&substream->mmap_count, 0);
                prev = substream;
        }
@@ -692,7 +691,7 @@ EXPORT_SYMBOL(snd_pcm_new_stream);
  *
  * Returns zero if successful, or a negative error code on failure.
  */
-int snd_pcm_new(struct snd_card *card, char *id, int device,
+int snd_pcm_new(struct snd_card *card, const char *id, int device,
                int playback_count, int capture_count,
                struct snd_pcm ** rpcm)
 {
index 921691080f35ff8301301507b9259ae9c89d400f..fbb2e391591ea2c1a5e1933c65f6b946e7a0bd2c 100644 (file)
@@ -125,23 +125,32 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
        }
 }
 
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define xrun_debug(substream)  ((substream)->pstr->xrun_debug)
+#else
+#define xrun_debug(substream)  0
+#endif
+
+#define dump_stack_on_xrun(substream) do {     \
+               if (xrun_debug(substream) > 1)  \
+                       dump_stack();           \
+       } while (0)
+
 static void xrun(struct snd_pcm_substream *substream)
 {
        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       if (substream->pstr->xrun_debug) {
+       if (xrun_debug(substream)) {
                snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
                           substream->pcm->card->number,
                           substream->pcm->device,
                           substream->stream ? 'c' : 'p');
-               if (substream->pstr->xrun_debug > 1)
-                       dump_stack();
+               dump_stack_on_xrun(substream);
        }
-#endif
 }
 
-static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
-                                                         struct snd_pcm_runtime *runtime)
+static snd_pcm_uframes_t
+snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
+                         struct snd_pcm_runtime *runtime)
 {
        snd_pcm_uframes_t pos;
 
@@ -150,17 +159,21 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
        pos = substream->ops->pointer(substream);
        if (pos == SNDRV_PCM_POS_XRUN)
                return pos; /* XRUN */
-#ifdef CONFIG_SND_DEBUG
        if (pos >= runtime->buffer_size) {
-               snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
+               if (printk_ratelimit()) {
+                       snd_printd(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, "
+                                  "buffer size = 0x%lx, period size = 0x%lx\n",
+                                  substream->stream, pos, runtime->buffer_size,
+                                  runtime->period_size);
+               }
+               pos = 0;
        }
-#endif
        pos -= pos % runtime->min_align;
        return pos;
 }
 
-static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
-                                            struct snd_pcm_runtime *runtime)
+static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_runtime *runtime)
 {
        snd_pcm_uframes_t avail;
 
@@ -182,11 +195,21 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream
        return 0;
 }
 
-static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
+#define hw_ptr_error(substream, fmt, args...)                          \
+       do {                                                            \
+               if (xrun_debug(substream)) {                            \
+                       if (printk_ratelimit()) {                       \
+                               snd_printd("PCM: " fmt, ##args);        \
+                       }                                               \
+                       dump_stack_on_xrun(substream);                  \
+               }                                                       \
+       } while (0)
+
+static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t pos;
-       snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
+       snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
        snd_pcm_sframes_t delta;
 
        pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -194,36 +217,53 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
                xrun(substream);
                return -EPIPE;
        }
-       if (runtime->period_size == runtime->buffer_size)
-               goto __next_buf;
-       new_hw_ptr = runtime->hw_ptr_base + pos;
+       hw_base = runtime->hw_ptr_base;
+       new_hw_ptr = hw_base + pos;
        hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
-
-       delta = hw_ptr_interrupt - new_hw_ptr;
-       if (delta > 0) {
-               if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-                       if (runtime->periods > 1 && substream->pstr->xrun_debug) {
-                               snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
-                               if (substream->pstr->xrun_debug > 1)
-                                       dump_stack();
-                       }
-#endif
-                       return 0;
+       delta = new_hw_ptr - hw_ptr_interrupt;
+       if (hw_ptr_interrupt >= runtime->boundary) {
+               hw_ptr_interrupt -= runtime->boundary;
+               if (hw_base < runtime->boundary / 2)
+                       /* hw_base was already lapped; recalc delta */
+                       delta = new_hw_ptr - hw_ptr_interrupt;
+       }
+       if (delta < 0) {
+               delta += runtime->buffer_size;
+               if (delta < 0) {
+                       hw_ptr_error(substream, 
+                                    "Unexpected hw_pointer value "
+                                    "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
+                                    substream->stream, (long)pos,
+                                    (long)hw_ptr_interrupt);
+                       /* rebase to interrupt position */
+                       hw_base = new_hw_ptr = hw_ptr_interrupt;
+                       /* align hw_base to buffer_size */
+                       hw_base -= hw_base % runtime->buffer_size;
+                       delta = 0;
+               } else {
+                       hw_base += runtime->buffer_size;
+                       if (hw_base >= runtime->boundary)
+                               hw_base = 0;
+                       new_hw_ptr = hw_base + pos;
                }
-             __next_buf:
-               runtime->hw_ptr_base += runtime->buffer_size;
-               if (runtime->hw_ptr_base == runtime->boundary)
-                       runtime->hw_ptr_base = 0;
-               new_hw_ptr = runtime->hw_ptr_base + pos;
        }
-
+       if (delta > runtime->period_size) {
+               hw_ptr_error(substream,
+                            "Lost interrupts? "
+                            "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
+                            substream->stream, (long)delta,
+                            (long)hw_ptr_interrupt);
+               /* rebase hw_ptr_interrupt */
+               hw_ptr_interrupt =
+                       new_hw_ptr - new_hw_ptr % runtime->period_size;
+       }
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
+       runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
-       runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
+       runtime->hw_ptr_interrupt = hw_ptr_interrupt;
 
        return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -233,7 +273,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t pos;
-       snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
+       snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
        snd_pcm_sframes_t delta;
 
        old_hw_ptr = runtime->status->hw_ptr;
@@ -242,29 +282,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
                xrun(substream);
                return -EPIPE;
        }
-       new_hw_ptr = runtime->hw_ptr_base + pos;
-
-       delta = old_hw_ptr - new_hw_ptr;
-       if (delta > 0) {
-               if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-                       if (runtime->periods > 2 && substream->pstr->xrun_debug) {
-                               snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
-                               if (substream->pstr->xrun_debug > 1)
-                                       dump_stack();
-                       }
-#endif
+       hw_base = runtime->hw_ptr_base;
+       new_hw_ptr = hw_base + pos;
+
+       delta = new_hw_ptr - old_hw_ptr;
+       if (delta < 0) {
+               delta += runtime->buffer_size;
+               if (delta < 0) {
+                       hw_ptr_error(substream, 
+                                    "Unexpected hw_pointer value [2] "
+                                    "(stream=%i, pos=%ld, old_ptr=%ld)\n",
+                                    substream->stream, (long)pos,
+                                    (long)old_hw_ptr);
                        return 0;
                }
-               runtime->hw_ptr_base += runtime->buffer_size;
-               if (runtime->hw_ptr_base == runtime->boundary)
-                       runtime->hw_ptr_base = 0;
-               new_hw_ptr = runtime->hw_ptr_base + pos;
+               hw_base += runtime->buffer_size;
+               if (hw_base >= runtime->boundary)
+                       hw_base = 0;
+               new_hw_ptr = hw_base + pos;
+       }
+       if (delta > runtime->period_size && runtime->periods > 1) {
+               hw_ptr_error(substream,
+                            "hw_ptr skipping! "
+                            "(pos=%ld, delta=%ld, period=%ld)\n",
+                            (long)pos, (long)delta,
+                            (long)runtime->period_size);
+               return 0;
        }
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
+       runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
 
        return snd_pcm_update_hw_ptr_post(substream, runtime);
index a789efc9df3971e46b4f2535d57a4329d5b27dc2..d9b8f5379428cd8ae150a7e6696611d501fbb681 100644 (file)
@@ -186,7 +186,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk("%s = ", snd_pcm_hw_param_names[k]);
+               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
                printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
 #endif
                changed = snd_mask_refine(m, constrs_mask(constrs, k));
@@ -206,7 +206,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk("%s = ", snd_pcm_hw_param_names[k]);
+               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
                if (i->empty)
                        printk("empty");
                else
@@ -251,7 +251,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                        if (!doit)
                                continue;
 #ifdef RULES_DEBUG
-                       printk("Rule %d [%p]: ", k, r->func);
+                       printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
                        if (r->var >= 0) {
                                printk("%s = ", snd_pcm_hw_param_names[r->var]);
                                if (hw_is_mask(r->var)) {
index 2c89c04f29163766dde1c6b9f6f7a296310343f3..ca8068b63d6c1bc413d16a2309d7d33fbe378893 100644 (file)
@@ -85,25 +85,19 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
 
 static int snd_pcm_timer_start(struct snd_timer * timer)
 {
-       unsigned long flags;
        struct snd_pcm_substream *substream;
        
        substream = snd_timer_chip(timer);
-       spin_lock_irqsave(&substream->timer_lock, flags);
        substream->timer_running = 1;
-       spin_unlock_irqrestore(&substream->timer_lock, flags);
        return 0;
 }
 
 static int snd_pcm_timer_stop(struct snd_timer * timer)
 {
-       unsigned long flags;
        struct snd_pcm_substream *substream;
        
        substream = snd_timer_chip(timer);
-       spin_lock_irqsave(&substream->timer_lock, flags);
        substream->timer_running = 0;
-       spin_unlock_irqrestore(&substream->timer_lock, flags);
        return 0;
 }
 
index 002777ba336aea636cd0a5c54d54934c87867bd8..473247c8e6d3e22c2e3466e80443e6e6e3054680 100644 (file)
@@ -224,156 +224,143 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
        return 0;
 }
 
-int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
-                           int mode, struct snd_rawmidi_file * rfile)
+/* look for an available substream for the given stream direction;
+ * if a specific subdevice is given, try to assign it
+ */
+static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
+                           int stream, int mode,
+                           struct snd_rawmidi_substream **sub_ret)
+{
+       struct snd_rawmidi_substream *substream;
+       struct snd_rawmidi_str *s = &rmidi->streams[stream];
+       static unsigned int info_flags[2] = {
+               [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
+               [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
+       };
+
+       if (!(rmidi->info_flags & info_flags[stream]))
+               return -ENXIO;
+       if (subdevice >= 0 && subdevice >= s->substream_count)
+               return -ENODEV;
+       if (s->substream_opened >= s->substream_count)
+               return -EAGAIN;
+
+       list_for_each_entry(substream, &s->substreams, list) {
+               if (substream->opened) {
+                       if (stream == SNDRV_RAWMIDI_STREAM_INPUT ||
+                           !(mode & SNDRV_RAWMIDI_LFLG_APPEND))
+                               continue;
+               }
+               if (subdevice < 0 || subdevice == substream->number) {
+                       *sub_ret = substream;
+                       return 0;
+               }
+       }
+       return -EAGAIN;
+}
+
+/* open and do ref-counting for the given substream */
+static int open_substream(struct snd_rawmidi *rmidi,
+                         struct snd_rawmidi_substream *substream,
+                         int mode)
+{
+       int err;
+
+       err = snd_rawmidi_runtime_create(substream);
+       if (err < 0)
+               return err;
+       err = substream->ops->open(substream);
+       if (err < 0)
+               return err;
+       substream->opened = 1;
+       if (substream->use_count++ == 0)
+               substream->active_sensing = 1;
+       if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
+               substream->append = 1;
+       rmidi->streams[substream->stream].substream_opened++;
+       return 0;
+}
+
+static void close_substream(struct snd_rawmidi *rmidi,
+                           struct snd_rawmidi_substream *substream,
+                           int cleanup);
+
+static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
+                            struct snd_rawmidi_file *rfile)
 {
-       struct snd_rawmidi *rmidi;
-       struct list_head *list1, *list2;
        struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
-       struct snd_rawmidi_runtime *input = NULL, *output = NULL;
        int err;
 
-       if (rfile)
-               rfile->input = rfile->output = NULL;
-       mutex_lock(&register_mutex);
-       rmidi = snd_rawmidi_search(card, device);
-       mutex_unlock(&register_mutex);
-       if (rmidi == NULL) {
-               err = -ENODEV;
-               goto __error1;
-       }
-       if (!try_module_get(rmidi->card->module)) {
-               err = -EFAULT;
-               goto __error1;
-       }
-       if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-               mutex_lock(&rmidi->open_mutex);
+       rfile->input = rfile->output = NULL;
        if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
-               if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
-                       err = -ENXIO;
-                       goto __error;
-               }
-               if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
-                       err = -ENODEV;
-                       goto __error;
-               }
-               if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >=
-                   rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
-                       err = -EAGAIN;
+               err = assign_substream(rmidi, subdevice,
+                                      SNDRV_RAWMIDI_STREAM_INPUT,
+                                      mode, &sinput);
+               if (err < 0)
                        goto __error;
-               }
        }
        if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
-               if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) {
-                       err = -ENXIO;
-                       goto __error;
-               }
-               if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
-                       err = -ENODEV;
-                       goto __error;
-               }
-               if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >=
-                   rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
-                       err = -EAGAIN;
+               err = assign_substream(rmidi, subdevice,
+                                      SNDRV_RAWMIDI_STREAM_OUTPUT,
+                                      mode, &soutput);
+               if (err < 0)
                        goto __error;
-               }
-       }
-       list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next;
-       while (1) {
-               if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
-                       sinput = NULL;
-                       if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
-                               err = -EAGAIN;
-                               goto __error;
-                       }
-                       break;
-               }
-               sinput = list_entry(list1, struct snd_rawmidi_substream, list);
-               if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened)
-                       goto __nexti;
-               if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number))
-                       break;
-             __nexti:
-               list1 = list1->next;
        }
-       list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next;
-       while (1) {
-               if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
-                       soutput = NULL;
-                       if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
-                               err = -EAGAIN;
-                               goto __error;
-                       }
-                       break;
-               }
-               soutput = list_entry(list2, struct snd_rawmidi_substream, list);
-               if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
-                       if (mode & SNDRV_RAWMIDI_LFLG_APPEND) {
-                               if (soutput->opened && !soutput->append)
-                                       goto __nexto;
-                       } else {
-                               if (soutput->opened)
-                                       goto __nexto;
-                       }
-               }
-               if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number))
-                       break;
-             __nexto:
-               list2 = list2->next;
-       }
-       if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
-               if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
-                       goto __error;
-               input = sinput->runtime;
-               if ((err = sinput->ops->open(sinput)) < 0)
+
+       if (sinput) {
+               err = open_substream(rmidi, sinput, mode);
+               if (err < 0)
                        goto __error;
-               sinput->opened = 1;
-               rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
-       } else {
-               sinput = NULL;
        }
-       if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
-               if (soutput->opened)
-                       goto __skip_output;
-               if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
-                       if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
-                               sinput->ops->close(sinput);
-                       goto __error;
-               }
-               output = soutput->runtime;
-               if ((err = soutput->ops->open(soutput)) < 0) {
-                       if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
-                               sinput->ops->close(sinput);
+       if (soutput) {
+               err = open_substream(rmidi, soutput, mode);
+               if (err < 0) {
+                       if (sinput)
+                               close_substream(rmidi, sinput, 0);
                        goto __error;
                }
-             __skip_output:
-               soutput->opened = 1;
-               if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
-                       soutput->append = 1;
-               if (soutput->use_count++ == 0)
-                       soutput->active_sensing = 1;
-               rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++;
-       } else {
-               soutput = NULL;
-       }
-       if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-               mutex_unlock(&rmidi->open_mutex);
-       if (rfile) {
-               rfile->rmidi = rmidi;
-               rfile->input = sinput;
-               rfile->output = soutput;
        }
+
+       rfile->rmidi = rmidi;
+       rfile->input = sinput;
+       rfile->output = soutput;
        return 0;
 
       __error:
-       if (input != NULL)
+       if (sinput && sinput->runtime)
                snd_rawmidi_runtime_free(sinput);
-       if (output != NULL)
+       if (soutput && soutput->runtime)
                snd_rawmidi_runtime_free(soutput);
-       module_put(rmidi->card->module);
-       if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-               mutex_unlock(&rmidi->open_mutex);
-      __error1:
+       return err;
+}
+
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
+                           int mode, struct snd_rawmidi_file * rfile)
+{
+       struct snd_rawmidi *rmidi;
+       int err;
+
+       if (snd_BUG_ON(!rfile))
+               return -EINVAL;
+
+       mutex_lock(&register_mutex);
+       rmidi = snd_rawmidi_search(card, device);
+       if (rmidi == NULL) {
+               mutex_unlock(&register_mutex);
+               return -ENODEV;
+       }
+       if (!try_module_get(rmidi->card->module)) {
+               mutex_unlock(&register_mutex);
+               return -ENXIO;
+       }
+       mutex_unlock(&register_mutex);
+
+       mutex_lock(&rmidi->open_mutex);
+       err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
+       mutex_unlock(&rmidi->open_mutex);
+       if (err < 0)
+               module_put(rmidi->card->module);
        return err;
 }
 
@@ -385,10 +372,13 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        unsigned short fflags;
        int err;
        struct snd_rawmidi *rmidi;
-       struct snd_rawmidi_file *rawmidi_file;
+       struct snd_rawmidi_file *rawmidi_file = NULL;
        wait_queue_t wait;
        struct snd_ctl_file *kctl;
 
+       if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
+               return -EINVAL;         /* invalid combination */
+
        if (maj == snd_major) {
                rmidi = snd_lookup_minor_data(iminor(inode),
                                              SNDRV_DEVICE_TYPE_RAWMIDI);
@@ -402,24 +392,25 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
 
        if (rmidi == NULL)
                return -ENODEV;
-       if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
-               return -EINVAL;         /* invalid combination */
+
+       if (!try_module_get(rmidi->card->module))
+               return -ENXIO;
+
+       mutex_lock(&rmidi->open_mutex);
        card = rmidi->card;
        err = snd_card_file_add(card, file);
        if (err < 0)
-               return -ENODEV;
+               goto __error_card;
        fflags = snd_rawmidi_file_flags(file);
        if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */
                fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
-       fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
        rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
        if (rawmidi_file == NULL) {
-               snd_card_file_remove(card, file);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto __error;
        }
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&rmidi->open_wait, &wait);
-       mutex_lock(&rmidi->open_mutex);
        while (1) {
                subdevice = -1;
                read_lock(&card->ctl_files_rwlock);
@@ -431,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                        }
                }
                read_unlock(&card->ctl_files_rwlock);
-               err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device,
-                                             subdevice, fflags, rawmidi_file);
+               err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
                if (err >= 0)
                        break;
                if (err == -EAGAIN) {
@@ -451,67 +441,89 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                        break;
                }
        }
+       remove_wait_queue(&rmidi->open_wait, &wait);
+       if (err < 0) {
+               kfree(rawmidi_file);
+               goto __error;
+       }
 #ifdef CONFIG_SND_OSSEMUL
        if (rawmidi_file->input && rawmidi_file->input->runtime)
                rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
        if (rawmidi_file->output && rawmidi_file->output->runtime)
                rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
 #endif
-       remove_wait_queue(&rmidi->open_wait, &wait);
-       if (err >= 0) {
-               file->private_data = rawmidi_file;
-       } else {
-               snd_card_file_remove(card, file);
-               kfree(rawmidi_file);
-       }
+       file->private_data = rawmidi_file;
+       mutex_unlock(&rmidi->open_mutex);
+       return 0;
+
+ __error:
+       snd_card_file_remove(card, file);
+ __error_card:
        mutex_unlock(&rmidi->open_mutex);
+       module_put(rmidi->card->module);
        return err;
 }
 
-int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile)
+static void close_substream(struct snd_rawmidi *rmidi,
+                           struct snd_rawmidi_substream *substream,
+                           int cleanup)
 {
-       struct snd_rawmidi *rmidi;
-       struct snd_rawmidi_substream *substream;
-       struct snd_rawmidi_runtime *runtime;
+       rmidi->streams[substream->stream].substream_opened--;
+       if (--substream->use_count)
+               return;
 
-       if (snd_BUG_ON(!rfile))
-               return -ENXIO;
-       rmidi = rfile->rmidi;
-       mutex_lock(&rmidi->open_mutex);
-       if (rfile->input != NULL) {
-               substream = rfile->input;
-               rfile->input = NULL;
-               runtime = substream->runtime;
-               snd_rawmidi_input_trigger(substream, 0);
-               substream->ops->close(substream);
-               if (runtime->private_free != NULL)
-                       runtime->private_free(substream);
-               snd_rawmidi_runtime_free(substream);
-               substream->opened = 0;
-               rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
-       }
-       if (rfile->output != NULL) {
-               substream = rfile->output;
-               rfile->output = NULL;
-               if (--substream->use_count == 0) {
-                       runtime = substream->runtime;
+       if (cleanup) {
+               if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
+                       snd_rawmidi_input_trigger(substream, 0);
+               else {
                        if (substream->active_sensing) {
                                unsigned char buf = 0xfe;
-                               /* sending single active sensing message to shut the device up */
+                               /* sending single active sensing message
+                                * to shut the device up
+                                */
                                snd_rawmidi_kernel_write(substream, &buf, 1);
                        }
                        if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
                                snd_rawmidi_output_trigger(substream, 0);
-                       substream->ops->close(substream);
-                       if (runtime->private_free != NULL)
-                               runtime->private_free(substream);
-                       snd_rawmidi_runtime_free(substream);
-                       substream->opened = 0;
-                       substream->append = 0;
                }
-               rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
        }
+       substream->ops->close(substream);
+       if (substream->runtime->private_free)
+               substream->runtime->private_free(substream);
+       snd_rawmidi_runtime_free(substream);
+       substream->opened = 0;
+       substream->append = 0;
+}
+
+static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
+{
+       struct snd_rawmidi *rmidi;
+
+       rmidi = rfile->rmidi;
+       mutex_lock(&rmidi->open_mutex);
+       if (rfile->input) {
+               close_substream(rmidi, rfile->input, 1);
+               rfile->input = NULL;
+       }
+       if (rfile->output) {
+               close_substream(rmidi, rfile->output, 1);
+               rfile->output = NULL;
+       }
+       rfile->rmidi = NULL;
        mutex_unlock(&rmidi->open_mutex);
+       wake_up(&rmidi->open_wait);
+}
+
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
+{
+       struct snd_rawmidi *rmidi;
+
+       if (snd_BUG_ON(!rfile))
+               return -ENXIO;
+       
+       rmidi = rfile->rmidi;
+       rawmidi_release_priv(rfile);
        module_put(rmidi->card->module);
        return 0;
 }
@@ -520,15 +532,14 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file)
 {
        struct snd_rawmidi_file *rfile;
        struct snd_rawmidi *rmidi;
-       int err;
 
        rfile = file->private_data;
-       err = snd_rawmidi_kernel_release(rfile);
        rmidi = rfile->rmidi;
-       wake_up(&rmidi->open_wait);
+       rawmidi_release_priv(rfile);
        kfree(rfile);
        snd_card_file_remove(rmidi->card, file);
-       return err;
+       module_put(rmidi->card->module);
+       return 0;
 }
 
 static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
index bf8d2b4cb15e8e403a10f94eb15bc4ee67d251c8..c0154a959d55373969c0e4eb608099f1e71098a7 100644 (file)
@@ -181,7 +181,7 @@ char *enabled_str(int bool);
 /* for debug */
 #ifdef SNDRV_SEQ_OSS_DEBUG
 extern int seq_oss_debug;
-#define debug_printk(x)        do { if (seq_oss_debug > 0) snd_printk x; } while (0)
+#define debug_printk(x)        do { if (seq_oss_debug > 0) snd_printd x; } while (0)
 #else
 #define debug_printk(x)        /**/
 #endif
index 0101a8b99b7325650b7b4ccb758aac26366815aa..29896ab23403a219283920ab0dd204e545047440 100644 (file)
@@ -321,7 +321,8 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
                        freeprev = cell;
                } else {
 #if 0
-                       printk("type = %i, source = %i, dest = %i, client = %i\n",
+                       printk(KERN_DEBUG "type = %i, source = %i, dest = %i, "
+                              "client = %i\n",
                                cell->event.type,
                                cell->event.source.client,
                                cell->event.dest.client,
index 4cc57f902e2c9ac03f8b8e6216be27738430d385..257624bd199776c37ecc01815fd377e3150ac3ec 100644 (file)
@@ -50,18 +50,38 @@ struct link_slave {
        struct link_master *master;
        struct link_ctl_info info;
        int vals[2];            /* current values */
+       unsigned int flags;
        struct snd_kcontrol slave; /* the copy of original control entry */
 };
 
+static int slave_update(struct link_slave *slave)
+{
+       struct snd_ctl_elem_value *uctl;
+       int err, ch;
+
+       uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
+       if (!uctl)
+               return -ENOMEM;
+       uctl->id = slave->slave.id;
+       err = slave->slave.get(&slave->slave, uctl);
+       for (ch = 0; ch < slave->info.count; ch++)
+               slave->vals[ch] = uctl->value.integer.value[ch];
+       kfree(uctl);
+       return 0;
+}
+
 /* get the slave ctl info and save the initial values */
 static int slave_init(struct link_slave *slave)
 {
        struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
-       int err, ch;
+       int err;
 
-       if (slave->info.count)
-               return 0; /* already initialized */
+       if (slave->info.count) {
+               /* already initialized */
+               if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
+                       return slave_update(slave);
+               return 0;
+       }
 
        uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
        if (!uinfo)
@@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave)
        slave->info.max_val = uinfo->value.integer.max;
        kfree(uinfo);
 
-       uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
-       if (!uctl)
-               return -ENOMEM;
-       uctl->id = slave->slave.id;
-       err = slave->slave.get(&slave->slave, uctl);
-       for (ch = 0; ch < slave->info.count; ch++)
-               slave->vals[ch] = uctl->value.integer.value[ch];
-       kfree(uctl);
-       return 0;
+       return slave_update(slave);
 }
 
 /* initialize master volume */
@@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol)
  * - logarithmic volume control (dB level), no linear volume
  * - master can only attenuate the volume, no gain
  */
-int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
+int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
+                      unsigned int flags)
 {
        struct link_master *master_link = snd_kcontrol_chip(master);
        struct link_slave *srec;
@@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
        srec->slave = *slave;
        memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
        srec->master = master_link;
+       srec->flags = flags;
 
        /* override callbacks */
        slave->info = slave_info;
@@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
        list_add_tail(&srec->list, &master_link->slaves);
        return 0;
 }
-
-EXPORT_SYMBOL(snd_ctl_add_slave);
+EXPORT_SYMBOL(_snd_ctl_add_slave);
 
 /*
  * ctl callbacks for master controls
@@ -327,8 +340,20 @@ static void master_free(struct snd_kcontrol *kcontrol)
 }
 
 
-/*
- * Create a virtual master control with the given name
+/**
+ * snd_ctl_make_virtual_master - Create a virtual master control
+ * @name: name string of the control element to create
+ * @tlv: optional TLV int array for dB information
+ *
+ * Creates a virtual matster control with the given name string.
+ * Returns the created control element, or NULL for errors (ENOMEM).
+ *
+ * After creating a vmaster element, you can add the slave controls
+ * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
+ *
+ * The optional argument @tlv can be used to specify the TLV information
+ * for dB scale of the master control.  It should be a single element
+ * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
  */
 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
                                                 const unsigned int *tlv)
@@ -367,5 +392,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
 
        return kctl;
 }
-
 EXPORT_SYMBOL(snd_ctl_make_virtual_master);
index 73be7e14a603d56208aec9d9bd741b48c5444750..54239d2e0997b7ac88e2e6c2e3898afc79a7c0f9 100644 (file)
@@ -588,10 +588,10 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
        int idx, err;
        int dev = devptr->id;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_dummy));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_dummy), &card);
+       if (err < 0)
+               return err;
        dummy = card->private_data;
        dummy->card = card;
        for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
index 7783843ca9ae95ce9dd2acee69eb970acd914348..1950ffce2b545cdff262daae280128134259fa20 100644 (file)
@@ -1279,9 +1279,9 @@ static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev)
        if (!enable[dev])
                return -ENOENT;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
        if (err < 0) {
                PDEBUG(INIT_FAILURE, "probe(): create failed!\n");
index 5b996f3faba5844c434d693af77fee3bcd3bbba4..149d05a8202d58bf381c3eb059e3302f89e2a188 100644 (file)
@@ -73,9 +73,9 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
                snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
 
        *rcard = NULL;
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        strcpy(card->driver, "MPU-401 UART");
        strcpy(card->shortname, card->driver);
        sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
index 48b64e6b26701e14ace4015b5df08b7f56408d5a..2f8f295d6b0cc731885c82d6907172a1a577788d 100644 (file)
@@ -303,8 +303,10 @@ static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
 
                snd_mtpav_send_byte(mtp_card, 0xf5);
                snd_mtpav_send_byte(mtp_card, portp->hwport);
-               //snd_printk("new outport: 0x%x\n", (unsigned int) portp->hwport);
-
+               /*
+               snd_printk(KERN_DEBUG "new outport: 0x%x\n",
+                          (unsigned int) portp->hwport);
+               */
                if (!(outbyte & 0x80) && portp->running_status)
                        snd_mtpav_send_byte(mtp_card, portp->running_status);
        }
@@ -540,7 +542,7 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
 
        u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
 
-       //printk("snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt);
+       /* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
 
        if (!(sbyt & SIGS_BYTE))
                return;
@@ -585,12 +587,12 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
 static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard)
 {
        if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) {
-               snd_printk("MTVAP port 0x%lx is busy\n", port);
+               snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
                return -EBUSY;
        }
        mcard->port = port;
        if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) {
-               snd_printk("MTVAP IRQ %d busy\n", irq);
+               snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
                return -EBUSY;
        }
        mcard->irq = irq;
@@ -696,9 +698,9 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
        int err;
        struct mtpav *mtp_card;
 
-       card = snd_card_new(index, id, THIS_MODULE, sizeof(*mtp_card));
-       if (! card)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, sizeof(*mtp_card), &card);
+       if (err < 0)
+               return err;
 
        mtp_card = card->private_data;
        spin_lock_init(&mtp_card->spinlock);
index 87ba1ddc01151fdfb5bd8f38d80103a68964aa5a..9284829bf9275e9c2afabbbe8e2026c35c2dfb60 100644 (file)
@@ -957,10 +957,10 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
        if ((err = snd_mts64_probe_port(p)) < 0)
                return err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL) {
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printd("Cannot create card\n");
-               return -ENOMEM;
+               return err;
        }
        strcpy(card->driver, DRIVER_NAME);
        strcpy(card->shortname, "ESI " CARD_NAME);
@@ -1015,7 +1015,7 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
                goto __err;
        }
 
-       snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base);
+       snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base);
        return 0;
 
 __err:
index 780582340fefab73e11930775edc81fcda2ff9f6..6e31e46ca3934f46b8a8cef2ffa8215a69d3c8e8 100644 (file)
@@ -302,7 +302,7 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
        opl3 = hw->private_data;
        status = inb(opl3->l_port);
 #if 0
-       snd_printk("AdLib IRQ status = 0x%x\n", status);
+       snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x\n", status);
 #endif
        if (!(status & 0x80))
                return;
index 16feafa2c51e872cfb6266b3882e76b407c1180e..6e7d09ae0e82310fa053155c43ec2b9c11d1d084 100644 (file)
@@ -125,7 +125,7 @@ static void debug_alloc(struct snd_opl3 *opl3, char *s, int voice) {
        int i;
        char *str = "x.24";
 
-       printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
+       printk(KERN_DEBUG "time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
        for (i = 0; i < opl3->max_voices; i++)
                printk("%c", *(str + opl3->voices[i].state + 1));
        printk("\n");
@@ -218,7 +218,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
        for (i = 0; i < END; i++) {
                if (best[i].voice >= 0) {
 #ifdef DEBUG_ALLOC
-                       printk("%s %iop allocation on voice %i\n",
+                       printk(KERN_DEBUG "%s %iop allocation on voice %i\n",
                               alloc_type[i], instr_4op ? 4 : 2,
                               best[i].voice);
 #endif
@@ -317,7 +317,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        opl3 = p;
 
 #ifdef DEBUG_MIDI
-       snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
+       snd_printk(KERN_DEBUG "Note on, ch %i, inst %i, note %i, vel %i\n",
                   chan->number, chan->midi_program, note, vel);
 #endif
 
@@ -372,7 +372,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
                return;
        }
 #ifdef DEBUG_MIDI
-       snd_printk("  --> OPL%i instrument: %s\n",
+       snd_printk(KERN_DEBUG "  --> OPL%i instrument: %s\n",
                   instr_4op ? 3 : 2, patch->name);
 #endif
        /* in SYNTH mode, application takes care of voices */
@@ -431,7 +431,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        }
 
 #ifdef DEBUG_MIDI
-       snd_printk("  --> setting OPL3 connection: 0x%x\n",
+       snd_printk(KERN_DEBUG "  --> setting OPL3 connection: 0x%x\n",
                   opl3->connection_reg);
 #endif
        /*
@@ -466,7 +466,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        /* Program the FM voice characteristics */
        for (i = 0; i < (instr_4op ? 4 : 2); i++) {
 #ifdef DEBUG_MIDI
-               snd_printk("  --> programming operator %i\n", i);
+               snd_printk(KERN_DEBUG "  --> programming operator %i\n", i);
 #endif
                op_offset = snd_opl3_regmap[voice_offset][i];
 
@@ -546,7 +546,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        blocknum |= OPL3_KEYON_BIT;
 
 #ifdef DEBUG_MIDI
-       snd_printk("  --> trigger voice %i\n", voice);
+       snd_printk(KERN_DEBUG "  --> trigger voice %i\n", voice);
 #endif
        /* Set OPL3 KEYON_BLOCK register of requested voice */ 
        opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
@@ -602,7 +602,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
                        prg = extra_prg - 1;
                }
 #ifdef DEBUG_MIDI
-               snd_printk(" *** allocating extra program\n");
+               snd_printk(KERN_DEBUG " *** allocating extra program\n");
 #endif
                goto __extra_prg;
        }
@@ -633,7 +633,7 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
 
        /* kill voice */
 #ifdef DEBUG_MIDI
-       snd_printk("  --> kill voice %i\n", voice);
+       snd_printk(KERN_DEBUG "  --> kill voice %i\n", voice);
 #endif
        opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
        /* clear Key ON bit */
@@ -670,7 +670,7 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
        opl3 = p;
 
 #ifdef DEBUG_MIDI
-       snd_printk("Note off, ch %i, inst %i, note %i\n",
+       snd_printk(KERN_DEBUG "Note off, ch %i, inst %i, note %i\n",
                   chan->number, chan->midi_program, note);
 #endif
 
@@ -709,7 +709,7 @@ void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *cha
 
        opl3 = p;
 #ifdef DEBUG_MIDI
-       snd_printk("Key pressure, ch#: %i, inst#: %i\n",
+       snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n",
                   chan->number, chan->midi_program);
 #endif
 }
@@ -723,7 +723,7 @@ void snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan)
 
        opl3 = p;
 #ifdef DEBUG_MIDI
-       snd_printk("Terminate note, ch#: %i, inst#: %i\n",
+       snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n",
                   chan->number, chan->midi_program);
 #endif
 }
@@ -812,7 +812,7 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
 
        opl3 = p;
 #ifdef DEBUG_MIDI
-       snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",
+       snd_printk(KERN_DEBUG "Controller, TYPE = %i, ch#: %i, inst#: %i\n",
                   type, chan->number, chan->midi_program);
 #endif
 
@@ -849,7 +849,7 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
 
        opl3 = p;
 #ifdef DEBUG_MIDI
-       snd_printk("NRPN, ch#: %i, inst#: %i\n",
+       snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n",
                   chan->number, chan->midi_program);
 #endif
 }
@@ -864,6 +864,6 @@ void snd_opl3_sysex(void *p, unsigned char *buf, int len,
 
        opl3 = p;
 #ifdef DEBUG_MIDI
-       snd_printk("SYSEX\n");
+       snd_printk(KERN_DEBUG "SYSEX\n");
 #endif
 }
index 9a2271dc046a653e7f80077108bd6c19b2c3e6a7..a54b1dc5cc7859f7b10316aed9fce1af5b9c391f 100644 (file)
@@ -220,14 +220,14 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
                return -EINVAL;
 
        if (count < (int)sizeof(sbi)) {
-               snd_printk("FM Error: Patch record too short\n");
+               snd_printk(KERN_ERR "FM Error: Patch record too short\n");
                return -EINVAL;
        }
        if (copy_from_user(&sbi, buf, sizeof(sbi)))
                return -EFAULT;
 
        if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
-               snd_printk("FM Error: Invalid instrument number %d\n",
+               snd_printk(KERN_ERR "FM Error: Invalid instrument number %d\n",
                           sbi.channel);
                return -EINVAL;
        }
@@ -254,7 +254,9 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
        opl3 = arg->private_data;
        switch (cmd) {
                case SNDCTL_FM_LOAD_INSTR:
-                       snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
+                       snd_printk(KERN_ERR "OPL3: "
+                                  "Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. "
+                                  "Fix the program.\n");
                        return -EINVAL;
 
                case SNDCTL_SYNTH_MEMAVL:
index 962bb9c8b9c8902b5fd5bcaa111a515b8cc71fe8..6d57b6441dec53312de691a6caeb835ae2ef607d 100644 (file)
@@ -168,7 +168,7 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
 
 #ifdef CONFIG_SND_DEBUG
        default:
-               snd_printk("unknown IOCTL: 0x%x\n", cmd);
+               snd_printk(KERN_WARNING "unknown IOCTL: 0x%x\n", cmd);
 #endif
        }
        return -ENOTTY;
index a4049eb94d35a28bafa41072e6e44af726d6f251..b60cef257b589288a7339157bfdbc9e009b5c5bb 100644 (file)
@@ -57,7 +57,7 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
        else
                min_div = MAX_DIV;
 #if PCSP_DEBUG
-       printk("PCSP: lpj=%li, min_div=%i, res=%li\n",
+       printk(KERN_DEBUG "PCSP: lpj=%li, min_div=%i, res=%li\n",
               loops_per_jiffy, min_div, tp.tv_nsec);
 #endif
 
@@ -98,9 +98,9 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
        hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pcsp_chip.timer.function = pcsp_do_timer;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_pcsp_create(card);
        if (err < 0) {
index b1c047ec19afe6e5ce9e6cf1acb2124c72719d45..60158e2e0eafb529e00013b4a9997d325b1b7fa2 100644 (file)
@@ -746,10 +746,10 @@ static int __devinit snd_portman_probe(struct platform_device *pdev)
        if ((err = snd_portman_probe_port(p)) < 0)
                return err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL) {
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printd("Cannot create card\n");
-               return -ENOMEM;
+               return err;
        }
        strcpy(card->driver, DRIVER_NAME);
        strcpy(card->shortname, CARD_NAME);
index d8aab9da97c29ad8058f5be9751537b25b043500..b2b6d50c942559fcb14474ff1e8281ae947e4db4 100644 (file)
@@ -241,7 +241,8 @@ static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
                        snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
 
                if (status & UART_LSR_OE)
-                       snd_printk("%s: Overrun on device at 0x%lx\n",
+                       snd_printk(KERN_WARNING
+                                  "%s: Overrun on device at 0x%lx\n",
                               uart->rmidi->name, uart->base);
        }
 
@@ -636,7 +637,8 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
                }
        } else {
                if (!snd_uart16550_write_buffer(uart, midi_byte)) {
-                       snd_printk("%s: Buffer overrun on device at 0x%lx\n",
+                       snd_printk(KERN_WARNING
+                                  "%s: Buffer overrun on device at 0x%lx\n",
                                   uart->rmidi->name, uart->base);
                        return 0;
                }
@@ -815,7 +817,8 @@ static int __devinit snd_uart16550_create(struct snd_card *card,
        if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
                if (request_irq(irq, snd_uart16550_interrupt,
                                IRQF_DISABLED, "Serial MIDI", uart)) {
-                       snd_printk("irq %d busy. Using Polling.\n", irq);
+                       snd_printk(KERN_WARNING
+                                  "irq %d busy. Using Polling.\n", irq);
                } else {
                        uart->irq = irq;
                }
@@ -919,26 +922,29 @@ static int __devinit snd_serial_probe(struct platform_device *devptr)
        case SNDRV_SERIAL_GENERIC:
                break;
        default:
-               snd_printk("Adaptor type is out of range 0-%d (%d)\n",
+               snd_printk(KERN_ERR
+                          "Adaptor type is out of range 0-%d (%d)\n",
                           SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);
                return -ENODEV;
        }
 
        if (outs[dev] < 1 || outs[dev] > SNDRV_SERIAL_MAX_OUTS) {
-               snd_printk("Count of outputs is out of range 1-%d (%d)\n",
+               snd_printk(KERN_ERR
+                          "Count of outputs is out of range 1-%d (%d)\n",
                           SNDRV_SERIAL_MAX_OUTS, outs[dev]);
                return -ENODEV;
        }
 
        if (ins[dev] < 1 || ins[dev] > SNDRV_SERIAL_MAX_INS) {
-               snd_printk("Count of inputs is out of range 1-%d (%d)\n",
+               snd_printk(KERN_ERR
+                          "Count of inputs is out of range 1-%d (%d)\n",
                           SNDRV_SERIAL_MAX_INS, ins[dev]);
                return -ENODEV;
        }
 
-       card  = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err  = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "Serial");
        strcpy(card->shortname, "Serial MIDI (UART16550A)");
index f79e3614079d238aca26df870c863949bbda1e94..0e631c3221e3b72f46b2b1b11569d5931ead1097 100644 (file)
@@ -90,15 +90,17 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
        int idx, err;
        int dev = devptr->id;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_card_virmidi));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_card_virmidi), &card);
+       if (err < 0)
+               return err;
        vmidi = (struct snd_card_virmidi *)card->private_data;
        vmidi->card = card;
 
        if (midi_devs[dev] > MAX_MIDI_DEVICES) {
-               snd_printk("too much midi devices for virmidi %d: force to use %d\n", dev, MAX_MIDI_DEVICES);
+               snd_printk(KERN_WARNING
+                          "too much midi devices for virmidi %d: "
+                          "force to use %d\n", dev, MAX_MIDI_DEVICES);
                midi_devs[dev] = MAX_MIDI_DEVICES;
        }
        for (idx = 0; idx < midi_devs[dev]; idx++) {
index 14e3354be43a4470b1cd241c5649f5fa3c6637f5..19c6e376c7c781abe0ed587da593a50ee6130d74 100644 (file)
@@ -688,7 +688,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
                image = dsp->data + i;
                /* Wait DSP ready for a new read */
                if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
-                       printk("dsp loading error at position %d\n", i);
+                       printk(KERN_ERR
+                              "dsp loading error at position %d\n", i);
                        return err;
                }
                cptr = image;
index 8d6362e2d4c9ec54f5a0784e6f49baa424990f90..46df8817c18f7b79faa466eb01fbb12af3149921 100644 (file)
@@ -119,16 +119,6 @@ void snd_vx_free_firmware(struct vx_core *chip)
 
 #else /* old style firmware loading */
 
-static int vx_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
-static int vx_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
 static int vx_hwdep_dsp_status(struct snd_hwdep *hw,
                               struct snd_hwdep_dsp_status *info)
 {
@@ -243,8 +233,6 @@ int snd_vx_setup_firmware(struct vx_core *chip)
 
        hw->iface = SNDRV_HWDEP_IFACE_VX;
        hw->private_data = chip;
-       hw->ops.open = vx_hwdep_open;
-       hw->ops.release = vx_hwdep_release;
        hw->ops.dsp_status = vx_hwdep_dsp_status;
        hw->ops.dsp_load = vx_hwdep_dsp_load;
        hw->exclusive = 1;
index 0e1ba9b47904aa95de29dfe18f6aa6324aa8a3a7..b0560fec6bba68fb8dc516a92c84263101ed98c2 100644 (file)
@@ -103,7 +103,7 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
  * returns the frequency of UER, or 0 if not sync,
  * or a negative error code.
  */
-static int vx_read_uer_status(struct vx_core *chip, int *mode)
+static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode)
 {
        int val, freq;
 
index 37970666a45333229d8fee8d2ad2330d7c74c7e0..36879bf88700bbed235aca6a13577ee5ed106038 100644 (file)
@@ -7,8 +7,6 @@ snd-i2c-objs := i2c.o
 snd-cs8427-objs := cs8427.o
 snd-tea6330t-objs := tea6330t.o
 
-obj-$(CONFIG_L3) += l3/
-
 obj-$(CONFIG_SND) += other/
 
 # Toplevel Module Dependency
diff --git a/sound/i2c/l3/Makefile b/sound/i2c/l3/Makefile
deleted file mode 100644 (file)
index 49455b8..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for ALSA
-#
-
-snd-uda1341-objs := uda1341.o
-
-# Module Dependency
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-uda1341.o
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
deleted file mode 100644 (file)
index 9840eb4..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Philips UDA1341 mixer device driver
- * Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License.
- *
- * History:
- *
- * 2002-03-13   Tomas Kasparek  initial release - based on uda1341.c from OSS
- * 2002-03-28   Tomas Kasparek  basic mixer is working (volume, bass, treble)
- * 2002-03-30   Tomas Kasparek  proc filesystem support, complete mixer and DSP
- *                              features support
- * 2002-04-12  Tomas Kasparek  proc interface update, code cleanup
- * 2002-05-12   Tomas Kasparek  another code cleanup
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-
-#include <asm/uaccess.h>
-
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-#include <sound/info.h>
-
-#include <linux/l3/l3.h>
-
-#include <sound/uda1341.h>
-
-/* {{{ HW regs definition */
-
-#define STAT0                   0x00
-#define STAT1                  0x80
-#define STAT_MASK               0x80
-
-#define DATA0_0                        0x00
-#define DATA0_1                        0x40
-#define DATA0_2                        0x80
-#define DATA_MASK               0xc0
-
-#define IS_DATA0(x)     ((x) >= data0_0 && (x) <= data0_2)
-#define IS_DATA1(x)     ((x) == data1)
-#define IS_STATUS(x)    ((x) == stat0 || (x) == stat1)
-#define IS_EXTEND(x)   ((x) >= ext0 && (x) <= ext6)
-
-/* }}} */
-
-
-static const char *peak_names[] = {
-       "before",
-       "after",
-};
-
-static const char *filter_names[] = {
-       "flat",
-       "min",
-       "min",
-       "max",
-};
-
-static const char *mixer_names[] = {
-       "double differential",
-       "input channel 1 (line in)",
-       "input channel 2 (microphone)",
-       "digital mixer",
-};
-
-static const char *deemp_names[] = {
-       "none",
-       "32 kHz",
-       "44.1 kHz",
-       "48 kHz",        
-};
-
-enum uda1341_regs_names {
-       stat0,
-       stat1,
-       data0_0,
-       data0_1,
-       data0_2,
-       data1,
-       ext0,
-       ext1,
-       ext2,
-       empty,
-       ext4,
-       ext5,
-       ext6,
-       uda1341_reg_last,
-};
-
-static const char *uda1341_reg_names[] = {
-       "stat 0 ",
-       "stat 1 ",
-       "data 00",
-       "data 01",
-       "data 02",
-       "data 1 ",
-       "ext 0",
-       "ext 1",
-       "ext 2",
-       "empty",
-       "ext 4",
-       "ext 5",
-       "ext 6",
-};
-
-static const int uda1341_enum_items[] = {
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       2, //peak - before/after
-       4, //deemp - none/32/44.1/48
-       0,
-       4, //filter - flat/min/min/max
-       0, 0, 0,
-       4, //mixer - differ/line/mic/mixer
-       0, 0, 0, 0, 0,
-};
-
-static const char ** uda1341_enum_names[] = {
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       peak_names, //peak - before/after
-       deemp_names, //deemp - none/32/44.1/48
-       NULL,
-       filter_names, //filter - flat/min/min/max
-       NULL, NULL, NULL,
-       mixer_names, //mixer - differ/line/mic/mixer
-       NULL, NULL, NULL, NULL, NULL,
-};
-
-typedef int uda1341_cfg[CMD_LAST];
-
-struct uda1341 {
-       int (*write) (struct l3_client *uda1341, unsigned short reg, unsigned short val);
-       int (*read) (struct l3_client *uda1341, unsigned short reg);        
-       unsigned char regs[uda1341_reg_last];
-       int active;
-       spinlock_t reg_lock;
-       struct snd_card *card;
-       uda1341_cfg cfg;
-#ifdef CONFIG_PM
-       unsigned char suspend_regs[uda1341_reg_last];
-       uda1341_cfg suspend_cfg;
-#endif
-};
-
-/* transfer 8bit integer into string with binary representation */
-static void int2str_bin8(uint8_t val, char *buf)
-{
-       const int size = sizeof(val) * 8;
-       int i;
-
-       for (i= 0; i < size; i++){
-               *(buf++) = (val >> (size - 1)) ? '1' : '0';
-               val <<= 1;
-       }
-       *buf = '\0'; //end the string with zero
-}
-
-/* {{{ HW manipulation routines */
-
-static int snd_uda1341_codec_write(struct l3_client *clnt, unsigned short reg, unsigned short val)
-{
-       struct uda1341 *uda = clnt->driver_data;
-       unsigned char buf[2] = { 0xc0, 0xe0 }; // for EXT addressing
-       int err = 0;
-
-       uda->regs[reg] = val;
-
-       if (uda->active) {
-               if (IS_DATA0(reg)) {
-                       err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)&val, 1);
-               } else if (IS_DATA1(reg)) {
-                       err = l3_write(clnt, UDA1341_DATA1, (const unsigned char *)&val, 1);
-               } else if (IS_STATUS(reg)) {
-                       err = l3_write(clnt, UDA1341_STATUS, (const unsigned char *)&val, 1);
-               } else if (IS_EXTEND(reg)) {
-                       buf[0] |= (reg - ext0) & 0x7;   //EXT address
-                       buf[1] |= val;                  //EXT data
-                       err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)buf, 2);
-               }
-       } else
-               printk(KERN_ERR "UDA1341 codec not active!\n");
-       return err;
-}
-
-static int snd_uda1341_codec_read(struct l3_client *clnt, unsigned short reg)
-{
-       unsigned char val;
-       int err;
-
-       err = l3_read(clnt, reg, &val, 1);
-       if (err == 1)
-               // use just 6bits - the rest is address of the reg
-               return val & 63;
-       return err < 0 ? err : -EIO;
-}
-
-static inline int snd_uda1341_valid_reg(struct l3_client *clnt, unsigned short reg)
-{
-       return reg < uda1341_reg_last;
-}
-
-static int snd_uda1341_update_bits(struct l3_client *clnt, unsigned short reg,
-                                  unsigned short mask, unsigned short shift,
-                                  unsigned short value, int flush)
-{
-       int change;
-       unsigned short old, new;
-       struct uda1341 *uda = clnt->driver_data;
-
-#if 0
-       printk(KERN_DEBUG "update_bits: reg: %s mask: %d shift: %d val: %d\n",
-              uda1341_reg_names[reg], mask, shift, value);
-#endif
-        
-       if (!snd_uda1341_valid_reg(clnt, reg))
-               return -EINVAL;
-       spin_lock(&uda->reg_lock);
-       old = uda->regs[reg];
-       new = (old & ~(mask << shift)) | (value << shift);
-       change = old != new;
-       if (change) {
-               if (flush) uda->write(clnt, reg, new);
-               uda->regs[reg] = new;
-       }
-       spin_unlock(&uda->reg_lock);
-       return change;
-}
-
-static int snd_uda1341_cfg_write(struct l3_client *clnt, unsigned short what,
-                                unsigned short value, int flush)
-{
-       struct uda1341 *uda = clnt->driver_data;
-       int ret = 0;
-#ifdef CONFIG_PM
-       int reg;
-#endif
-
-#if 0
-       printk(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value);
-#endif
-
-       uda->cfg[what] = value;
-        
-       switch(what) {
-       case CMD_RESET:
-               ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, 1, flush);   // MUTE
-               ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 1, flush);     // RESET
-               ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 0, flush);     // RESTORE
-               uda->cfg[CMD_RESET]=0;
-               break;
-       case CMD_FS:
-               ret = snd_uda1341_update_bits(clnt, stat0, 3, 4, value, flush);
-               break;
-       case CMD_FORMAT:
-               ret = snd_uda1341_update_bits(clnt, stat0, 7, 1, value, flush);
-               break;
-       case CMD_OGAIN:
-               ret = snd_uda1341_update_bits(clnt, stat1, 1, 6, value, flush);
-               break;
-       case CMD_IGAIN:
-               ret = snd_uda1341_update_bits(clnt, stat1, 1, 5, value, flush);
-               break;
-       case CMD_DAC:
-               ret = snd_uda1341_update_bits(clnt, stat1, 1, 0, value, flush);
-               break;
-       case CMD_ADC:
-               ret = snd_uda1341_update_bits(clnt, stat1, 1, 1, value, flush);
-               break;
-       case CMD_VOLUME:
-               ret = snd_uda1341_update_bits(clnt, data0_0, 63, 0, value, flush);
-               break;
-       case CMD_BASS:
-               ret = snd_uda1341_update_bits(clnt, data0_1, 15, 2, value, flush);
-               break;
-       case CMD_TREBBLE:
-               ret = snd_uda1341_update_bits(clnt, data0_1, 3, 0, value, flush);
-               break;
-       case CMD_PEAK:
-               ret = snd_uda1341_update_bits(clnt, data0_2, 1, 5, value, flush);
-               break;
-       case CMD_DEEMP:
-               ret = snd_uda1341_update_bits(clnt, data0_2, 3, 3, value, flush);
-               break;
-       case CMD_MUTE:
-               ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, value, flush);
-               break;
-       case CMD_FILTER:
-               ret = snd_uda1341_update_bits(clnt, data0_2, 3, 0, value, flush);
-               break;
-       case CMD_CH1:
-               ret = snd_uda1341_update_bits(clnt, ext0, 31, 0, value, flush);
-               break;
-       case CMD_CH2:
-               ret = snd_uda1341_update_bits(clnt, ext1, 31, 0, value, flush);
-               break;
-       case CMD_MIC:
-               ret = snd_uda1341_update_bits(clnt, ext2, 7, 2, value, flush);
-               break;
-       case CMD_MIXER:
-               ret = snd_uda1341_update_bits(clnt, ext2, 3, 0, value, flush);
-               break;
-       case CMD_AGC:
-               ret = snd_uda1341_update_bits(clnt, ext4, 1, 4, value, flush);
-               break;
-       case CMD_IG:
-               ret = snd_uda1341_update_bits(clnt, ext4, 3, 0, value & 0x3, flush);
-               ret = snd_uda1341_update_bits(clnt, ext5, 31, 0, value >> 2, flush);
-               break;
-       case CMD_AGC_TIME:
-               ret = snd_uda1341_update_bits(clnt, ext6, 7, 2, value, flush);
-               break;
-       case CMD_AGC_LEVEL:
-               ret = snd_uda1341_update_bits(clnt, ext6, 3, 0, value, flush);
-               break;
-#ifdef CONFIG_PM               
-       case CMD_SUSPEND:
-               for (reg = stat0; reg < uda1341_reg_last; reg++)
-                       uda->suspend_regs[reg] = uda->regs[reg];
-               for (reg = 0; reg < CMD_LAST; reg++)
-                       uda->suspend_cfg[reg] = uda->cfg[reg];
-               break;
-       case CMD_RESUME:
-               for (reg = stat0; reg < uda1341_reg_last; reg++)
-                       snd_uda1341_codec_write(clnt, reg, uda->suspend_regs[reg]);
-               for (reg = 0; reg < CMD_LAST; reg++)
-                       uda->cfg[reg] = uda->suspend_cfg[reg];
-               break;
-#endif
-       default:
-               ret = -EINVAL;
-               break;
-       }
-                
-       if (!uda->active)
-               printk(KERN_ERR "UDA1341 codec not active!\n");                
-       return ret;
-}
-
-/* }}} */
-
-/* {{{ Proc interface */
-#ifdef CONFIG_PROC_FS
-
-static const char *format_names[] = {
-       "I2S-bus",
-       "LSB 16bits",
-       "LSB 18bits",
-       "LSB 20bits",
-       "MSB",
-       "in LSB 16bits/out MSB",
-       "in LSB 18bits/out MSB",
-       "in LSB 20bits/out MSB",        
-};
-
-static const char *fs_names[] = {
-       "512*fs",
-       "384*fs",
-       "256*fs",
-       "Unused - bad value!",
-};
-
-static const char* bass_values[][16] = {
-       {"0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB",
-        "0 dB", "0 dB", "0 dB", "0 dB", "undefined", }, //flat
-       {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
-        "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
-       {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
-        "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
-       {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "20 dB",
-        "22 dB", "24 dB", "24 dB", "24 dB", "undefined",}, // max
-};
-
-static const char *mic_sens_value[] = {
-       "-3 dB", "0 dB", "3 dB", "9 dB", "15 dB", "21 dB", "27 dB", "not used",
-};
-
-static const unsigned short AGC_atime[] = {
-       11, 16, 11, 16, 21, 11, 16, 21,
-};
-
-static const unsigned short AGC_dtime[] = {
-       100, 100, 200, 200, 200, 400, 400, 400,
-};
-
-static const char *AGC_level[] = {
-       "-9.0", "-11.5", "-15.0", "-17.5",
-};
-
-static const char *ig_small_value[] = {
-       "-3.0", "-2.5", "-2.0", "-1.5", "-1.0", "-0.5",
-};
-
-/*
- * this was computed as peak_value[i] = pow((63-i)*1.42,1.013)
- *
- * UDA1341 datasheet on page 21: Peak value (dB) = (Peak level - 63.5)*5*log2
- * There is an table with these values [level]=value: [3]=-90.31, [7]=-84.29
- * [61]=-2.78, [62] = -1.48, [63] = 0.0
- * I tried to compute it, but using but even using logarithm with base either 10 or 2
- * i was'n able to get values in the table from the formula. So I constructed another
- * formula (see above) to interpolate the values as good as possible. If there is some
- * mistake, please contact me on tomas.kasparek@seznam.cz. Thanks.
- * UDA1341TS datasheet is available at:
- *   http://www-us9.semiconductors.com/acrobat/datasheets/UDA1341TS_3.pdf 
- */
-static const char *peak_value[] = {
-       "-INF dB", "N.A.", "N.A", "90.31 dB", "N.A.", "N.A.", "N.A.", "-84.29 dB",
-       "-82.65 dB", "-81.13 dB", "-79.61 dB", "-78.09 dB", "-76.57 dB", "-75.05 dB", "-73.53 dB",
-       "-72.01 dB", "-70.49 dB", "-68.97 dB", "-67.45 dB", "-65.93 dB", "-64.41 dB", "-62.90 dB",
-       "-61.38 dB", "-59.86 dB", "-58.35 dB", "-56.83 dB", "-55.32 dB", "-53.80 dB", "-52.29 dB",
-       "-50.78 dB", "-49.26 dB", "-47.75 dB", "-46.24 dB", "-44.73 dB", "-43.22 dB", "-41.71 dB",
-       "-40.20 dB", "-38.69 dB", "-37.19 dB", "-35.68 dB", "-34.17 dB", "-32.67 dB", "-31.17 dB",
-       "-29.66 dB", "-28.16 dB", "-26.66 dB", "-25.16 dB", "-23.66 dB", "-22.16 dB", "-20.67 dB",
-       "-19.17 dB", "-17.68 dB", "-16.19 dB", "-14.70 dB", "-13.21 dB", "-11.72 dB", "-10.24 dB",
-       "-8.76 dB", "-7.28 dB", "-5.81 dB", "-4.34 dB", "-2.88 dB", "-1.43 dB", "0.00 dB",
-};
-
-static void snd_uda1341_proc_read(struct snd_info_entry *entry, 
-                                 struct snd_info_buffer *buffer)
-{
-       struct l3_client *clnt = entry->private_data;
-       struct uda1341 *uda = clnt->driver_data;
-       int peak;
-
-       peak = snd_uda1341_codec_read(clnt, UDA1341_DATA1);
-       if (peak < 0)
-               peak = 0;
-       
-       snd_iprintf(buffer, "%s\n\n", uda->card->longname);
-
-       // for information about computed values see UDA1341TS datasheet pages 15 - 21
-       snd_iprintf(buffer, "DAC power           : %s\n", uda->cfg[CMD_DAC] ? "on" : "off");
-       snd_iprintf(buffer, "ADC power           : %s\n", uda->cfg[CMD_ADC] ? "on" : "off");
-       snd_iprintf(buffer, "Clock frequency     : %s\n", fs_names[uda->cfg[CMD_FS]]);
-       snd_iprintf(buffer, "Data format         : %s\n\n", format_names[uda->cfg[CMD_FORMAT]]);
-
-       snd_iprintf(buffer, "Filter mode         : %s\n", filter_names[uda->cfg[CMD_FILTER]]);
-       snd_iprintf(buffer, "Mixer mode          : %s\n", mixer_names[uda->cfg[CMD_MIXER]]);
-       snd_iprintf(buffer, "De-emphasis         : %s\n", deemp_names[uda->cfg[CMD_DEEMP]]);    
-       snd_iprintf(buffer, "Peak detection pos. : %s\n", uda->cfg[CMD_PEAK] ? "after" : "before");
-       snd_iprintf(buffer, "Peak value          : %s\n\n", peak_value[peak]);          
-       
-       snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off");
-       snd_iprintf(buffer, "AGC attack time     : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]);
-       snd_iprintf(buffer, "AGC decay time      : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
-       snd_iprintf(buffer, "AGC output level    : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]);
-
-       snd_iprintf(buffer, "Mute                : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off");
-
-       if (uda->cfg[CMD_VOLUME] == 0)
-               snd_iprintf(buffer, "Volume              : 0 dB\n");
-       else if (uda->cfg[CMD_VOLUME] < 62)
-               snd_iprintf(buffer, "Volume              : %d dB\n", -1*uda->cfg[CMD_VOLUME] +1);
-       else
-               snd_iprintf(buffer, "Volume              : -INF dB\n");
-       snd_iprintf(buffer, "Bass                : %s\n", bass_values[uda->cfg[CMD_FILTER]][uda->cfg[CMD_BASS]]);
-       snd_iprintf(buffer, "Trebble             : %d dB\n", uda->cfg[CMD_FILTER] ? 2*uda->cfg[CMD_TREBBLE] : 0);
-       snd_iprintf(buffer, "Input Gain (6dB)    : %s\n", uda->cfg[CMD_IGAIN] ? "on" : "off");
-       snd_iprintf(buffer, "Output Gain (6dB)   : %s\n", uda->cfg[CMD_OGAIN] ? "on" : "off");
-       snd_iprintf(buffer, "Mic sensitivity     : %s\n", mic_sens_value[uda->cfg[CMD_MIC]]);
-
-       
-       if(uda->cfg[CMD_CH1] < 31)
-               snd_iprintf(buffer, "Mixer gain channel 1: -%d.%c dB\n",
-                           ((uda->cfg[CMD_CH1] >> 1) * 3) + (uda->cfg[CMD_CH1] & 1),
-                           uda->cfg[CMD_CH1] & 1 ? '5' : '0');
-       else
-               snd_iprintf(buffer, "Mixer gain channel 1: -INF dB\n");
-       if(uda->cfg[CMD_CH2] < 31)
-               snd_iprintf(buffer, "Mixer gain channel 2: -%d.%c dB\n",
-                           ((uda->cfg[CMD_CH2] >> 1) * 3) + (uda->cfg[CMD_CH2] & 1),
-                           uda->cfg[CMD_CH2] & 1 ? '5' : '0');
-       else
-               snd_iprintf(buffer, "Mixer gain channel 2: -INF dB\n");
-
-       if(uda->cfg[CMD_IG] > 5)
-               snd_iprintf(buffer, "Input Amp. Gain ch 2: %d.%c dB\n",
-                           (uda->cfg[CMD_IG] >> 1) -3, uda->cfg[CMD_IG] & 1 ? '5' : '0');
-       else
-               snd_iprintf(buffer, "Input Amp. Gain ch 2: %s dB\n",  ig_small_value[uda->cfg[CMD_IG]]);
-}
-
-static void snd_uda1341_proc_regs_read(struct snd_info_entry *entry, 
-                                      struct snd_info_buffer *buffer)
-{
-       struct l3_client *clnt = entry->private_data;
-       struct uda1341 *uda = clnt->driver_data;                
-       int reg;
-       char buf[12];
-
-       for (reg = 0; reg < uda1341_reg_last; reg ++) {
-               if (reg == empty)
-                       continue;
-               int2str_bin8(uda->regs[reg], buf);
-               snd_iprintf(buffer, "%s = %s\n", uda1341_reg_names[reg], buf);
-       }
-
-       int2str_bin8(snd_uda1341_codec_read(clnt, UDA1341_DATA1), buf);
-       snd_iprintf(buffer, "DATA1 = %s\n", buf);
-}
-#endif /* CONFIG_PROC_FS */
-
-static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_client *clnt)
-{
-       struct snd_info_entry *entry;
-
-       if (! snd_card_proc_new(card, "uda1341", &entry))
-               snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read);
-       if (! snd_card_proc_new(card, "uda1341-regs", &entry))
-               snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read);
-}
-
-/* }}} */
-
-/* {{{ Mixer controls setting */
-
-/* {{{ UDA1341 single functions */
-
-#define UDA1341_SINGLE(xname, where, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_single, \
-  .get = snd_uda1341_get_single, .put = snd_uda1341_put_single, \
-  .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
-}
-
-static int snd_uda1341_info_single(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 12) & 63;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_uda1341_get_single(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;
-       int where = kcontrol->private_value & 31;        
-       int mask = (kcontrol->private_value >> 12) & 63;
-       int invert = (kcontrol->private_value >> 18) & 1;
-        
-       ucontrol->value.integer.value[0] = uda->cfg[where];
-       if (invert)
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-
-       return 0;
-}
-
-static int snd_uda1341_put_single(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;
-       int where = kcontrol->private_value & 31;        
-       int reg = (kcontrol->private_value >> 5) & 15;
-       int shift = (kcontrol->private_value >> 9) & 7;
-       int mask = (kcontrol->private_value >> 12) & 63;
-       int invert = (kcontrol->private_value >> 18) & 1;
-       unsigned short val;
-
-       val = (ucontrol->value.integer.value[0] & mask);
-       if (invert)
-               val = mask - val;
-
-       uda->cfg[where] = val;
-       return snd_uda1341_update_bits(clnt, reg, mask, shift, val, FLUSH);
-}
-
-/* }}} */
-
-/* {{{ UDA1341 enum functions */
-
-#define UDA1341_ENUM(xname, where, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_enum, \
-  .get = snd_uda1341_get_enum, .put = snd_uda1341_put_enum, \
-  .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
-}
-
-static int snd_uda1341_info_enum(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       int where = kcontrol->private_value & 31;
-       const char **texts;
-       
-       // this register we don't handle this way
-       if (!uda1341_enum_items[where])
-               return -EINVAL;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = uda1341_enum_items[where];
-
-       if (uinfo->value.enumerated.item >= uda1341_enum_items[where])
-               uinfo->value.enumerated.item = uda1341_enum_items[where] - 1;
-
-       texts = uda1341_enum_names[where];
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int snd_uda1341_get_enum(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;
-       int where = kcontrol->private_value & 31;        
-        
-       ucontrol->value.enumerated.item[0] = uda->cfg[where];   
-       return 0;
-}
-
-static int snd_uda1341_put_enum(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;
-       int where = kcontrol->private_value & 31;        
-       int reg = (kcontrol->private_value >> 5) & 15;
-       int shift = (kcontrol->private_value >> 9) & 7;
-       int mask = (kcontrol->private_value >> 12) & 63;
-
-       uda->cfg[where] = (ucontrol->value.enumerated.item[0] & mask);
-       
-       return snd_uda1341_update_bits(clnt, reg, mask, shift, uda->cfg[where], FLUSH);
-}
-
-/* }}} */
-
-/* {{{ UDA1341 2regs functions */
-
-#define UDA1341_2REGS(xname, where, reg_1, reg_2, shift_1, shift_2, mask_1, mask_2, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_uda1341_info_2regs, \
-  .get = snd_uda1341_get_2regs, .put = snd_uda1341_put_2regs, \
-  .private_value = where | (reg_1 << 5) | (reg_2 << 9) | (shift_1 << 13) | (shift_2 << 16) | \
-                         (mask_1 << 19) | (mask_2 << 25) | (invert << 31) \
-}
-
-
-static int snd_uda1341_info_2regs(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       int mask_1 = (kcontrol->private_value >> 19) & 63;
-       int mask_2 = (kcontrol->private_value >> 25) & 63;
-       int mask;
-        
-       mask = (mask_2 + 1) * (mask_1 + 1) - 1;
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_uda1341_get_2regs(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;
-       int where = kcontrol->private_value & 31;
-       int mask_1 = (kcontrol->private_value >> 19) & 63;
-       int mask_2 = (kcontrol->private_value >> 25) & 63;        
-       int invert = (kcontrol->private_value >> 31) & 1;
-       int mask;
-
-       mask = (mask_2 + 1) * (mask_1 + 1) - 1;
-
-       ucontrol->value.integer.value[0] = uda->cfg[where];
-       if (invert)
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-       return 0;
-}
-
-static int snd_uda1341_put_2regs(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
-       struct uda1341 *uda = clnt->driver_data;        
-       int where = kcontrol->private_value & 31;        
-       int reg_1 = (kcontrol->private_value >> 5) & 15;
-       int reg_2 = (kcontrol->private_value >> 9) & 15;        
-       int shift_1 = (kcontrol->private_value >> 13) & 7;
-       int shift_2 = (kcontrol->private_value >> 16) & 7;
-       int mask_1 = (kcontrol->private_value >> 19) & 63;
-       int mask_2 = (kcontrol->private_value >> 25) & 63;        
-       int invert = (kcontrol->private_value >> 31) & 1;
-       int mask;
-       unsigned short val1, val2, val;
-
-       val = ucontrol->value.integer.value[0];
-         
-       mask = (mask_2 + 1) * (mask_1 + 1) - 1;
-
-       val1 = val & mask_1;
-       val2 = (val / (mask_1 + 1)) & mask_2;        
-
-       if (invert) {
-               val1 = mask_1 - val1;
-               val2 = mask_2 - val2;
-       }
-
-       uda->cfg[where] = invert ? mask - val : val;
-        
-       //FIXME - return value
-       snd_uda1341_update_bits(clnt, reg_1, mask_1, shift_1, val1, FLUSH);
-       return snd_uda1341_update_bits(clnt, reg_2, mask_2, shift_2, val2, FLUSH);
-}
-
-/* }}} */
-  
-static struct snd_kcontrol_new snd_uda1341_controls[] = {
-       UDA1341_SINGLE("Master Playback Switch", CMD_MUTE, data0_2, 2, 1, 1),
-       UDA1341_SINGLE("Master Playback Volume", CMD_VOLUME, data0_0, 0, 63, 1),
-
-       UDA1341_SINGLE("Bass Playback Volume", CMD_BASS, data0_1, 2, 15, 0),
-       UDA1341_SINGLE("Treble Playback Volume", CMD_TREBBLE, data0_1, 0, 3, 0),
-
-       UDA1341_SINGLE("Input Gain Switch", CMD_IGAIN, stat1, 5, 1, 0),
-       UDA1341_SINGLE("Output Gain Switch", CMD_OGAIN, stat1, 6, 1, 0),
-
-       UDA1341_SINGLE("Mixer Gain Channel 1 Volume", CMD_CH1, ext0, 0, 31, 1),
-       UDA1341_SINGLE("Mixer Gain Channel 2 Volume", CMD_CH2, ext1, 0, 31, 1),
-
-       UDA1341_SINGLE("Mic Sensitivity Volume", CMD_MIC, ext2, 2, 7, 0),
-
-       UDA1341_SINGLE("AGC Output Level", CMD_AGC_LEVEL, ext6, 0, 3, 0),
-       UDA1341_SINGLE("AGC Time Constant", CMD_AGC_TIME, ext6, 2, 7, 0),
-       UDA1341_SINGLE("AGC Time Constant Switch", CMD_AGC, ext4, 4, 1, 0),
-
-       UDA1341_SINGLE("DAC Power", CMD_DAC, stat1, 0, 1, 0),
-       UDA1341_SINGLE("ADC Power", CMD_ADC, stat1, 1, 1, 0),
-
-       UDA1341_ENUM("Peak detection", CMD_PEAK, data0_2, 5, 1, 0),
-       UDA1341_ENUM("De-emphasis", CMD_DEEMP, data0_2, 3, 3, 0),
-       UDA1341_ENUM("Mixer mode", CMD_MIXER, ext2, 0, 3, 0),
-       UDA1341_ENUM("Filter mode", CMD_FILTER, data0_2, 0, 3, 0),
-
-       UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0),
-};
-
-static void uda1341_free(struct l3_client *clnt)
-{
-       l3_detach_client(clnt); // calls kfree for driver_data (struct uda1341)
-       kfree(clnt);
-}
-
-static int uda1341_dev_free(struct snd_device *device)
-{
-       struct l3_client *clnt = device->device_data;
-       uda1341_free(clnt);
-       return 0;
-}
-
-int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **clntp)
-{
-       static struct snd_device_ops ops = {
-               .dev_free =     uda1341_dev_free,
-       };
-       struct l3_client *clnt;
-       int idx, err;
-
-       if (snd_BUG_ON(!card))
-               return -EINVAL;
-
-       clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
-       if (clnt == NULL)
-               return -ENOMEM;
-         
-       if ((err = l3_attach_client(clnt, "l3-bit-sa1100-gpio", UDA1341_ALSA_NAME))) {
-               kfree(clnt);
-               return err;
-       }
-
-       for (idx = 0; idx < ARRAY_SIZE(snd_uda1341_controls); idx++) {
-               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_uda1341_controls[idx], clnt))) < 0) {
-                       uda1341_free(clnt);
-                       return err;
-               }
-       }
-
-       if ((err = snd_device_new(card, SNDRV_DEV_CODEC, clnt, &ops)) < 0) {
-               uda1341_free(clnt);
-               return err;
-       }
-
-       *clntp = clnt;
-       strcpy(card->mixername, "UDA1341TS Mixer");
-       ((struct uda1341 *)clnt->driver_data)->card = card;
-        
-       snd_uda1341_proc_init(card, clnt);
-        
-       return 0;
-}
-
-/* }}} */
-
-/* {{{ L3 operations */
-
-static int uda1341_attach(struct l3_client *clnt)
-{
-       struct uda1341 *uda;
-
-       uda = kzalloc(sizeof(*uda), 0, GFP_KERNEL);
-       if (!uda)
-               return -ENOMEM;
-
-       /* init fixed parts of my copy of registers */
-       uda->regs[stat0]   = STAT0;
-       uda->regs[stat1]   = STAT1;
-
-       uda->regs[data0_0] = DATA0_0;
-       uda->regs[data0_1] = DATA0_1;
-       uda->regs[data0_2] = DATA0_2;
-
-       uda->write = snd_uda1341_codec_write;
-       uda->read = snd_uda1341_codec_read;
-  
-       spin_lock_init(&uda->reg_lock);
-        
-       clnt->driver_data = uda;
-       return 0;
-}
-
-static void uda1341_detach(struct l3_client *clnt)
-{
-       kfree(clnt->driver_data);
-}
-
-static int
-uda1341_command(struct l3_client *clnt, int cmd, void *arg)
-{
-       if (cmd != CMD_READ_REG)
-               return snd_uda1341_cfg_write(clnt, cmd, (int) arg, FLUSH);
-
-       return snd_uda1341_codec_read(clnt, (int) arg);
-}
-
-static int uda1341_open(struct l3_client *clnt)
-{
-       struct uda1341 *uda = clnt->driver_data;
-
-       uda->active = 1;
-
-       /* init default configuration */
-       snd_uda1341_cfg_write(clnt, CMD_RESET, 0, REGS_ONLY);
-       snd_uda1341_cfg_write(clnt, CMD_FS, F256, FLUSH);       // unknown state after reset
-       snd_uda1341_cfg_write(clnt, CMD_FORMAT, LSB16, FLUSH);  // unknown state after reset
-       snd_uda1341_cfg_write(clnt, CMD_OGAIN, ON, FLUSH);      // default off after reset
-       snd_uda1341_cfg_write(clnt, CMD_IGAIN, ON, FLUSH);      // default off after reset
-       snd_uda1341_cfg_write(clnt, CMD_DAC, ON, FLUSH);        // ??? default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_ADC, ON, FLUSH);        // ??? default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_VOLUME, 20, FLUSH);     // default 0dB after reset
-       snd_uda1341_cfg_write(clnt, CMD_BASS, 0, REGS_ONLY);    // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_TREBBLE, 0, REGS_ONLY); // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_PEAK, AFTER, REGS_ONLY);// default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_DEEMP, NONE, REGS_ONLY);// default value after reset
-       //at this moment should be QMUTED by h3600_audio_init
-       snd_uda1341_cfg_write(clnt, CMD_MUTE, OFF, REGS_ONLY);  // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_FILTER, MAX, FLUSH);    // defaul flat after reset
-       snd_uda1341_cfg_write(clnt, CMD_CH1, 31, FLUSH);        // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_CH2, 4, FLUSH);         // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_MIC, 4, FLUSH);         // default 0dB after reset
-       snd_uda1341_cfg_write(clnt, CMD_MIXER, MIXER, FLUSH);   // default doub.dif.mode          
-       snd_uda1341_cfg_write(clnt, CMD_AGC, OFF, FLUSH);       // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_IG, 0, FLUSH);          // unknown state after reset
-       snd_uda1341_cfg_write(clnt, CMD_AGC_TIME, 0, FLUSH);    // default value after reset
-       snd_uda1341_cfg_write(clnt, CMD_AGC_LEVEL, 0, FLUSH);   // default value after reset
-
-       return 0;
-}
-
-static void uda1341_close(struct l3_client *clnt)
-{
-       struct uda1341 *uda = clnt->driver_data;
-
-       uda->active = 0;
-}
-
-/* }}} */
-
-/* {{{ Module and L3 initialization */
-
-static struct l3_ops uda1341_ops = {
-       .open =         uda1341_open,
-       .command =      uda1341_command,
-       .close =        uda1341_close,
-};
-
-static struct l3_driver uda1341_driver = {
-       .name =         UDA1341_ALSA_NAME,
-       .attach_client = uda1341_attach,
-       .detach_client = uda1341_detach,
-       .ops =          &uda1341_ops,
-       .owner =        THIS_MODULE,
-};
-
-static int __init uda1341_init(void)
-{
-       return l3_add_driver(&uda1341_driver);
-}
-
-static void __exit uda1341_exit(void)
-{
-       l3_del_driver(&uda1341_driver);
-}
-
-module_init(uda1341_init);
-module_exit(uda1341_exit);
-
-MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Philips UDA1341 CODEC driver for ALSA");
-MODULE_SUPPORTED_DEVICE("{{UDA1341,UDA1341TS}}");
-
-EXPORT_SYMBOL(snd_chip_uda1341_mixer_new);
-
-/* }}} */
-
-/*
- * Local variables:
- * indent-tabs-mode: t
- * End:
- */
index ce0aa044e274180abfd50c04477d9c091df95562..c5c9a9218ff6ef3c209c7554c2c788eb3b516de2 100644 (file)
@@ -56,8 +56,8 @@ config SND_AD1848
          Say Y here to include support for AD1848 (Analog Devices) or
          CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
          
-         For newer chips from Cirrus Logic, use the CS4231, CS4232 or
-         CS4236+ drivers.
+         For newer chips from Cirrus Logic, use the CS4231 or CS4232+
+         drivers.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-ad1848.
@@ -94,6 +94,8 @@ config SND_CMI8330
        tristate "C-Media CMI8330"
        select SND_WSS_LIB
        select SND_SB16_DSP
+       select SND_OPL3_LIB
+       select SND_MPU401_UART
        help
          Say Y here to include support for soundcards based on the
          C-Media CMI8330 chip.
@@ -112,26 +114,15 @@ config SND_CS4231
          To compile this driver as a module, choose M here: the module
          will be called snd-cs4231.
 
-config SND_CS4232
-       tristate "Generic Cirrus Logic CS4232 driver"
-       select SND_OPL3_LIB
-       select SND_MPU401_UART
-       select SND_WSS_LIB
-       help
-         Say Y here to include support for CS4232 chips from Cirrus
-         Logic - Crystal Semiconductors.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-cs4232.
-
 config SND_CS4236
-       tristate "Generic Cirrus Logic CS4236+ driver"
+       tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_WSS_LIB
        help
-         Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
-         CS4239 chips from Cirrus Logic - Crystal Semiconductors.
+         Say Y to include support for CS4232,CS4235,CS4236,CS4237B,
+         CS4238B,CS4239 chips from Cirrus Logic - Crystal
+         Semiconductors.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-cs4236.
@@ -377,14 +368,17 @@ config SND_SGALAXY
          will be called snd-sgalaxy.
 
 config SND_SSCAPE
-       tristate "Ensoniq SoundScape PnP driver"
+       tristate "Ensoniq SoundScape driver"
        select SND_HWDEP
        select SND_MPU401_UART
        select SND_WSS_LIB
        help
-         Say Y here to include support for Ensoniq SoundScape PnP
+         Say Y here to include support for Ensoniq SoundScape 
          soundcards.
 
+         The PCM audio is supported on SoundScape Classic, Elite, PnP
+         and VIVO cards. The MIDI support is very experimental.
+
          To compile this driver as a module, choose M here: the module
          will be called snd-sscape.
 
@@ -411,5 +405,36 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
          you need to install the firmware files from the
          alsa-firmware package.
 
+config SND_MSND_PINNACLE
+       tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
+       depends on X86 && EXPERIMENTAL
+       select FW_LOADER
+       select SND_MPU401_UART
+       select SND_PCM
+       help
+         Say Y to include support for Turtle Beach MultiSound Pinnacle/
+         Fiji soundcards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-msnd-pinnacle.
+
+config SND_MSND_CLASSIC
+       tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
+       depends on X86 && EXPERIMENTAL
+       select FW_LOADER
+       select SND_MPU401_UART
+       select SND_PCM
+       help
+         Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+         Monterey (not for the Pinnacle or Fiji).
+
+         See <file:Documentation/sound/oss/MultiSound> for important information
+         about this driver.  Note that it has been discontinued, but the
+         Voyetra Turtle Beach knowledge base entry for it is still available
+         at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-msnd-classic.
+
 endif  # SND_ISA
 
index 63af13d901a5f0178c42eb9953495142e895d08b..b906b9a1a81e622654fa8628f62b9547679afe77 100644 (file)
@@ -26,5 +26,5 @@ obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
 obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
                     sb/ wavefront/ wss/
index 77524244a846458a7f561f7722e39b1e5e17b971..bbcbf92a8ebea1cb11aa8d164f7651d6ab87d11d 100644 (file)
@@ -156,10 +156,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
        struct snd_card_ad1816a *acard;
        struct snd_ad1816a *chip;
        struct snd_opl3 *opl3;
+       struct snd_timer *timer;
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct snd_card_ad1816a))) == NULL)
-               return -ENOMEM;
+       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                               sizeof(struct snd_card_ad1816a), &card);
+       if (error < 0)
+               return error;
        acard = (struct snd_card_ad1816a *)card->private_data;
 
        if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
@@ -194,6 +196,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                return error;
        }
 
+       error = snd_ad1816a_timer(chip, 0, &timer);
+       if (error < 0) {
+               snd_card_free(card);
+               return error;
+       }
+
        if (mpu_port[dev] > 0) {
                if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
                                        mpu_port[dev], 0, mpu_irq[dev], IRQF_DISABLED,
@@ -207,11 +215,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                                    OPL3_HW_AUTO, 0, &opl3) < 0) {
                        printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", fm_port[dev], fm_port[dev] + 2);
                } else {
-                       if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
-                               snd_card_free(card);
-                               return error;
-                       }
-                       if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+                       error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+                       if (error < 0) {
                                snd_card_free(card);
                                return error;
                        }
index 3bfca7c59bafe5eaa2e994f44ecc658700e15abd..05aef8b97e968e1e2d9678a805ac04d2df4eb481 100644 (file)
@@ -37,7 +37,7 @@ static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
                if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
                        return 0;
 
-       snd_printk("chip busy.\n");
+       snd_printk(KERN_WARNING "chip busy.\n");
        return -EBUSY;
 }
 
@@ -196,7 +196,7 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
                spin_unlock(&chip->lock);
                break;
        default:
-               snd_printk("invalid trigger mode 0x%x.\n", what);
+               snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
                error = -EINVAL;
        }
 
@@ -377,7 +377,6 @@ static struct snd_pcm_hardware snd_ad1816a_capture = {
        .fifo_size =            0,
 };
 
-#if 0 /* not used now */
 static int snd_ad1816a_timer_close(struct snd_timer *timer)
 {
        struct snd_ad1816a *chip = snd_timer_chip(timer);
@@ -442,8 +441,6 @@ static struct snd_timer_hardware snd_ad1816a_timer_table = {
        .start =        snd_ad1816a_timer_start,
        .stop =         snd_ad1816a_timer_stop,
 };
-#endif /* not used now */
-
 
 static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
 {
@@ -568,7 +565,7 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
        case AD1816A_HW_AD1815: return "AD1815";
        case AD1816A_HW_AD18MAX10: return "AD18max10";
        default:
-               snd_printk("Unknown chip version %d:%d.\n",
+               snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
                        chip->version, chip->hardware);
                return "AD1816A - unknown";
        }
@@ -687,7 +684,6 @@ int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_p
        return 0;
 }
 
-#if 0 /* not used now */
 int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd_timer **rtimer)
 {
        struct snd_timer *timer;
@@ -709,7 +705,6 @@ int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd
                *rtimer = timer;
        return 0;
 }
-#endif /* not used now */
 
 /*
  *
index 223a6c038819217a2d5bfb74e81bfd6a56ba1d86..4beeb6f98e0eab9b06d291aa4ac3ea9451f43d95 100644 (file)
@@ -91,9 +91,9 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
        struct snd_pcm *pcm;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card)
-               return -EINVAL;
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0)
+               return error;
 
        error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
                        thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
index 374b7177e111d2f806930d84cdb147c1ace28356..7465ae036e0bd9e871ef632e03207e2347bf7b73 100644 (file)
@@ -53,10 +53,10 @@ static int __devinit snd_adlib_probe(struct device *dev, unsigned int n)
        struct snd_opl3 *opl3;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card) {
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0) {
                dev_err(dev, "could not create card\n");
-               return -EINVAL;
+               return error;
        }
 
        card->private_data = request_region(port[n], 4, CRD_NAME);
index f1ce30f379c9d5fa06ef68b62b5643b08596871c..5fd52e4d707998769f317b8dbbaf3d7e0839f9f4 100644 (file)
@@ -163,9 +163,10 @@ static int __devinit snd_card_als100_probe(int dev,
        struct snd_card_als100 *acard;
        struct snd_opl3 *opl3;
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct snd_card_als100))) == NULL)
-               return -ENOMEM;
+       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                               sizeof(struct snd_card_als100), &card);
+       if (error < 0)
+               return error;
        acard = card->private_data;
 
        if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
index 3e74d1a3928e7f8b6067090cb54f13645f6e746b..f7aa637b0d181497fccdf1f48ff7f352b68ad5e2 100644 (file)
@@ -184,9 +184,10 @@ static int __devinit snd_card_azt2320_probe(int dev,
        struct snd_wss *chip;
        struct snd_opl3 *opl3;
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct snd_card_azt2320))) == NULL)
-               return -ENOMEM;
+       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                               sizeof(struct snd_card_azt2320), &card);
+       if (error < 0)
+               return error;
        acard = (struct snd_card_azt2320 *)card->private_data;
 
        if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
index e49aec700a556681ea1e5f05b3e68da7d571852d..de83608719ea23138a793e2c557444add2f4001e 100644 (file)
  *  To quickly load the module,
  *
  *  modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
- *    sbdma16=5 wssport=0x530 wssirq=11 wssdma=0
+ *    sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 fmport=0x388
  *
  *  This card has two mixers and two PCM devices.  I've cheesed it such
  *  that recording and playback can be done through the same device.
- *  The driver "magically" routes the capturing to the AD1848 codec,
+ *  The driver "magically" routes the capturing to the CMI8330 codec,
  *  and playback to the SB16 codec.  This allows for full-duplex mode
  *  to some extent.
  *  The utilities in alsa-utils are aware of both devices, so passing
@@ -51,6 +51,8 @@
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
 #include <sound/sb.h>
 #include <sound/initval.h>
 
@@ -79,6 +81,9 @@ static int sbdma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
 static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
@@ -107,6 +112,12 @@ MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
 module_param_array(wssdma, int, NULL, 0444);
 MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
 
+module_param_array(fmport, long, NULL, 0444);
+MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver.");
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port.");
 #ifdef CONFIG_PNP
 static int isa_registered;
 static int pnp_registered;
@@ -149,6 +160,7 @@ struct snd_cmi8330 {
 #ifdef CONFIG_PNP
        struct pnp_dev *cap;
        struct pnp_dev *play;
+       struct pnp_dev *mpu;
 #endif
        struct snd_card *card;
        struct snd_wss *wss;
@@ -165,7 +177,7 @@ struct snd_cmi8330 {
 #ifdef CONFIG_PNP
 
 static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
-       { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" } } },
+       { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
        { .id = "" }
 };
 
@@ -219,8 +231,10 @@ WSS_SINGLE("3D Control - Switch", 0,
                CMI8330_RMUX3D, 5, 1, 1),
 WSS_SINGLE("PC Speaker Playback Volume", 0,
                CMI8330_OUTPUTVOL, 3, 3, 0),
-WSS_SINGLE("FM Playback Switch", 0,
-               CMI8330_RECMUX, 3, 1, 1),
+WSS_DOUBLE("FM Playback Switch", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+               CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
 WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
                CMI8330_RMUX3D, 7, 1, 1),
 WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
@@ -323,16 +337,21 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
        if (acard->play == NULL)
                return -EBUSY;
 
+       acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
+       if (acard->play == NULL)
+               return -EBUSY;
+
        pdev = acard->cap;
 
        err = pnp_activate_dev(pdev);
        if (err < 0) {
-               snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n");
+               snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n");
                return -EBUSY;
        }
        wssport[dev] = pnp_port_start(pdev, 0);
        wssdma[dev] = pnp_dma(pdev, 0);
        wssirq[dev] = pnp_irq(pdev, 0);
+       fmport[dev] = pnp_port_start(pdev, 1);
 
        /* allocate SB16 resources */
        pdev = acard->play;
@@ -347,6 +366,17 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
        sbdma16[dev] = pnp_dma(pdev, 1);
        sbirq[dev] = pnp_irq(pdev, 0);
 
+       /* allocate MPU-401 resources */
+       pdev = acard->mpu;
+
+       err = pnp_activate_dev(pdev);
+       if (err < 0) {
+               snd_printk(KERN_ERR
+                          "CMI8330/C3D (MPU-401) PnP configure failure\n");
+               return -EBUSY;
+       }
+       mpuport[dev] = pnp_port_start(pdev, 0);
+       mpuirq[dev] = pnp_irq(pdev, 0);
        return 0;
 }
 #endif
@@ -467,26 +497,29 @@ static int snd_cmi8330_resume(struct snd_card *card)
 
 #define PFX    "cmi8330: "
 
-static struct snd_card *snd_cmi8330_card_new(int dev)
+static int snd_cmi8330_card_new(int dev, struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_cmi8330 *acard;
+       int err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_cmi8330));
-       if (card == NULL) {
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_cmi8330), &card);
+       if (err < 0) {
                snd_printk(KERN_ERR PFX "could not get a new card\n");
-               return NULL;
+               return err;
        }
        acard = card->private_data;
        acard->card = card;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
 {
        struct snd_cmi8330 *acard;
        int i, err;
+       struct snd_opl3 *opl3;
 
        acard = card->private_data;
        err = snd_wss_create(card, wssport[dev] + 4, -1,
@@ -494,11 +527,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
                             wssdma[dev], -1,
                             WSS_HW_DETECT, 0, &acard->wss);
        if (err < 0) {
-               snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
+               snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n");
                return err;
        }
        if (acard->wss->hardware != WSS_HW_CMI8330) {
-               snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
+               snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n");
                return -ENODEV;
        }
 
@@ -530,6 +563,27 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
                snd_printk(KERN_ERR PFX "failed to create pcms\n");
                return err;
        }
+       if (fmport[dev] != SNDRV_AUTO_PORT) {
+               if (snd_opl3_create(card,
+                                   fmport[dev], fmport[dev] + 2,
+                                   OPL3_HW_AUTO, 0, &opl3) < 0) {
+                       snd_printk(KERN_ERR PFX
+                                  "no OPL device at 0x%lx-0x%lx ?\n",
+                                  fmport[dev], fmport[dev] + 2);
+               } else {
+                       err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       if (mpuport[dev] != SNDRV_AUTO_PORT) {
+               if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                                       mpuport[dev], 0, mpuirq[dev],
+                                       IRQF_DISABLED, NULL) < 0)
+                       printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
+                               mpuport[dev]);
+       }
 
        strcpy(card->driver, "CMI8330/C3D");
        strcpy(card->shortname, "C-Media CMI8330/C3D");
@@ -564,9 +618,9 @@ static int __devinit snd_cmi8330_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       card = snd_cmi8330_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_cmi8330_card_new(dev, &card);
+       if (err < 0)
+               return err;
        snd_card_set_dev(card, pdev);
        if ((err = snd_cmi8330_probe(card, dev)) < 0) {
                snd_card_free(card);
@@ -628,9 +682,9 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
                               
-       card = snd_cmi8330_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_cmi8330_card_new(dev, &card);
+       if (res < 0)
+               return res;
        if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
                snd_printk(KERN_ERR PFX "PnP detection failed\n");
                snd_card_free(card);
index 5870ca21ab59c24e135abb500c1d5e1ed4c5b633..6d397e8d54acee86a40046d171a93d603f3e8972 100644 (file)
@@ -3,13 +3,11 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-cs4236-lib-objs := cs4236_lib.o
 snd-cs4231-objs := cs4231.o
-snd-cs4232-objs := cs4232.o
-snd-cs4236-objs := cs4236.o
+snd-cs4236-objs := cs4236.o cs4236_lib.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
-obj-$(CONFIG_SND_CS4232) += snd-cs4232.o
-obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o
+obj-$(CONFIG_SND_CS4236) += snd-cs4236.o
+
 
index f019d449e2d65cd243c9a5aec5b51c35441c5e99..cb9153e75b8228ab75851b42d74900dae4c263e8 100644 (file)
@@ -95,9 +95,9 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
        struct snd_pcm *pcm;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card)
-               return -EINVAL;
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0)
+               return error;
 
        error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
                        WSS_HW_DETECT, 0, &chip);
diff --git a/sound/isa/cs423x/cs4232.c b/sound/isa/cs423x/cs4232.c
deleted file mode 100644 (file)
index 9fad2e6..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CS4232
-#include "cs4236.c"
index 019c9401663eb9839787f63f4b32d0d9f1cba20b..a076a6ce8071b344ff12d9ce4be8305f4ec8b67e 100644 (file)
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-#ifdef CS4232
-MODULE_DESCRIPTION("Cirrus Logic CS4232");
+MODULE_DESCRIPTION("Cirrus Logic CS4232-9");
 MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000},"
                "{Turtle Beach,Tropez Plus},"
                "{SIC CrystalWave 32},"
                "{Hewlett Packard,Omnibook 5500},"
                "{TerraTec,Maestro 32/96},"
-               "{Philips,PCA70PS}}");
-#else
-MODULE_DESCRIPTION("Cirrus Logic CS4235-9");
-MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
+               "{Philips,PCA70PS}},"
+               "{{Crystal Semiconductors,CS4235},"
                "{Crystal Semiconductors,CS4236},"
                "{Crystal Semiconductors,CS4237},"
                "{Crystal Semiconductors,CS4238},"
@@ -70,15 +67,11 @@ MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
                "{Typhoon Soundsystem,CS4236B},"
                "{Turtle Beach,Malibu},"
                "{Unknown,Digital PC 5000 Onboard}}");
-#endif
 
-#ifdef CS4232
-#define IDENT "CS4232"
-#define DEV_NAME "cs4232"
-#else
-#define IDENT "CS4236+"
-#define DEV_NAME "cs4236"
-#endif
+MODULE_ALIAS("snd_cs4232");
+
+#define IDENT "CS4232+"
+#define DEV_NAME "cs4232+"
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
@@ -128,9 +121,7 @@ MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
 #ifdef CONFIG_PNP
 static int isa_registered;
 static int pnpc_registered;
-#ifdef CS4232
 static int pnp_registered;
-#endif
 #endif /* CONFIG_PNP */
 
 struct snd_card_cs4236 {
@@ -145,11 +136,10 @@ struct snd_card_cs4236 {
 
 #ifdef CONFIG_PNP
 
-#ifdef CS4232
 /*
  * PNP BIOS
  */
-static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
+static const struct pnp_device_id snd_cs423x_pnpbiosids[] = {
        { .id = "CSC0100" },
        { .id = "CSC0000" },
        /* Guillemot Turtlebeach something appears to be cs4232 compatible
@@ -157,10 +147,8 @@ static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
        { .id = "GIM0100" },
        { .id = "" }
 };
-MODULE_DEVICE_TABLE(pnp, snd_cs4232_pnpbiosids);
-#endif /* CS4232 */
+MODULE_DEVICE_TABLE(pnp, snd_cs423x_pnpbiosids);
 
-#ifdef CS4232
 #define CS423X_ISAPNP_DRIVER   "cs4232_isapnp"
 static struct pnp_card_device_id snd_cs423x_pnpids[] = {
        /* Philips PCA70PS */
@@ -179,12 +167,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
        { .id = "CSCf032", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
        /* Netfinity 3000 on-board soundcard */
        { .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC010f" } } },
-       /* --- */
-       { .id = "" }    /* end */
-};
-#else /* CS4236 */
-#define CS423X_ISAPNP_DRIVER   "cs4236_isapnp"
-static struct pnp_card_device_id snd_cs423x_pnpids[] = {
        /* Intel Marlin Spike Motherboard - CS4235 */
        { .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
        /* Intel Marlin Spike Motherboard (#2) - CS4235 */
@@ -266,7 +248,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
        /* --- */
        { .id = "" }    /* end */
 };
-#endif
 
 MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
 
@@ -323,17 +304,19 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
        return 0;
 }
 
-#ifdef CS4232
-static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
-                                        struct pnp_dev *pdev)
+static int __devinit snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard,
+                                        struct pnp_dev *pdev,
+                                        struct pnp_dev *cdev)
 {
        acard->wss = pdev;
        if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
                return -EBUSY;
-       cport[dev] = -1;
+       if (cdev)
+               cport[dev] = pnp_port_start(cdev, 0);
+       else
+               cport[dev] = -1;
        return 0;
 }
-#endif
 
 static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
                                          struct pnp_card_link *card,
@@ -382,16 +365,18 @@ static void snd_card_cs4236_free(struct snd_card *card)
        release_and_free_resource(acard->res_sb_port);
 }
 
-static struct snd_card *snd_cs423x_card_new(int dev)
+static int snd_cs423x_card_new(int dev, struct snd_card **cardp)
 {
        struct snd_card *card;
+       int err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_card_cs4236));
-       if (card == NULL)
-               return NULL;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_card_cs4236), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_card_cs4236_free;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
@@ -409,40 +394,39 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
                        return -EBUSY;
                }
 
-#ifdef CS4232
        err = snd_wss_create(card, port[dev], cport[dev],
                             irq[dev],
                             dma1[dev], dma2[dev],
-                            WSS_HW_DETECT, 0, &chip);
-       if (err < 0)
-               return err;
-       acard->chip = chip;
-
-       err = snd_wss_pcm(chip, 0, &pcm);
-       if (err < 0)
-               return err;
-
-       err = snd_wss_mixer(chip);
+                            WSS_HW_DETECT3, 0, &chip);
        if (err < 0)
                return err;
-
-#else /* CS4236 */
-       err = snd_cs4236_create(card,
-                               port[dev], cport[dev],
-                               irq[dev], dma1[dev], dma2[dev],
-                               WSS_HW_DETECT, 0, &chip);
-       if (err < 0)
-               return err;
-       acard->chip = chip;
-
-       err = snd_cs4236_pcm(chip, 0, &pcm);
-       if (err < 0)
-               return err;
-
-       err = snd_cs4236_mixer(chip);
-       if (err < 0)
-               return err;
-#endif
+       if (chip->hardware & WSS_HW_CS4236B_MASK) {
+               snd_wss_free(chip);
+               err = snd_cs4236_create(card,
+                                       port[dev], cport[dev],
+                                       irq[dev], dma1[dev], dma2[dev],
+                                       WSS_HW_DETECT, 0, &chip);
+               if (err < 0)
+                       return err;
+               acard->chip = chip;
+
+               err = snd_cs4236_pcm(chip, 0, &pcm);
+               if (err < 0)
+                       return err;
+
+               err = snd_cs4236_mixer(chip);
+               if (err < 0)
+                       return err;
+       } else {
+               acard->chip = chip;
+               err = snd_wss_pcm(chip, 0, &pcm);
+               if (err < 0)
+                       return err;
+
+               err = snd_wss_mixer(chip);
+               if (err < 0)
+                       return err;
+       }
        strcpy(card->driver, pcm->name);
        strcpy(card->shortname, pcm->name);
        sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
@@ -512,9 +496,9 @@ static int __devinit snd_cs423x_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       card = snd_cs423x_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_cs423x_card_new(dev, &card);
+       if (err < 0)
+               return err;
        snd_card_set_dev(card, pdev);
        if ((err = snd_cs423x_probe(card, dev)) < 0) {
                snd_card_free(card);
@@ -577,13 +561,14 @@ static struct isa_driver cs423x_isa_driver = {
 
 
 #ifdef CONFIG_PNP
-#ifdef CS4232
-static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
+static int __devinit snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
                                               const struct pnp_device_id *id)
 {
        static int dev;
        int err;
        struct snd_card *card;
+       struct pnp_dev *cdev;
+       char cid[PNP_ID_LEN];
 
        if (pnp_device_is_isapnp(pdev))
                return -ENOENT; /* we have another procedure - card */
@@ -594,10 +579,19 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_cs423x_card_new(dev);
-       if (! card)
-               return -ENOMEM;
-       if ((err = snd_card_cs4232_pnp(dev, card->private_data, pdev)) < 0) {
+       /* prepare second id */
+       strcpy(cid, pdev->id[0].id);
+       cid[5] = '1';
+       cdev = NULL;
+       list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) {
+               if (!strcmp(cdev->id[0].id, cid))
+                       break;
+       }
+       err = snd_cs423x_card_new(dev, &card);
+       if (err < 0)
+               return err;
+       err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
+       if (err < 0) {
                printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
                snd_card_free(card);
                return err;
@@ -612,35 +606,34 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
        return 0;
 }
 
-static void __devexit snd_cs4232_pnp_remove(struct pnp_dev * pdev)
+static void __devexit snd_cs423x_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
        pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
-static int snd_cs4232_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+static int snd_cs423x_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
 {
        return snd_cs423x_suspend(pnp_get_drvdata(pdev));
 }
 
-static int snd_cs4232_pnp_resume(struct pnp_dev *pdev)
+static int snd_cs423x_pnp_resume(struct pnp_dev *pdev)
 {
        return snd_cs423x_resume(pnp_get_drvdata(pdev));
 }
 #endif
 
-static struct pnp_driver cs4232_pnp_driver = {
-       .name = "cs4232-pnpbios",
-       .id_table = snd_cs4232_pnpbiosids,
-       .probe = snd_cs4232_pnpbios_detect,
-       .remove = __devexit_p(snd_cs4232_pnp_remove),
+static struct pnp_driver cs423x_pnp_driver = {
+       .name = "cs423x-pnpbios",
+       .id_table = snd_cs423x_pnpbiosids,
+       .probe = snd_cs423x_pnpbios_detect,
+       .remove = __devexit_p(snd_cs423x_pnp_remove),
 #ifdef CONFIG_PM
-       .suspend        = snd_cs4232_pnp_suspend,
-       .resume         = snd_cs4232_pnp_resume,
+       .suspend        = snd_cs423x_pnp_suspend,
+       .resume         = snd_cs423x_pnp_resume,
 #endif
 };
-#endif /* CS4232 */
 
 static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
                                            const struct pnp_card_device_id *pid)
@@ -656,9 +649,9 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_cs423x_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_cs423x_card_new(dev, &card);
+       if (res < 0)
+               return res;
        if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
                printk(KERN_ERR "isapnp detection failed and probing for " IDENT
                       " is not supported\n");
@@ -714,18 +707,14 @@ static int __init alsa_card_cs423x_init(void)
 #ifdef CONFIG_PNP
        if (!err)
                isa_registered = 1;
-#ifdef CS4232
-       err = pnp_register_driver(&cs4232_pnp_driver);
+       err = pnp_register_driver(&cs423x_pnp_driver);
        if (!err)
                pnp_registered = 1;
-#endif
        err = pnp_register_card_driver(&cs423x_pnpc_driver);
        if (!err)
                pnpc_registered = 1;
-#ifdef CS4232
        if (pnp_registered)
                err = 0;
-#endif
        if (isa_registered)
                err = 0;
 #endif
@@ -737,10 +726,8 @@ static void __exit alsa_card_cs423x_exit(void)
 #ifdef CONFIG_PNP
        if (pnpc_registered)
                pnp_unregister_card_driver(&cs423x_pnpc_driver);
-#ifdef CS4232
        if (pnp_registered)
-               pnp_unregister_driver(&cs4232_pnp_driver);
-#endif
+               pnp_unregister_driver(&cs423x_pnp_driver);
        if (isa_registered)
 #endif
                isa_unregister_driver(&cs423x_isa_driver);
index 6a85fdc53b60a716f248ad1c20210f1148732cd6..38835f31298bfd85c2db009ee7d9070f905db672 100644 (file)
 #include <sound/wss.h>
 #include <sound/asoundef.h>
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips");
-MODULE_LICENSE("GPL");
-
 /*
  *
  */
@@ -286,7 +282,8 @@ int snd_cs4236_create(struct snd_card *card,
        if (hardware == WSS_HW_DETECT)
                hardware = WSS_HW_DETECT3;
        if (cport < 0x100) {
-               snd_printk("please, specify control port for CS4236+ chips\n");
+               snd_printk(KERN_ERR "please, specify control port "
+                          "for CS4236+ chips\n");
                return -ENODEV;
        }
        err = snd_wss_create(card, port, cport,
@@ -295,7 +292,8 @@ int snd_cs4236_create(struct snd_card *card,
                return err;
 
        if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
-               snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
+               snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
+                          "not available, hardware=0x%x\n", chip->hardware);
                snd_device_free(card, chip);
                return -ENODEV;
        }
@@ -303,16 +301,19 @@ int snd_cs4236_create(struct snd_card *card,
        {
                int idx;
                for (idx = 0; idx < 8; idx++)
-                       snd_printk("CD%i = 0x%x\n", idx, inb(chip->cport + idx));
+                       snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
+                                  idx, inb(chip->cport + idx));
                for (idx = 0; idx < 9; idx++)
-                       snd_printk("C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx));
+                       snd_printk(KERN_DEBUG "C%i = 0x%x\n",
+                                  idx, snd_cs4236_ctrl_in(chip, idx));
        }
 #endif
        ver1 = snd_cs4236_ctrl_in(chip, 1);
        ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
        snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
        if (ver1 != ver2) {
-               snd_printk("CS4236+ chip detected, but control port 0x%lx is not valid\n", cport);
+               snd_printk(KERN_ERR "CS4236+ chip detected, but "
+                          "control port 0x%lx is not valid\n", cport);
                snd_device_free(card, chip);
                return -ENODEV;
        }
@@ -883,7 +884,8 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
        spin_lock_irqsave(&chip->reg_lock, flags);
        ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
 #if 0
-       printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+       printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+              "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
                        snd_wss_in(chip, CS4231_ALT_FEATURE_1),
                        snd_cs4236_ctrl_in(chip, 3),
                        snd_cs4236_ctrl_in(chip, 4),
@@ -920,7 +922,8 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
        mutex_unlock(&chip->mce_mutex);
 
 #if 0
-       printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+       printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+              "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
                        snd_wss_in(chip, CS4231_ALT_FEATURE_1),
                        snd_cs4236_ctrl_in(chip, 3),
                        snd_cs4236_ctrl_in(chip, 4),
@@ -1015,23 +1018,3 @@ int snd_cs4236_mixer(struct snd_wss *chip)
        }
        return 0;
 }
-
-EXPORT_SYMBOL(snd_cs4236_create);
-EXPORT_SYMBOL(snd_cs4236_pcm);
-EXPORT_SYMBOL(snd_cs4236_mixer);
-
-/*
- *  INIT part
- */
-
-static int __init alsa_cs4236_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_cs4236_exit(void)
-{
-}
-
-module_init(alsa_cs4236_init)
-module_exit(alsa_cs4236_exit)
index a0242c3b613ef2a22dabb34531724883cc62e529..80f5b1af9be8e9d3ea908502880660f49200c267 100644 (file)
@@ -150,9 +150,10 @@ static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard,
        struct snd_card_dt019x *acard;
        struct snd_opl3 *opl3;
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct snd_card_dt019x))) == NULL)
-               return -ENOMEM;
+       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                               sizeof(struct snd_card_dt019x), &card);
+       if (error < 0)
+               return error;
        acard = card->private_data;
 
        snd_card_set_dev(card, &pcard->card->dev);
index b46377139cf81d4ffc73d1e10572f6996c5ad4c3..442b081cafb755f90ed2181d73cbeea9fe5a2279 100644 (file)
@@ -49,6 +49,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;    /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260 */
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
 static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 5,7,9,10 */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;   /* 5,7,9,10 */
@@ -65,6 +66,8 @@ MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
 module_param_array(mpu_port, long, NULL, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
 module_param_array(irq, int, NULL, 0444);
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for ES1688 driver.");
 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
 module_param_array(mpu_irq, int, NULL, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
@@ -122,9 +125,9 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
        struct snd_pcm *pcm;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card)
-               return -EINVAL;
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0)
+               return error;
 
        error = snd_es1688_legacy_create(card, dev, n, &chip);
        if (error < 0)
@@ -143,13 +146,19 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
        sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name,
                chip->port, chip->irq, chip->dma8);
 
-       if (snd_opl3_create(card, chip->port, chip->port + 2,
-                       OPL3_HW_OPL3, 0, &opl3) < 0)
-               dev_warn(dev, "opl3 not detected at 0x%lx\n", chip->port);
-       else {
-               error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
-               if (error < 0)
-                       goto out;
+       if (fm_port[n] == SNDRV_AUTO_PORT)
+               fm_port[n] = port[n];   /* share the same port */
+
+       if (fm_port[n] > 0) {
+               if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+                               OPL3_HW_OPL3, 0, &opl3) < 0)
+                       dev_warn(dev,
+                                "opl3 not detected at 0x%lx\n", fm_port[n]);
+               else {
+                       error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+                       if (error < 0)
+                               goto out;
+               }
        }
 
        if (mpu_irq[n] >= 0 && mpu_irq[n] != SNDRV_AUTO_IRQ &&
index 4fbb508a817f39485406800431c87fc7130c8450..4c6e14f87f2d816c4f843bed883aec20c1bd732e 100644 (file)
@@ -45,7 +45,7 @@ static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
                        return 1;
                }
 #ifdef CONFIG_SND_DEBUG
-       printk("snd_es1688_dsp_command: timeout (0x%x)\n", val);
+       printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
 #endif
        return 0;
 }
@@ -167,13 +167,16 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
        hw = ES1688_HW_AUTO;
        switch (chip->version & 0xfff0) {
        case 0x4880:
-               snd_printk("[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n", chip->port);
+               snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
+                          "but driver is in another place\n", chip->port);
                return -ENODEV;
        case 0x6880:
                hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688;
                break;
        default:
-               snd_printk("[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n", chip->port, chip->version);
+               snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
+                          "with version 0x%x (Jazz16 soundcard?)\n",
+                          chip->port, chip->version);
                return -ENODEV;
        }
 
@@ -223,7 +226,7 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
                }
        }
 #if 0
-       snd_printk("mpu cfg = 0x%x\n", cfg);
+       snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
 #endif
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_es1688_mixer_write(chip, 0x40, cfg);
@@ -237,7 +240,9 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
                cfg = 0xf0;     /* enable only DMA counter interrupt */
                irq_bits = irqs[chip->irq & 0x0f];
                if (irq_bits < 0) {
-                       snd_printk("[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n", chip->port, chip->irq);
+                       snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
+                                  "for ES1688 chip!!\n",
+                                  chip->port, chip->irq);
 #if 0
                        irq_bits = 0;
                        cfg = 0x10;
@@ -250,7 +255,8 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
                cfg = 0xf0;     /* extended mode DMA enable */
                dma = chip->dma8;
                if (dma > 3 || dma == 2) {
-                       snd_printk("[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n", chip->port, dma);
+                       snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
+                                  "for ES1688 chip!!\n", chip->port, dma);
 #if 0
                        dma_bits = 0;
                        cfg = 0x00;     /* disable all DMA */
@@ -341,8 +347,9 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va
                return -EINVAL; /* something is wrong */
        }
 #if 0
-       printk("trigger: val = 0x%x, value = 0x%x\n", val, value);
-       printk("trigger: pointer = 0x%x\n", snd_dma_pointer(chip->dma8, chip->dma_size));
+       printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
+       printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
+              snd_dma_pointer(chip->dma8, chip->dma_size));
 #endif
        snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
        spin_unlock(&chip->reg_lock);
index 90498e4ca2601f3c82005a4de4eaafd5e857d935..8cfbff73a8357416ad45a7d51c63cb298e5ba90f 100644 (file)
@@ -2125,10 +2125,10 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
 #define is_isapnp_selected(dev)                0
 #endif
 
-static struct snd_card *snd_es18xx_card_new(int dev)
+static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
 {
-       return snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_audiodrive));
+       return snd_card_create(index[dev], id[dev], THIS_MODULE,
+                              sizeof(struct snd_audiodrive), cardp);
 }
 
 static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
@@ -2197,9 +2197,9 @@ static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr)
        struct snd_card *card;
        int err;
 
-       card = snd_es18xx_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_es18xx_card_new(dev, &card);
+       if (err < 0)
+               return err;
        snd_card_set_dev(card, devptr);
        if ((err = snd_audiodrive_probe(card, dev)) < 0) {
                snd_card_free(card);
@@ -2303,9 +2303,9 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_es18xx_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_es18xx_card_new(dev, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
@@ -2362,9 +2362,9 @@ static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_es18xx_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_es18xx_card_new(dev, &card);
+       if (res < 0)
+               return res;
 
        if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
                snd_card_free(card);
index f45f6116c77ab03d7f171717617f5569a0f4127c..36c27c832360180e9b31edb60d3aebc85eaf4bfe 100644 (file)
@@ -45,7 +45,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
        unsigned char dma_cmd;
        unsigned int address_high;
 
-       // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count);
+       snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
+                   addr, buf_addr, count);
 
        if (gus->gf1.dma1 > 3) {
                if (gus->gf1.enh_mode) {
@@ -77,7 +78,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
        snd_gf1_dma_ack(gus);
        snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
 #if 0
-       snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd);
+       snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
+                  address << 1, count, dma_cmd);
 #endif
        spin_lock_irqsave(&gus->reg_lock, flags);
        if (gus->gf1.enh_mode) {
@@ -142,7 +144,9 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
        snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
        kfree(block);
 #if 0
-       printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd);
+       snd_printd(KERN_DEBUG "program dma (IRQ) - "
+                  "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+                  block->addr, block->buf_addr, block->count, block->cmd);
 #endif
 }
 
@@ -203,13 +207,16 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
        }
        *block = *__block;
        block->next = NULL;
-#if 0
-       printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd);
-#endif
-#if 0
-       printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last);
-       printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm);
-#endif
+
+       snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+                   block->addr, (long) block->buffer, block->count,
+                   block->cmd);
+
+       snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
+                   (long)gus->gf1.dma_data_pcm_last);
+       snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
+                   (long)gus->gf1.dma_data_pcm);
+
        spin_lock_irqsave(&gus->dma_lock, flags);
        if (synth) {
                if (gus->gf1.dma_data_synth_last) {
index 041894ddd014ab2966c4b13a9a002416f026e530..2055aff71b50ff4a50613a66905e007620aa876f 100644 (file)
@@ -41,7 +41,7 @@ __again:
        if (status == 0)
                return IRQ_RETVAL(handled);
        handled = 1;
-       // snd_printk("IRQ: status = 0x%x\n", status);
+       /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
        if (status & 0x02) {
                STAT_ADD(gus->gf1.interrupt_stat_midi_in);
                if (gus->gf1.interrupt_handler_midi_in)
@@ -65,7 +65,9 @@ __again:
                                continue;       /* multi request */
                        already |= _current_;   /* mark request */
 #if 0
-                       printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE)));
+                       printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
+                              "voice_verify = %i\n",
+                              voice, voice_status, inb(GUSP(gus, GF1PAGE)));
 #endif
                        pvoice = &gus->gf1.voices[voice]; 
                        if (pvoice->use) {
index 38510aeb21c64893a988a900224bd7420b037ff2..edb11eefdfe3e2097f25037cd5bf507de817bdc7 100644 (file)
@@ -82,7 +82,10 @@ static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
 
        count += offset & 31;
        offset &= ~31;
-       // snd_printk("block change - offset = 0x%x, count = 0x%x\n", offset, count);
+       /*
+       snd_printk(KERN_DEBUG "block change - offset = 0x%x, count = 0x%x\n",
+                  offset, count);
+       */
        memset(&block, 0, sizeof(block));
        block.cmd = SNDRV_GF1_DMA_IRQ;
        if (snd_pcm_format_unsigned(runtime->format))
@@ -135,7 +138,11 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
                curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
                end = curr + (pcmp->block_size / runtime->channels);
                end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
-               // snd_printk("init: curr=0x%x, begin=0x%x, end=0x%x, ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+               /*
+               snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, "
+                          "ctrl=0x%x, ramp=0x%x, rate=0x%x\n",
+                          curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+               */
                pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
                vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
                spin_lock_irqsave(&gus->reg_lock, flags);
@@ -205,9 +212,11 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
        ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
 #if 0
        snd_gf1_select_voice(gus, pvoice->number);
-       printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+       printk(KERN_DEBUG "position = 0x%x\n",
+              (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
        snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
-       printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+       printk(KERN_DEBUG "position = 0x%x\n",
+              (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
        snd_gf1_select_voice(gus, pvoice->number);
 #endif
        pcmp->bpos++;
@@ -299,7 +308,11 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
        unsigned int len;
        unsigned long flags;
 
-       // printk("poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port);
+       /*
+       printk(KERN_DEBUG
+              "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n",
+              (int)buf, pos, count, gus->gf1.port);
+       */
        while (count > 0) {
                len = count;
                if (len > 512)          /* limit, to allow IRQ */
@@ -680,7 +693,8 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)
        runtime->private_free = snd_gf1_pcm_playback_free;
 
 #if 0
-       printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
+       printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
+              (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
 #endif
        if ((err = snd_gf1_dma_init(gus)) < 0)
                return err;
index f0af3f79b08bae4167eb98ed00e9d7b107b5559d..21cc42e4c4be8aa91dc5a910f5013e5cb256da73 100644 (file)
@@ -129,8 +129,14 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
        }
        spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
 #if 0
-       snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
-       snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
+       snd_printk(KERN_DEBUG
+                  "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
+                  gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+       snd_printk(KERN_DEBUG
+                  "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
+                  "(page = 0x%x)\n",
+                  gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
+                  inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
 #endif
        return 0;
 }
index 426532a4d730cfdcc2fa053db7b7f83d84187581..086b8f0e0f94320fb3763e962918265750eaa1b3 100644 (file)
@@ -148,9 +148,9 @@ static int __devinit snd_gusclassic_probe(struct device *dev, unsigned int n)
        struct snd_gus_card *gus;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card)
-               return -EINVAL;
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0)
+               return error;
 
        if (pcm_channels[n] < 2)
                pcm_channels[n] = 2;
index 7ad4c3b41a848092b2c7d4795d3e70aa1ebb0a4a..180a8dea6bd94cbec45ba6bcae82282cfe7119fb 100644 (file)
@@ -241,9 +241,9 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
        struct snd_opl3 *opl3;
        int error;
 
-       card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
-       if (!card)
-               return -EINVAL;
+       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       if (error < 0)
+               return error;
 
        if (mpu_port[n] == SNDRV_AUTO_PORT)
                mpu_port[n] = 0;
index f94c1976e632c2c55314cd8daee9e0f9aeb0f716..f26eac8d8110093aed72bfc51dce0340ca972ee9 100644 (file)
@@ -214,10 +214,10 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
        struct snd_wss *wss;
        struct snd_gusmax *maxcard;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_gusmax));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_gusmax), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_gusmax_free;
        maxcard = (struct snd_gusmax *)card->private_data;
        maxcard->card = card;
index 5faecfb602d3bec1a66235e5c1e5951f2ec2a215..534a6eced2b810882a4676834926b3703fddf1d4 100644 (file)
@@ -170,7 +170,7 @@ static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int da
        unsigned long port = bus->private_value;
 
 #if 0
-       printk("i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
+       printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
 #endif
        outb((data << 1) | ctrl, port);
        udelay(10);
@@ -183,7 +183,7 @@ static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
 
        res = inb(port) & 1;
 #if 0
-       printk("i2c_getclockline - 0x%lx -> %i\n", port, res);
+       printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
 #endif
        return res;
 }
@@ -197,7 +197,7 @@ static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
                udelay(10);
        res = (inb(port) & 2) >> 1;
 #if 0
-       printk("i2c_getdataline - 0x%lx -> %i\n", port, res);
+       printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
 #endif
        return res;
 }
@@ -342,7 +342,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
                        snd_gf1_poke(gus, local, d);
                        snd_gf1_poke(gus, local + 1, d + 1);
 #if 0
-                       printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n",
+                       printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
+                              "local + 1 = 0x%x, idx << 22 = 0x%x\n",
                               d,
                               snd_gf1_peek(gus, local),
                               snd_gf1_peek(gus, local + 1),
@@ -356,7 +357,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
                }
        }
 #if 0
-       printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);
+       printk(KERN_DEBUG "sizes: %i %i %i %i\n",
+              sizes[0], sizes[1], sizes[2], sizes[3]);
 #endif
 }
 
@@ -410,12 +412,12 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
                lmct = (psizes[3] << 24) | (psizes[2] << 16) |
                    (psizes[1] << 8) | psizes[0];
 #if 0
-               printk("lmct = 0x%08x\n", lmct);
+               printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
 #endif
                for (i = 0; i < ARRAY_SIZE(lmc); i++)
                        if (lmct == lmc[i]) {
 #if 0
-                               printk("found !!! %i\n", i);
+                               printk(KERN_DEBUG "found !!! %i\n", i);
 #endif
                                snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
                                snd_interwave_bank_sizes(gus, psizes);
@@ -626,20 +628,22 @@ static void snd_interwave_free(struct snd_card *card)
                free_irq(iwcard->irq, (void *)iwcard);
 }
 
-static struct snd_card *snd_interwave_card_new(int dev)
+static int snd_interwave_card_new(int dev, struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_interwave *iwcard;
+       int err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_interwave));
-       if (card == NULL)
-               return NULL;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_interwave), &card);
+       if (err < 0)
+               return err;
        iwcard = card->private_data;
        iwcard->card = card;
        iwcard->irq = -1;
        card->private_free = snd_interwave_free;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
@@ -778,9 +782,9 @@ static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr)
        struct snd_card *card;
        int err;
 
-       card = snd_interwave_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_interwave_card_new(dev, &card);
+       if (err < 0)
+               return err;
 
        snd_card_set_dev(card, devptr);
        if ((err = snd_interwave_probe(card, dev)) < 0) {
@@ -876,9 +880,9 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
                                
-       card = snd_interwave_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_interwave_card_new(dev, &card);
+       if (res < 0)
+               return res;
 
        if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) {
                snd_card_free(card);
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
new file mode 100644 (file)
index 0000000..2171c0a
--- /dev/null
@@ -0,0 +1,9 @@
+
+snd-msnd-lib-objs := msnd.o msnd_midi.o msnd_pinnacle_mixer.o
+snd-msnd-pinnacle-objs := msnd_pinnacle.o
+snd-msnd-classic-objs := msnd_classic.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
+obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o snd-msnd-lib.o
+
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
new file mode 100644 (file)
index 0000000..9064544
--- /dev/null
@@ -0,0 +1,705 @@
+/*********************************************************************
+ *
+ * 2002/06/30 Karsten Wiese:
+ *     removed kernel-version dependencies.
+ *     ripped from linux kernel 2.4.18 (OSS Implementation) by me.
+ *     In the OSS Version, this file is compiled to a separate MODULE,
+ *     that is used by the pinnacle and the classic driver.
+ *     since there is no classic driver for alsa yet (i dont have a classic
+ *     & writing one blindfold is difficult) this file's object is statically
+ *     linked into the pinnacle-driver-module for now. look for the string
+ *             "uncomment this to make this a module again"
+ *     to do guess what.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "msnd.h"
+
+#define LOGNAME                        "msnd"
+
+
+void snd_msnd_init_queue(void *base, int start, int size)
+{
+       writew(PCTODSP_BASED(start), base + JQS_wStart);
+       writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+       writew(0, base + JQS_wHead);
+       writew(0, base + JQS_wTail);
+}
+EXPORT_SYMBOL(snd_msnd_init_queue);
+
+static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
+{
+       unsigned int io = dev->io;
+       int timeout = 1000;
+
+       while (timeout-- > 0)
+               if (inb(io + HP_ISR) & HPISR_TXDE)
+                       return 0;
+
+       return -EIO;
+}
+
+static int snd_msnd_wait_HC0(struct snd_msnd *dev)
+{
+       unsigned int io = dev->io;
+       int timeout = 1000;
+
+       while (timeout-- > 0)
+               if (!(inb(io + HP_CVR) & HPCVR_HC))
+                       return 0;
+
+       return -EIO;
+}
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (snd_msnd_wait_HC0(dev) == 0) {
+               outb(cmd, dev->io + HP_CVR);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
+
+       return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
+
+int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
+                  unsigned char mid, unsigned char low)
+{
+       unsigned int io = dev->io;
+
+       if (snd_msnd_wait_TXDE(dev) == 0) {
+               outb(high, io + HP_TXH);
+               outb(mid, io + HP_TXM);
+               outb(low, io + HP_TXL);
+               return 0;
+       }
+
+       snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
+
+       return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_word);
+
+int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
+{
+       int i;
+
+       if (len % 3 != 0) {
+               snd_printk(KERN_ERR LOGNAME
+                          ": Upload host data not multiple of 3!\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < len; i += 3)
+               if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
+                       return -EIO;
+
+       inb(dev->io + HP_RXL);
+       inb(dev->io + HP_CVR);
+
+       return 0;
+}
+EXPORT_SYMBOL(snd_msnd_upload_host);
+
+int snd_msnd_enable_irq(struct snd_msnd *dev)
+{
+       unsigned long flags;
+
+       if (dev->irq_ref++)
+               return 0;
+
+       snd_printdd(LOGNAME ": Enabling IRQ\n");
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (snd_msnd_wait_TXDE(dev) == 0) {
+               outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+               if (dev->type == msndClassic)
+                       outb(dev->irqid, dev->io + HP_IRQM);
+
+               outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+               outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+               enable_irq(dev->irq);
+               snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
+                                   dev->dspq_buff_size);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
+
+       return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_enable_irq);
+
+int snd_msnd_disable_irq(struct snd_msnd *dev)
+{
+       unsigned long flags;
+
+       if (--dev->irq_ref > 0)
+               return 0;
+
+       if (dev->irq_ref < 0)
+               snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
+                          dev->irq_ref);
+
+       snd_printdd(LOGNAME ": Disabling IRQ\n");
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (snd_msnd_wait_TXDE(dev) == 0) {
+               outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+               if (dev->type == msndClassic)
+                       outb(HPIRQ_NONE, dev->io + HP_IRQM);
+               disable_irq(dev->irq);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
+
+       return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_disable_irq);
+
+static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
+{
+       long tmp = (size * HZ * chip->play_sample_size) / 8;
+       return tmp / (chip->play_sample_rate * chip->play_channels);
+}
+
+static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
+{
+       if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
+               return;
+       set_bit(F_WRITEFLUSH, &chip->flags);
+/*     interruptible_sleep_on_timeout(
+               &chip->writeflush,
+               get_play_delay_jiffies(&chip, chip->DAPF.len));*/
+       clear_bit(F_WRITEFLUSH, &chip->flags);
+       if (!signal_pending(current))
+               schedule_timeout_interruptible(
+                       get_play_delay_jiffies(chip, chip->play_period_bytes));
+       clear_bit(F_WRITING, &chip->flags);
+}
+
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
+{
+       if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
+               clear_bit(F_READING, &chip->flags);
+               snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+               snd_msnd_disable_irq(chip);
+               if (file) {
+                       snd_printd(KERN_INFO LOGNAME
+                                  ": Stopping read for %p\n", file);
+                       chip->mode &= ~FMODE_READ;
+               }
+               clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+       }
+       if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
+               if (test_bit(F_WRITING, &chip->flags)) {
+                       snd_msnd_dsp_write_flush(chip);
+                       snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+               }
+               snd_msnd_disable_irq(chip);
+               if (file) {
+                       snd_printd(KERN_INFO
+                                  LOGNAME ": Stopping write for %p\n", file);
+                       chip->mode &= ~FMODE_WRITE;
+               }
+               clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+       }
+}
+EXPORT_SYMBOL(snd_msnd_dsp_halt);
+
+
+int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
+{
+       int /*size, n,*/ timeout = 3;
+       u16 wTmp;
+       /* void *DAQD; */
+
+       /* Increment the tail and check for queue wrap */
+       wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+       if (wTmp > readw(chip->DARQ + JQS_wSize))
+               wTmp = 0;
+       while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
+               udelay(1);
+
+       if (chip->capturePeriods == 2) {
+               void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
+                            bank * DAQDS__size + DAQDS_wStart;
+               unsigned short offset = 0x3000 + chip->capturePeriodBytes;
+
+               if (readw(pDAQ) != PCTODSP_BASED(0x3000))
+                       offset = 0x3000;
+               writew(PCTODSP_BASED(offset), pDAQ);
+       }
+
+       writew(wTmp, chip->DARQ + JQS_wTail);
+
+#if 0
+       /* Get our digital audio queue struct */
+       DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
+
+       /* Get length of data */
+       size = readw(DAQD + DAQDS_wSize);
+
+       /* Read data from the head (unprotected bank 1 access okay
+          since this is only called inside an interrupt) */
+       outb(HPBLKSEL_1, chip->io + HP_BLKS);
+       n = msnd_fifo_write(&chip->DARF,
+                           (char *)(chip->base + bank * DAR_BUFF_SIZE),
+                           size, 0);
+       if (n <= 0) {
+               outb(HPBLKSEL_0, chip->io + HP_BLKS);
+               return n;
+       }
+       outb(HPBLKSEL_0, chip->io + HP_BLKS);
+#endif
+
+       return 1;
+}
+EXPORT_SYMBOL(snd_msnd_DARQ);
+
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
+{
+       u16     DAPQ_tail;
+       int     protect = start, nbanks = 0;
+       void    *DAQD;
+       static int play_banks_submitted;
+       /* unsigned long flags;
+       spin_lock_irqsave(&chip->lock, flags); not necessary */
+
+       DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
+       while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
+               int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
+
+               if (start) {
+                       start = 0;
+                       play_banks_submitted = 0;
+               }
+
+               /* Get our digital audio queue struct */
+               DAQD = bank_num * DAQDS__size + chip->mappedbase +
+                       DAPQ_DATA_BUFF;
+
+               /* Write size of this bank */
+               writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
+               if (play_banks_submitted < 3)
+                       ++play_banks_submitted;
+               else if (chip->playPeriods == 2) {
+                       unsigned short offset = chip->play_period_bytes;
+
+                       if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
+                               offset = 0;
+
+                       writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
+               }
+               ++nbanks;
+
+               /* Then advance the tail */
+               /*
+               if (protect)
+                       snd_printd(KERN_INFO "B %X %lX\n",
+                                  bank_num, xtime.tv_usec);
+               */
+
+               DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+               writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
+               /* Tell the DSP to play the bank */
+               snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
+               if (protect)
+                       if (2 == bank_num)
+                               break;
+       }
+       /*
+       if (protect)
+               snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
+       */
+       /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
+       return nbanks;
+}
+EXPORT_SYMBOL(snd_msnd_DAPQ);
+
+static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
+                                     unsigned int pcm_periods,
+                                     unsigned int pcm_count)
+{
+       int     n;
+       void    *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+       chip->last_playbank = -1;
+       chip->playLimit = pcm_count * (pcm_periods - 1);
+       chip->playPeriods = pcm_periods;
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
+
+       chip->play_period_bytes = pcm_count;
+
+       for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+               writew(PCTODSP_BASED((u32)(pcm_count * n)),
+                       pDAQ + DAQDS_wStart);
+               writew(0, pDAQ + DAQDS_wSize);
+               writew(1, pDAQ + DAQDS_wFormat);
+               writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+               writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+               writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+               writew(n, pDAQ + DAQDS_wFlags);
+       }
+}
+
+static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
+                                        unsigned int pcm_periods,
+                                        unsigned int pcm_count)
+{
+       int             n;
+       void            *pDAQ;
+       /* unsigned long        flags; */
+
+       /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
+
+       chip->last_recbank = 2;
+       chip->captureLimit = pcm_count * (pcm_periods - 1);
+       chip->capturePeriods = pcm_periods;
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
+               chip->DARQ + JQS_wTail);
+
+#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
+       spin_lock_irqsave(&chip->lock, flags);
+       outb(HPBLKSEL_1, chip->io + HP_BLKS);
+       memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
+       outb(HPBLKSEL_0, chip->io + HP_BLKS);
+       spin_unlock_irqrestore(&chip->lock, flags);
+#endif
+
+       chip->capturePeriodBytes = pcm_count;
+       snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+
+       pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+       for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+               u32 tmp = pcm_count * n;
+
+               writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
+               writew(pcm_count, pDAQ + DAQDS_wSize);
+               writew(1, pDAQ + DAQDS_wFormat);
+               writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+               writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+               writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+               writew(n, pDAQ + DAQDS_wFlags);
+       }
+}
+
+static struct snd_pcm_hardware snd_msnd_playback = {
+       .info =                 SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_8000_48000,
+       .rate_min =             8000,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     0x3000,
+       .period_bytes_min =     0x40,
+       .period_bytes_max =     0x1800,
+       .periods_min =          2,
+       .periods_max =          3,
+       .fifo_size =            0,
+};
+
+static struct snd_pcm_hardware snd_msnd_capture = {
+       .info =                 SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_8000_48000,
+       .rate_min =             8000,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     0x3000,
+       .period_bytes_min =     0x40,
+       .period_bytes_max =     0x1800,
+       .periods_min =          2,
+       .periods_max =          3,
+       .fifo_size =            0,
+};
+
+
+static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+       clear_bit(F_WRITING, &chip->flags);
+       snd_msnd_enable_irq(chip);
+
+       runtime->dma_area = chip->mappedbase;
+       runtime->dma_bytes = 0x3000;
+
+       chip->playback_substream = substream;
+       runtime->hw = snd_msnd_playback;
+       return 0;
+}
+
+static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       snd_msnd_disable_irq(chip);
+       clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+       return 0;
+}
+
+
+static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       int     i;
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+       void    *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+       chip->play_sample_size = snd_pcm_format_width(params_format(params));
+       chip->play_channels = params_channels(params);
+       chip->play_sample_rate = params_rate(params);
+
+       for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+               writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+               writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+               writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+       }
+       /* dont do this here:
+        * snd_msnd_calibrate_adc(chip->play_sample_rate);
+        */
+
+       return 0;
+}
+
+static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+       unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+       unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+       unsigned int pcm_periods = pcm_size / pcm_count;
+
+       snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
+       chip->playDMAPos = 0;
+       return 0;
+}
+
+static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
+                                    int cmd)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+       int     result = 0;
+
+       if (cmd == SNDRV_PCM_TRIGGER_START) {
+               snd_printdd("snd_msnd_playback_trigger(START)\n");
+               chip->banksPlayed = 0;
+               set_bit(F_WRITING, &chip->flags);
+               snd_msnd_DAPQ(chip, 1);
+       } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+               snd_printdd("snd_msnd_playback_trigger(STop)\n");
+               /* interrupt diagnostic, comment this out later */
+               clear_bit(F_WRITING, &chip->flags);
+               snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+       } else {
+               snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
+               result = -EINVAL;
+       }
+
+       snd_printdd("snd_msnd_playback_trigger() ENDE\n");
+       return result;
+}
+
+static snd_pcm_uframes_t
+snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       return bytes_to_frames(substream->runtime, chip->playDMAPos);
+}
+
+
+static struct snd_pcm_ops snd_msnd_playback_ops = {
+       .open =         snd_msnd_playback_open,
+       .close =        snd_msnd_playback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_msnd_playback_hw_params,
+       .prepare =      snd_msnd_playback_prepare,
+       .trigger =      snd_msnd_playback_trigger,
+       .pointer =      snd_msnd_playback_pointer,
+};
+
+static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       set_bit(F_AUDIO_READ_INUSE, &chip->flags);
+       snd_msnd_enable_irq(chip);
+       runtime->dma_area = chip->mappedbase + 0x3000;
+       runtime->dma_bytes = 0x3000;
+       memset(runtime->dma_area, 0, runtime->dma_bytes);
+       chip->capture_substream = substream;
+       runtime->hw = snd_msnd_capture;
+       return 0;
+}
+
+static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       snd_msnd_disable_irq(chip);
+       clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+       return 0;
+}
+
+static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+       unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+       unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+       unsigned int pcm_periods = pcm_size / pcm_count;
+
+       snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
+       chip->captureDMAPos = 0;
+       return 0;
+}
+
+static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
+                                   int cmd)
+{
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       if (cmd == SNDRV_PCM_TRIGGER_START) {
+               chip->last_recbank = -1;
+               set_bit(F_READING, &chip->flags);
+               if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
+                       return 0;
+
+               clear_bit(F_READING, &chip->flags);
+       } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+               clear_bit(F_READING, &chip->flags);
+               snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+
+static snd_pcm_uframes_t
+snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+       return bytes_to_frames(runtime, chip->captureDMAPos);
+}
+
+
+static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       int             i;
+       struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+       void            *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+       chip->capture_sample_size = snd_pcm_format_width(params_format(params));
+       chip->capture_channels = params_channels(params);
+       chip->capture_sample_rate = params_rate(params);
+
+       for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+               writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+               writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+               writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+       }
+       return 0;
+}
+
+
+static struct snd_pcm_ops snd_msnd_capture_ops = {
+       .open =         snd_msnd_capture_open,
+       .close =        snd_msnd_capture_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_msnd_capture_hw_params,
+       .prepare =      snd_msnd_capture_prepare,
+       .trigger =      snd_msnd_capture_trigger,
+       .pointer =      snd_msnd_capture_pointer,
+};
+
+
+int snd_msnd_pcm(struct snd_card *card, int device,
+                       struct snd_pcm **rpcm)
+{
+       struct snd_msnd *chip = card->private_data;
+       struct snd_pcm  *pcm;
+       int err;
+
+       err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
+
+       pcm->private_data = chip;
+       strcpy(pcm->name, "Hurricane");
+
+
+       if (rpcm)
+               *rpcm = pcm;
+       return 0;
+}
+EXPORT_SYMBOL(snd_msnd_pcm);
+
+MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
new file mode 100644 (file)
index 0000000..3773e24
--- /dev/null
@@ -0,0 +1,308 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define DEFSAMPLERATE          44100
+#define DEFSAMPLESIZE          SNDRV_PCM_FORMAT_S16
+#define DEFCHANNELS            1
+
+#define SRAM_BANK_SIZE         0x8000
+#define SRAM_CNTL_START                0x7F00
+#define SMA_STRUCT_START       0x7F40
+
+#define DSP_BASE_ADDR          0x4000
+#define DSP_BANK_BASE          0x4000
+
+#define AGND                   0x01
+#define SIGNAL                 0x02
+
+#define EXT_DSP_BIT_DCAL       0x0001
+#define EXT_DSP_BIT_MIDI_CON   0x0002
+
+#define BUFFSIZE               0x8000
+#define HOSTQ_SIZE             0x40
+
+#define DAP_BUFF_SIZE          0x2400
+
+#define DAPQ_STRUCT_SIZE       0x10
+#define DARQ_STRUCT_SIZE       0x10
+#define DAPQ_BUFF_SIZE         (3 * 0x10)
+#define DARQ_BUFF_SIZE         (3 * 0x10)
+#define MODQ_BUFF_SIZE         0x400
+
+#define DAPQ_DATA_BUFF         0x6C00
+#define DARQ_DATA_BUFF         0x6C30
+#define MODQ_DATA_BUFF         0x6C60
+#define MIDQ_DATA_BUFF         0x7060
+
+#define DAPQ_OFFSET            SRAM_CNTL_START
+#define DARQ_OFFSET            (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET            (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET            (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET            (SRAM_CNTL_START + 0x20)
+
+#define        HP_ICR                  0x00
+#define        HP_CVR                  0x01
+#define        HP_ISR                  0x02
+#define        HP_IVR                  0x03
+#define HP_NU                  0x04
+#define HP_INFO                        0x04
+#define        HP_TXH                  0x05
+#define        HP_RXH                  0x05
+#define        HP_TXM                  0x06
+#define        HP_RXM                  0x06
+#define        HP_TXL                  0x07
+#define        HP_RXL                  0x07
+
+#define HP_ICR_DEF             0x00
+#define HP_CVR_DEF             0x12
+#define HP_ISR_DEF             0x06
+#define HP_IVR_DEF             0x0f
+#define HP_NU_DEF              0x00
+
+#define        HP_IRQM                 0x09
+
+#define        HPR_BLRC                0x08
+#define        HPR_SPR1                0x09
+#define        HPR_SPR2                0x0A
+#define        HPR_TCL0                0x0B
+#define        HPR_TCL1                0x0C
+#define        HPR_TCL2                0x0D
+#define        HPR_TCL3                0x0E
+#define        HPR_TCL4                0x0F
+
+#define        HPICR_INIT              0x80
+#define HPICR_HM1              0x40
+#define HPICR_HM0              0x20
+#define HPICR_HF1              0x10
+#define HPICR_HF0              0x08
+#define        HPICR_TREQ              0x02
+#define        HPICR_RREQ              0x01
+
+#define HPCVR_HC               0x80
+
+#define        HPISR_HREQ              0x80
+#define HPISR_DMA              0x40
+#define HPISR_HF3              0x10
+#define HPISR_HF2              0x08
+#define        HPISR_TRDY              0x04
+#define        HPISR_TXDE              0x02
+#define        HPISR_RXDF              0x01
+
+#define        HPIO_290                0
+#define        HPIO_260                1
+#define        HPIO_250                2
+#define        HPIO_240                3
+#define        HPIO_230                4
+#define        HPIO_220                5
+#define        HPIO_210                6
+#define        HPIO_3E0                7
+
+#define        HPMEM_NONE              0
+#define        HPMEM_B000              1
+#define        HPMEM_C800              2
+#define        HPMEM_D000              3
+#define        HPMEM_D400              4
+#define        HPMEM_D800              5
+#define        HPMEM_E000              6
+#define        HPMEM_E800              7
+
+#define        HPIRQ_NONE              0
+#define HPIRQ_5                        1
+#define HPIRQ_7                        2
+#define HPIRQ_9                        3
+#define HPIRQ_10               4
+#define HPIRQ_11               5
+#define HPIRQ_12               6
+#define HPIRQ_15               7
+
+#define        HIMT_PLAY_DONE          0x00
+#define        HIMT_RECORD_DONE        0x01
+#define        HIMT_MIDI_EOS           0x02
+#define        HIMT_MIDI_OUT           0x03
+
+#define        HIMT_MIDI_IN_UCHAR      0x0E
+#define        HIMT_DSP                0x0F
+
+#define        HDEX_BASE               0x92
+#define        HDEX_PLAY_START         (0 + HDEX_BASE)
+#define        HDEX_PLAY_STOP          (1 + HDEX_BASE)
+#define        HDEX_PLAY_PAUSE         (2 + HDEX_BASE)
+#define        HDEX_PLAY_RESUME        (3 + HDEX_BASE)
+#define        HDEX_RECORD_START       (4 + HDEX_BASE)
+#define        HDEX_RECORD_STOP        (5 + HDEX_BASE)
+#define        HDEX_MIDI_IN_START      (6 + HDEX_BASE)
+#define        HDEX_MIDI_IN_STOP       (7 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_START     (8 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_STOP      (9 + HDEX_BASE)
+#define        HDEX_AUX_REQ            (10 + HDEX_BASE)
+
+#define        HDEXAR_CLEAR_PEAKS      1
+#define        HDEXAR_IN_SET_POTS      2
+#define        HDEXAR_AUX_SET_POTS     3
+#define        HDEXAR_CAL_A_TO_D       4
+#define        HDEXAR_RD_EXT_DSP_BITS  5
+
+/* Pinnacle only HDEXAR defs */
+#define        HDEXAR_SET_ANA_IN       0
+#define        HDEXAR_SET_SYNTH_IN     4
+#define        HDEXAR_READ_DAT_IN      5
+#define        HDEXAR_MIC_SET_POTS     6
+#define        HDEXAR_SET_DAT_IN       7
+
+#define HDEXAR_SET_SYNTH_48    8
+#define HDEXAR_SET_SYNTH_44    9
+
+#define HIWORD(l)              ((u16)((((u32)(l)) >> 16) & 0xFFFF))
+#define LOWORD(l)              ((u16)(u32)(l))
+#define HIBYTE(w)              ((u8)(((u16)(w) >> 8) & 0xFF))
+#define LOBYTE(w)              ((u8)(w))
+#define MAKELONG(low, hi)      ((long)(((u16)(low))|(((u32)((u16)(hi)))<<16)))
+#define MAKEWORD(low, hi)      ((u16)(((u8)(low))|(((u16)((u8)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w)      (u16)((w)/2)
+#define PCTODSP_BASED(w)       (u16)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w)       (((w) - DSP_BASE_ADDR) * 2)
+
+#ifdef SLOWIO
+#  undef outb
+#  undef inb
+#  define outb                 outb_p
+#  define inb                  inb_p
+#endif
+
+/* JobQueueStruct */
+#define JQS_wStart             0x00
+#define JQS_wSize              0x02
+#define JQS_wHead              0x04
+#define JQS_wTail              0x06
+#define JQS__size              0x08
+
+/* DAQueueDataStruct */
+#define DAQDS_wStart           0x00
+#define DAQDS_wSize            0x02
+#define DAQDS_wFormat          0x04
+#define DAQDS_wSampleSize      0x06
+#define DAQDS_wChannels                0x08
+#define DAQDS_wSampleRate      0x0A
+#define DAQDS_wIntMsg          0x0C
+#define DAQDS_wFlags           0x0E
+#define DAQDS__size            0x10
+
+#include <sound/pcm.h>
+
+struct snd_msnd {
+       void __iomem            *mappedbase;
+       int                     play_period_bytes;
+       int                     playLimit;
+       int                     playPeriods;
+       int                     playDMAPos;
+       int                     banksPlayed;
+       int                     captureDMAPos;
+       int                     capturePeriodBytes;
+       int                     captureLimit;
+       int                     capturePeriods;
+       struct snd_card         *card;
+       void                    *msndmidi_mpu;
+       struct snd_rawmidi      *rmidi;
+
+       /* Hardware resources */
+       long io;
+       int memid, irqid;
+       int irq, irq_ref;
+       unsigned long base;
+
+       /* Motorola 56k DSP SMA */
+       void __iomem    *SMA;
+       void __iomem    *DAPQ;
+       void __iomem    *DARQ;
+       void __iomem    *MODQ;
+       void __iomem    *MIDQ;
+       void __iomem    *DSPQ;
+       int dspq_data_buff, dspq_buff_size;
+
+       /* State variables */
+       enum { msndClassic, msndPinnacle } type;
+       mode_t mode;
+       unsigned long flags;
+#define F_RESETTING                    0
+#define F_HAVEDIGITAL                  1
+#define F_AUDIO_WRITE_INUSE            2
+#define F_WRITING                      3
+#define F_WRITEBLOCK                   4
+#define F_WRITEFLUSH                   5
+#define F_AUDIO_READ_INUSE             6
+#define F_READING                      7
+#define F_READBLOCK                    8
+#define F_EXT_MIDI_INUSE               9
+#define F_HDR_MIDI_INUSE               10
+#define F_DISABLE_WRITE_NDELAY         11
+       spinlock_t lock;
+       spinlock_t mixer_lock;
+       int nresets;
+       unsigned recsrc;
+#define LEVEL_ENTRIES 32
+       int left_levels[LEVEL_ENTRIES];
+       int right_levels[LEVEL_ENTRIES];
+       int calibrate_signal;
+       int play_sample_size, play_sample_rate, play_channels;
+       int play_ndelay;
+       int capture_sample_size, capture_sample_rate, capture_channels;
+       int capture_ndelay;
+       u8 bCurrentMidiPatch;
+
+       int last_playbank, last_recbank;
+       struct snd_pcm_substream *playback_substream;
+       struct snd_pcm_substream *capture_substream;
+
+};
+
+void snd_msnd_init_queue(void *base, int start, int size);
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
+int snd_msnd_send_word(struct snd_msnd *chip,
+                          unsigned char high,
+                          unsigned char mid,
+                          unsigned char low);
+int snd_msnd_upload_host(struct snd_msnd *chip,
+                            const u8 *bin, int len);
+int snd_msnd_enable_irq(struct snd_msnd *chip);
+int snd_msnd_disable_irq(struct snd_msnd *chip);
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
+int snd_msnd_DARQ(struct snd_msnd *chip, int start);
+int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+
+int snd_msndmidi_new(struct snd_card *card, int device);
+void snd_msndmidi_input_read(void *mpu);
+
+void snd_msndmix_setup(struct snd_msnd *chip);
+int __devinit snd_msndmix_new(struct snd_card *card);
+int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
+#endif /* __MSND_H */
diff --git a/sound/isa/msnd/msnd_classic.c b/sound/isa/msnd/msnd_classic.c
new file mode 100644 (file)
index 0000000..3b23a09
--- /dev/null
@@ -0,0 +1,3 @@
+/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
+#define MSND_CLASSIC
+#include "msnd_pinnacle.c"
diff --git a/sound/isa/msnd/msnd_classic.h b/sound/isa/msnd/msnd_classic.h
new file mode 100644 (file)
index 0000000..f18d5fa
--- /dev/null
@@ -0,0 +1,129 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO                              0x10
+
+#define        HP_MEMM                                 0x08
+
+#define        HP_BITM                                 0x0E
+#define        HP_WAIT                                 0x0D
+#define        HP_DSPR                                 0x0A
+#define        HP_PROR                                 0x0B
+#define        HP_BLKS                                 0x0C
+
+#define        HPPRORESET_OFF                          0
+#define HPPRORESET_ON                          1
+
+#define HPDSPRESET_OFF                         0
+#define HPDSPRESET_ON                          1
+
+#define HPBLKSEL_0                             0
+#define HPBLKSEL_1                             1
+
+#define HPWAITSTATE_0                          0
+#define HPWAITSTATE_1                          1
+
+#define HPBITMODE_16                           0
+#define HPBITMODE_8                            1
+
+#define        HIDSP_INT_PLAY_UNDER                    0x00
+#define        HIDSP_INT_RECORD_OVER                   0x01
+#define        HIDSP_INPUT_CLIPPING                    0x02
+#define        HIDSP_MIDI_IN_OVER                      0x10
+#define        HIDSP_MIDI_OVERRUN_ERR  0x13
+
+#define TIME_PRO_RESET_DONE                    0x028A
+#define TIME_PRO_SYSEX                         0x0040
+#define TIME_PRO_RESET                         0x0032
+
+#define DAR_BUFF_SIZE                          0x2000
+
+#define MIDQ_BUFF_SIZE                         0x200
+#define DSPQ_BUFF_SIZE                         0x40
+
+#define DSPQ_DATA_BUFF                         0x7260
+
+#define MOP_SYNTH                              0x10
+#define MOP_EXTOUT                             0x32
+#define MOP_EXTTHRU                            0x02
+#define MOP_OUTMASK                            0x01
+
+#define MIP_EXTIN                              0x01
+#define MIP_SYNTH                              0x00
+#define MIP_INMASK                             0x32
+
+/* Classic SMA Common Data */
+#define SMA_wCurrPlayBytes                     0x0000
+#define SMA_wCurrRecordBytes                   0x0002
+#define SMA_wCurrPlayVolLeft                   0x0004
+#define SMA_wCurrPlayVolRight                  0x0006
+#define SMA_wCurrInVolLeft                     0x0008
+#define SMA_wCurrInVolRight                    0x000a
+#define SMA_wUser_3                            0x000c
+#define SMA_wUser_4                            0x000e
+#define SMA_dwUser_5                           0x0010
+#define SMA_dwUser_6                           0x0014
+#define SMA_wUser_7                            0x0018
+#define SMA_wReserved_A                                0x001a
+#define SMA_wReserved_B                                0x001c
+#define SMA_wReserved_C                                0x001e
+#define SMA_wReserved_D                                0x0020
+#define SMA_wReserved_E                                0x0022
+#define SMA_wReserved_F                                0x0024
+#define SMA_wReserved_G                                0x0026
+#define SMA_wReserved_H                                0x0028
+#define SMA_wCurrDSPStatusFlags                        0x002a
+#define SMA_wCurrHostStatusFlags               0x002c
+#define SMA_wCurrInputTagBits                  0x002e
+#define SMA_wCurrLeftPeak                      0x0030
+#define SMA_wCurrRightPeak                     0x0032
+#define SMA_wExtDSPbits                                0x0034
+#define SMA_bExtHostbits                       0x0036
+#define SMA_bBoardLevel                                0x0037
+#define SMA_bInPotPosRight                     0x0038
+#define SMA_bInPotPosLeft                      0x0039
+#define SMA_bAuxPotPosRight                    0x003a
+#define SMA_bAuxPotPosLeft                     0x003b
+#define SMA_wCurrMastVolLeft                   0x003c
+#define SMA_wCurrMastVolRight                  0x003e
+#define SMA_bUser_12                           0x0040
+#define SMA_bUser_13                           0x0041
+#define SMA_wUser_14                           0x0042
+#define SMA_wUser_15                           0x0044
+#define SMA_wCalFreqAtoD                       0x0046
+#define SMA_wUser_16                           0x0048
+#define SMA_wUser_17                           0x004a
+#define SMA__size                              0x004c
+
+#define INITCODEFILE           "turtlebeach/msndinit.bin"
+#define PERMCODEFILE           "turtlebeach/msndperm.bin"
+#define LONGNAME               "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
new file mode 100644 (file)
index 0000000..cb9aa4c
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2009 by Krzysztof Helt
+ *  Routines for control of MPU-401 in UART mode
+ *
+ *  MPU-401 supports UART mode which is not capable generate transmit
+ *  interrupts thus output is done via polling. Also, if irq < 0, then
+ *  input is done also via polling. Do not expect good performance.
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "msnd.h"
+
+#define MSNDMIDI_MODE_BIT_INPUT                0
+#define MSNDMIDI_MODE_BIT_OUTPUT               1
+#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER        2
+#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER       3
+
+struct snd_msndmidi {
+       struct snd_msnd *dev;
+
+       unsigned long mode;             /* MSNDMIDI_MODE_XXXX */
+
+       struct snd_rawmidi_substream *substream_input;
+
+       spinlock_t input_lock;
+};
+
+/*
+ * input/output open/close - protected by open_mutex in rawmidi.c
+ */
+static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
+{
+       struct snd_msndmidi *mpu;
+
+       snd_printdd("snd_msndmidi_input_open()\n");
+
+       mpu = substream->rmidi->private_data;
+
+       mpu->substream_input = substream;
+
+       snd_msnd_enable_irq(mpu->dev);
+
+       snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
+       set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+       return 0;
+}
+
+static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
+{
+       struct snd_msndmidi *mpu;
+
+       mpu = substream->rmidi->private_data;
+       snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
+       clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+       mpu->substream_input = NULL;
+       snd_msnd_disable_irq(mpu->dev);
+       return 0;
+}
+
+static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
+{
+       u16 tail;
+
+       tail = readw(mpu->dev->MIDQ + JQS_wTail);
+       writew(tail, mpu->dev->MIDQ + JQS_wHead);
+}
+
+/*
+ * trigger input
+ */
+static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
+                                       int up)
+{
+       unsigned long flags;
+       struct snd_msndmidi *mpu;
+
+       snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
+
+       mpu = substream->rmidi->private_data;
+       spin_lock_irqsave(&mpu->input_lock, flags);
+       if (up) {
+               if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+                                     &mpu->mode))
+                       snd_msndmidi_input_drop(mpu);
+       } else {
+               clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
+       }
+       spin_unlock_irqrestore(&mpu->input_lock, flags);
+       if (up)
+               snd_msndmidi_input_read(mpu);
+}
+
+void snd_msndmidi_input_read(void *mpuv)
+{
+       unsigned long flags;
+       struct snd_msndmidi *mpu = mpuv;
+       void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+
+       spin_lock_irqsave(&mpu->input_lock, flags);
+       while (readw(mpu->dev->MIDQ + JQS_wTail) !=
+              readw(mpu->dev->MIDQ + JQS_wHead)) {
+               u16 wTmp, val;
+               val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
+
+                       if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+                                    &mpu->mode))
+                               snd_rawmidi_receive(mpu->substream_input,
+                                                   (unsigned char *)&val, 1);
+
+               wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
+               if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
+                       writew(0,  mpu->dev->MIDQ + JQS_wHead);
+               else
+                       writew(wTmp,  mpu->dev->MIDQ + JQS_wHead);
+       }
+       spin_unlock_irqrestore(&mpu->input_lock, flags);
+}
+EXPORT_SYMBOL(snd_msndmidi_input_read);
+
+static struct snd_rawmidi_ops snd_msndmidi_input = {
+       .open =         snd_msndmidi_input_open,
+       .close =        snd_msndmidi_input_close,
+       .trigger =      snd_msndmidi_input_trigger,
+};
+
+static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
+{
+       struct snd_msndmidi *mpu = rmidi->private_data;
+       kfree(mpu);
+}
+
+int snd_msndmidi_new(struct snd_card *card, int device)
+{
+       struct snd_msnd *chip = card->private_data;
+       struct snd_msndmidi *mpu;
+       struct snd_rawmidi *rmidi;
+       int err;
+
+       err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
+       if (err < 0)
+               return err;
+       mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL);
+       if (mpu == NULL) {
+               snd_device_free(card, rmidi);
+               return -ENOMEM;
+       }
+       mpu->dev = chip;
+       chip->msndmidi_mpu = mpu;
+       rmidi->private_data = mpu;
+       rmidi->private_free = snd_msndmidi_free;
+       spin_lock_init(&mpu->input_lock);
+       strcpy(rmidi->name, "MSND MIDI");
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                           &snd_msndmidi_input);
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+       return 0;
+}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
new file mode 100644 (file)
index 0000000..60b6abd
--- /dev/null
@@ -0,0 +1,1238 @@
+/*********************************************************************
+ *
+ * Linux multisound pinnacle/fiji driver for ALSA.
+ *
+ * 2002/06/30 Karsten Wiese:
+ *     for now this is only used to build a pinnacle / fiji driver.
+ *     the OSS parent of this code is designed to also support
+ *     the multisound classic via the file msnd_classic.c.
+ *     to make it easier for some brave heart to implemt classic
+ *     support in alsa, i left all the MSND_CLASSIC tokens in this file.
+ *     but for now this untested & undone.
+ *
+ *
+ * ripped from linux kernel 2.4.18 by Karsten Wiese.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ * msnd_pinnacle.c / msnd_classic.c
+ *
+ * -- If MSND_CLASSIC is defined:
+ *
+ *     -> driver for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * -- Else
+ *
+ *     -> driver for Turtle Beach Pinnacle/Fiji
+ *
+ * 12-3-2000  Modified IO port validation  Steve Sycamore
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/interrupt.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/isa.h>
+#include <linux/isapnp.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/mpu401.h>
+
+#ifdef MSND_CLASSIC
+# ifndef __alpha__
+#  define SLOWIO
+# endif
+#endif
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+#  include "msnd_classic.h"
+#  define LOGNAME                      "msnd_classic"
+#else
+#  include "msnd_pinnacle.h"
+#  define LOGNAME                      "snd_msnd_pinnacle"
+#endif
+
+static void __devinit set_default_audio_parameters(struct snd_msnd *chip)
+{
+       chip->play_sample_size = DEFSAMPLESIZE;
+       chip->play_sample_rate = DEFSAMPLERATE;
+       chip->play_channels = DEFCHANNELS;
+       chip->capture_sample_size = DEFSAMPLESIZE;
+       chip->capture_sample_rate = DEFSAMPLERATE;
+       chip->capture_channels = DEFCHANNELS;
+}
+
+static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
+{
+       switch (HIBYTE(wMessage)) {
+       case HIMT_PLAY_DONE: {
+               if (chip->banksPlayed < 3)
+                       snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
+                               (unsigned)jiffies, LOBYTE(wMessage));
+
+               if (chip->last_playbank == LOBYTE(wMessage)) {
+                       snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
+                       break;
+               }
+               chip->banksPlayed++;
+
+               if (test_bit(F_WRITING, &chip->flags))
+                       snd_msnd_DAPQ(chip, 0);
+
+               chip->last_playbank = LOBYTE(wMessage);
+               chip->playDMAPos += chip->play_period_bytes;
+               if (chip->playDMAPos > chip->playLimit)
+                       chip->playDMAPos = 0;
+               snd_pcm_period_elapsed(chip->playback_substream);
+
+               break;
+       }
+       case HIMT_RECORD_DONE:
+               if (chip->last_recbank == LOBYTE(wMessage))
+                       break;
+               chip->last_recbank = LOBYTE(wMessage);
+               chip->captureDMAPos += chip->capturePeriodBytes;
+               if (chip->captureDMAPos > (chip->captureLimit))
+                       chip->captureDMAPos = 0;
+
+               if (test_bit(F_READING, &chip->flags))
+                       snd_msnd_DARQ(chip, chip->last_recbank);
+
+               snd_pcm_period_elapsed(chip->capture_substream);
+               break;
+
+       case HIMT_DSP:
+               switch (LOBYTE(wMessage)) {
+#ifndef MSND_CLASSIC
+               case HIDSP_PLAY_UNDER:
+#endif
+               case HIDSP_INT_PLAY_UNDER:
+                       snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
+                               chip->banksPlayed);
+                       if (chip->banksPlayed > 2)
+                               clear_bit(F_WRITING, &chip->flags);
+                       break;
+
+               case HIDSP_INT_RECORD_OVER:
+                       snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
+                       clear_bit(F_READING, &chip->flags);
+                       break;
+
+               default:
+                       snd_printd(KERN_WARNING LOGNAME
+                                  ": DSP message %d 0x%02x\n",
+                                  LOBYTE(wMessage), LOBYTE(wMessage));
+                       break;
+               }
+               break;
+
+       case HIMT_MIDI_IN_UCHAR:
+               if (chip->msndmidi_mpu)
+                       snd_msndmidi_input_read(chip->msndmidi_mpu);
+               break;
+
+       default:
+               snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
+                          HIBYTE(wMessage), HIBYTE(wMessage));
+               break;
+       }
+}
+
+static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
+{
+       struct snd_msnd *chip = dev_id;
+       void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+
+       /* Send ack to DSP */
+       /* inb(chip->io + HP_RXL); */
+
+       /* Evaluate queued DSP messages */
+       while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
+               u16 wTmp;
+
+               snd_msnd_eval_dsp_msg(chip,
+                       readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
+
+               wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
+               if (wTmp > readw(chip->DSPQ + JQS_wSize))
+                       writew(0, chip->DSPQ + JQS_wHead);
+               else
+                       writew(wTmp, chip->DSPQ + JQS_wHead);
+       }
+       /* Send ack to DSP */
+       inb(chip->io + HP_RXL);
+       return IRQ_HANDLED;
+}
+
+
+static int snd_msnd_reset_dsp(long io, unsigned char *info)
+{
+       int timeout = 100;
+
+       outb(HPDSPRESET_ON, io + HP_DSPR);
+       msleep(1);
+#ifndef MSND_CLASSIC
+       if (info)
+               *info = inb(io + HP_INFO);
+#endif
+       outb(HPDSPRESET_OFF, io + HP_DSPR);
+       msleep(1);
+       while (timeout-- > 0) {
+               if (inb(io + HP_CVR) == HP_CVR_DEF)
+                       return 0;
+               msleep(1);
+       }
+       snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+       return -EIO;
+}
+
+static int __devinit snd_msnd_probe(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       unsigned char info;
+#ifndef MSND_CLASSIC
+       char *xv, *rev = NULL;
+       char *pin = "TB Pinnacle", *fiji = "TB Fiji";
+       char *pinfiji = "TB Pinnacle/Fiji";
+#endif
+
+       if (!request_region(chip->io, DSP_NUMIO, "probing")) {
+               snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+               return -ENODEV;
+       }
+
+       if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
+               release_region(chip->io, DSP_NUMIO);
+               return -ENODEV;
+       }
+
+#ifdef MSND_CLASSIC
+       strcpy(card->shortname, "Classic/Tahiti/Monterey");
+       strcpy(card->longname, "Turtle Beach Multisound");
+       printk(KERN_INFO LOGNAME ": %s, "
+              "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+              card->shortname,
+              chip->io, chip->io + DSP_NUMIO - 1,
+              chip->irq,
+              chip->base, chip->base + 0x7fff);
+#else
+       switch (info >> 4) {
+       case 0xf:
+               xv = "<= 1.15";
+               break;
+       case 0x1:
+               xv = "1.18/1.2";
+               break;
+       case 0x2:
+               xv = "1.3";
+               break;
+       case 0x3:
+               xv = "1.4";
+               break;
+       default:
+               xv = "unknown";
+               break;
+       }
+
+       switch (info & 0x7) {
+       case 0x0:
+               rev = "I";
+               strcpy(card->shortname, pin);
+               break;
+       case 0x1:
+               rev = "F";
+               strcpy(card->shortname, pin);
+               break;
+       case 0x2:
+               rev = "G";
+               strcpy(card->shortname, pin);
+               break;
+       case 0x3:
+               rev = "H";
+               strcpy(card->shortname, pin);
+               break;
+       case 0x4:
+               rev = "E";
+               strcpy(card->shortname, fiji);
+               break;
+       case 0x5:
+               rev = "C";
+               strcpy(card->shortname, fiji);
+               break;
+       case 0x6:
+               rev = "D";
+               strcpy(card->shortname, fiji);
+               break;
+       case 0x7:
+               rev = "A-B (Fiji) or A-E (Pinnacle)";
+               strcpy(card->shortname, pinfiji);
+               break;
+       }
+       strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
+       printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
+              "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+              card->shortname,
+              rev, xv,
+              chip->io, chip->io + DSP_NUMIO - 1,
+              chip->irq,
+              chip->base, chip->base + 0x7fff);
+#endif
+
+       release_region(chip->io, DSP_NUMIO);
+       return 0;
+}
+
+static int snd_msnd_init_sma(struct snd_msnd *chip)
+{
+       static int initted;
+       u16 mastVolLeft, mastVolRight;
+       unsigned long flags;
+
+#ifdef MSND_CLASSIC
+       outb(chip->memid, chip->io + HP_MEMM);
+#endif
+       outb(HPBLKSEL_0, chip->io + HP_BLKS);
+       /* Motorola 56k shared memory base */
+       chip->SMA = chip->mappedbase + SMA_STRUCT_START;
+
+       if (initted) {
+               mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
+               mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
+       } else
+               mastVolLeft = mastVolRight = 0;
+       memset_io(chip->mappedbase, 0, 0x8000);
+
+       /* Critical section: bank 1 access */
+       spin_lock_irqsave(&chip->lock, flags);
+       outb(HPBLKSEL_1, chip->io + HP_BLKS);
+       memset_io(chip->mappedbase, 0, 0x8000);
+       outb(HPBLKSEL_0, chip->io + HP_BLKS);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       /* Digital audio play queue */
+       chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
+       snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
+
+       /* Digital audio record queue */
+       chip->DARQ = chip->mappedbase + DARQ_OFFSET;
+       snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+       /* MIDI out queue */
+       chip->MODQ = chip->mappedbase + MODQ_OFFSET;
+       snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
+
+       /* MIDI in queue */
+       chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
+       snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
+
+       /* DSP -> host message queue */
+       chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
+       snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+
+       /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+       writew(1, chip->SMA + SMA_wCurrPlayFormat);
+       writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
+       writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
+       writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
+#endif
+       writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
+       writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
+       writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
+#ifndef MSND_CLASSIC
+       writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
+       writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
+#endif
+       writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
+
+       initted = 1;
+
+       return 0;
+}
+
+
+static int upload_dsp_code(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       const struct firmware *init_fw = NULL, *perm_fw = NULL;
+       int err;
+
+       outb(HPBLKSEL_0, chip->io + HP_BLKS);
+
+       err = request_firmware(&init_fw, INITCODEFILE, card->dev);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+               goto cleanup1;
+       }
+       err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+               goto cleanup;
+       }
+
+       memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
+       if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
+               printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+               err = -ENODEV;
+               goto cleanup;
+       }
+       printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+       err = 0;
+
+cleanup:
+       release_firmware(perm_fw);
+cleanup1:
+       release_firmware(init_fw);
+       return err;
+}
+
+#ifdef MSND_CLASSIC
+static void reset_proteus(struct snd_msnd *chip)
+{
+       outb(HPPRORESET_ON, chip->io + HP_PROR);
+       msleep(TIME_PRO_RESET);
+       outb(HPPRORESET_OFF, chip->io + HP_PROR);
+       msleep(TIME_PRO_RESET_DONE);
+}
+#endif
+
+static int snd_msnd_initialize(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       int err, timeout;
+
+#ifdef MSND_CLASSIC
+       outb(HPWAITSTATE_0, chip->io + HP_WAIT);
+       outb(HPBITMODE_16, chip->io + HP_BITM);
+
+       reset_proteus(chip);
+#endif
+       err = snd_msnd_init_sma(chip);
+       if (err < 0) {
+               printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+               return err;
+       }
+
+       err = snd_msnd_reset_dsp(chip->io, NULL);
+       if (err < 0)
+               return err;
+
+       err = upload_dsp_code(card);
+       if (err < 0) {
+               printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+               return err;
+       }
+
+       timeout = 200;
+
+       while (readw(chip->mappedbase)) {
+               msleep(1);
+               if (!timeout--) {
+                       snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
+                       return -EIO;
+               }
+       }
+
+       snd_msndmix_setup(chip);
+       return 0;
+}
+
+static int snd_msnd_dsp_full_reset(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       int rv;
+
+       if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
+               return 0;
+
+       set_bit(F_RESETTING, &chip->flags);
+       snd_msnd_dsp_halt(chip, NULL);  /* Unconditionally halt */
+
+       rv = snd_msnd_initialize(card);
+       if (rv)
+               printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+       snd_msndmix_force_recsrc(chip, 0);
+       clear_bit(F_RESETTING, &chip->flags);
+       return rv;
+}
+
+static int snd_msnd_dev_free(struct snd_device *device)
+{
+       snd_printdd("snd_msnd_chip_free()\n");
+       return 0;
+}
+
+static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
+{
+       if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
+               return 0;
+       snd_msnd_dsp_full_reset(chip->card);
+       return snd_msnd_send_dsp_cmd(chip, cmd);
+}
+
+static int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
+{
+       snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
+       writew(srate, chip->SMA + SMA_wCalFreqAtoD);
+       if (chip->calibrate_signal == 0)
+               writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+                      | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+       else
+               writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+                      & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+       if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+           snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
+               schedule_timeout_interruptible(msecs_to_jiffies(333));
+               return 0;
+       }
+       printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
+       return -EIO;
+}
+
+/*
+ * ALSA callback function, called when attempting to open the MIDI device.
+ */
+static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
+{
+       snd_msnd_enable_irq(mpu->private_data);
+       snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
+       return 0;
+}
+
+static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
+{
+       snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
+       snd_msnd_disable_irq(mpu->private_data);
+}
+
+static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static int __devinit snd_msnd_attach(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       int err;
+       static struct snd_device_ops ops = {
+               .dev_free =      snd_msnd_dev_free,
+               };
+
+       err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
+                         chip);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
+               return err;
+       }
+       request_region(chip->io, DSP_NUMIO, card->shortname);
+
+       if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
+               printk(KERN_ERR LOGNAME
+                       ": unable to grab memory region 0x%lx-0x%lx\n",
+                       chip->base, chip->base + BUFFSIZE - 1);
+               release_region(chip->io, DSP_NUMIO);
+               free_irq(chip->irq, chip);
+               return -EBUSY;
+       }
+       chip->mappedbase = ioremap_nocache(chip->base, 0x8000);
+       if (!chip->mappedbase) {
+               printk(KERN_ERR LOGNAME
+                       ": unable to map memory region 0x%lx-0x%lx\n",
+                       chip->base, chip->base + BUFFSIZE - 1);
+               err = -EIO;
+               goto err_release_region;
+       }
+
+       err = snd_msnd_dsp_full_reset(card);
+       if (err < 0)
+               goto err_release_region;
+
+       /* Register device */
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0)
+               goto err_release_region;
+
+       err = snd_msnd_pcm(card, 0, NULL);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
+               goto err_release_region;
+       }
+
+       err = snd_msndmix_new(card);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
+               goto err_release_region;
+       }
+
+
+       if (mpu_io[0] != SNDRV_AUTO_PORT) {
+               struct snd_mpu401 *mpu;
+
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                                         mpu_io[0],
+                                         MPU401_MODE_INPUT |
+                                         MPU401_MODE_OUTPUT,
+                                         mpu_irq[0], IRQF_DISABLED,
+                                         &chip->rmidi);
+               if (err < 0) {
+                       printk(KERN_ERR LOGNAME
+                               ": error creating new Midi device\n");
+                       goto err_release_region;
+               }
+               mpu = chip->rmidi->private_data;
+
+               mpu->open_input = snd_msnd_mpu401_open;
+               mpu->close_input = snd_msnd_mpu401_close;
+               mpu->private_data = chip;
+       }
+
+       disable_irq(chip->irq);
+       snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
+       snd_msndmix_force_recsrc(chip, 0);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto err_release_region;
+
+       return 0;
+
+err_release_region:
+       if (chip->mappedbase)
+               iounmap(chip->mappedbase);
+       release_mem_region(chip->base, BUFFSIZE);
+       release_region(chip->io, DSP_NUMIO);
+       free_irq(chip->irq, chip);
+       return err;
+}
+
+
+static void __devexit snd_msnd_unload(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+
+       iounmap(chip->mappedbase);
+       release_mem_region(chip->base, BUFFSIZE);
+       release_region(chip->io, DSP_NUMIO);
+       free_irq(chip->irq, chip);
+       snd_card_free(card);
+}
+
+#ifndef MSND_CLASSIC
+
+/* Pinnacle/Fiji Logical Device Configuration */
+
+static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value)
+{
+       outb(reg, cfg);
+       outb(value, cfg + 1);
+       if (value != inb(cfg + 1)) {
+               printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
+{
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
+{
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
+{
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+       u16 wmem;
+
+       mem >>= 8;
+       wmem = (u16)(mem & 0xfff);
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+               return -EIO;
+       if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
+                                      MEMTYPE_HIADDR | MEMTYPE_16BIT))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_activate_logical(int cfg, int num)
+{
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
+                                               u16 io1, u16 irq, int mem)
+{
+       if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+               return -EIO;
+       if (snd_msnd_write_cfg_io0(cfg, num, io0))
+               return -EIO;
+       if (snd_msnd_write_cfg_io1(cfg, num, io1))
+               return -EIO;
+       if (snd_msnd_write_cfg_irq(cfg, num, irq))
+               return -EIO;
+       if (snd_msnd_write_cfg_mem(cfg, num, mem))
+               return -EIO;
+       if (snd_msnd_activate_logical(cfg, num))
+               return -EIO;
+       return 0;
+}
+
+static int __devinit snd_msnd_pinnacle_cfg_reset(int cfg)
+{
+       int i;
+
+       /* Reset devices if told to */
+       printk(KERN_INFO LOGNAME ": Resetting all devices\n");
+       for (i = 0; i < 4; ++i)
+               if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
+                       return -EIO;
+
+       return 0;
+}
+#endif
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
+
+static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+#ifndef MSND_CLASSIC
+/* Extra Peripheral Configuration (Default: Disable) */
+static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+/* If we have the digital daugherboard... */
+static int digital[SNDRV_CARDS];
+
+/* Extra Peripheral Configuration */
+static int reset[SNDRV_CARDS];
+#endif
+
+static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
+
+static int calibrate_signal;
+
+#ifdef CONFIG_PNP
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
+#define has_isapnp(x) isapnp[x]
+#else
+#define has_isapnp(x) 0
+#endif
+
+MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
+MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(INITCODEFILE);
+MODULE_FIRMWARE(PERMCODEFILE);
+
+module_param_array(io, long, NULL, S_IRUGO);
+MODULE_PARM_DESC(io, "IO port #");
+module_param_array(irq, int, NULL, S_IRUGO);
+module_param_array(mem, long, NULL, S_IRUGO);
+module_param_array(write_ndelay, int, NULL, S_IRUGO);
+module_param(calibrate_signal, int, S_IRUGO);
+#ifndef MSND_CLASSIC
+module_param_array(digital, int, NULL, S_IRUGO);
+module_param_array(cfg, long, NULL, S_IRUGO);
+module_param_array(reset, int, 0, S_IRUGO);
+module_param_array(mpu_io, long, NULL, S_IRUGO);
+module_param_array(mpu_irq, int, NULL, S_IRUGO);
+module_param_array(ide_io0, long, NULL, S_IRUGO);
+module_param_array(ide_io1, long, NULL, S_IRUGO);
+module_param_array(ide_irq, int, NULL, S_IRUGO);
+module_param_array(joystick_io, long, NULL, S_IRUGO);
+#endif
+
+
+static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i)
+{
+       if (io[i] == SNDRV_AUTO_PORT)
+               return 0;
+
+       if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
+               printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+               return 0;
+       }
+
+#ifdef MSND_CLASSIC
+       if (!(io[i] == 0x290 ||
+             io[i] == 0x260 ||
+             io[i] == 0x250 ||
+             io[i] == 0x240 ||
+             io[i] == 0x230 ||
+             io[i] == 0x220 ||
+             io[i] == 0x210 ||
+             io[i] == 0x3e0)) {
+               printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
+                       " to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
+                       "or 0x3E0\n");
+               return 0;
+       }
+#else
+       if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
+               printk(KERN_ERR LOGNAME
+                       ": \"io\" - DSP I/O base must within the range 0x100 "
+                       "to 0x3E0 and must be evenly divisible by 0x10\n");
+               return 0;
+       }
+#endif /* MSND_CLASSIC */
+
+       if (!(irq[i] == 5 ||
+             irq[i] == 7 ||
+             irq[i] == 9 ||
+             irq[i] == 10 ||
+             irq[i] == 11 ||
+             irq[i] == 12)) {
+               printk(KERN_ERR LOGNAME
+                       ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+               return 0;
+       }
+
+       if (!(mem[i] == 0xb0000 ||
+             mem[i] == 0xc8000 ||
+             mem[i] == 0xd0000 ||
+             mem[i] == 0xd8000 ||
+             mem[i] == 0xe0000 ||
+             mem[i] == 0xe8000)) {
+               printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+                      "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
+                      "0xe8000\n");
+               return 0;
+       }
+
+#ifndef MSND_CLASSIC
+       if (cfg[i] == SNDRV_AUTO_PORT) {
+               printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+       } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
+               printk(KERN_INFO LOGNAME
+                       ": Config port must be 0x250, 0x260 or 0x270 "
+                       "(or unspecified for PnP mode)\n");
+               return 0;
+       }
+#endif /* MSND_CLASSIC */
+
+       return 1;
+}
+
+static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
+{
+       int err;
+       struct snd_card *card;
+       struct snd_msnd *chip;
+
+       if (has_isapnp(idx) || cfg[idx] == SNDRV_AUTO_PORT) {
+               printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+               return -ENODEV;
+       }
+
+       err = snd_card_create(index[idx], id[idx], THIS_MODULE,
+                             sizeof(struct snd_msnd), &card);
+       if (err < 0)
+               return err;
+
+       snd_card_set_dev(card, pdev);
+       chip = card->private_data;
+       chip->card = card;
+
+#ifdef MSND_CLASSIC
+       switch (irq[idx]) {
+       case 5:
+               chip->irqid = HPIRQ_5; break;
+       case 7:
+               chip->irqid = HPIRQ_7; break;
+       case 9:
+               chip->irqid = HPIRQ_9; break;
+       case 10:
+               chip->irqid = HPIRQ_10; break;
+       case 11:
+               chip->irqid = HPIRQ_11; break;
+       case 12:
+               chip->irqid = HPIRQ_12; break;
+       }
+
+       switch (mem[idx]) {
+       case 0xb0000:
+               chip->memid = HPMEM_B000; break;
+       case 0xc8000:
+               chip->memid = HPMEM_C800; break;
+       case 0xd0000:
+               chip->memid = HPMEM_D000; break;
+       case 0xd8000:
+               chip->memid = HPMEM_D800; break;
+       case 0xe0000:
+               chip->memid = HPMEM_E000; break;
+       case 0xe8000:
+               chip->memid = HPMEM_E800; break;
+       }
+#else
+       printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
+                       cfg[idx]);
+
+       if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
+               printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
+                          cfg[idx]);
+               snd_card_free(card);
+               return -EIO;
+       }
+       if (reset[idx])
+               if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
+                       err = -EIO;
+                       goto cfg_error;
+               }
+
+       /* DSP */
+       err = snd_msnd_write_cfg_logical(cfg[idx], 0,
+                                        io[idx], 0,
+                                        irq[idx], mem[idx]);
+
+       if (err)
+               goto cfg_error;
+
+       /* The following are Pinnacle specific */
+
+       /* MPU */
+       if (mpu_io[idx] != SNDRV_AUTO_PORT
+           && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
+               printk(KERN_INFO LOGNAME
+                      ": Configuring MPU to I/O 0x%lx IRQ %d\n",
+                      mpu_io[idx], mpu_irq[idx]);
+               err = snd_msnd_write_cfg_logical(cfg[idx], 1,
+                                                mpu_io[idx], 0,
+                                                mpu_irq[idx], 0);
+
+               if (err)
+                       goto cfg_error;
+       }
+
+       /* IDE */
+       if (ide_io0[idx] != SNDRV_AUTO_PORT
+           && ide_io1[idx] != SNDRV_AUTO_PORT
+           && ide_irq[idx] != SNDRV_AUTO_IRQ) {
+               printk(KERN_INFO LOGNAME
+                      ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
+                      ide_io0[idx], ide_io1[idx], ide_irq[idx]);
+               err = snd_msnd_write_cfg_logical(cfg[idx], 2,
+                                                ide_io0[idx], ide_io1[idx],
+                                                ide_irq[idx], 0);
+
+               if (err)
+                       goto cfg_error;
+       }
+
+       /* Joystick */
+       if (joystick_io[idx] != SNDRV_AUTO_PORT) {
+               printk(KERN_INFO LOGNAME
+                      ": Configuring joystick to I/O 0x%lx\n",
+                      joystick_io[idx]);
+               err = snd_msnd_write_cfg_logical(cfg[idx], 3,
+                                                joystick_io[idx], 0,
+                                                0, 0);
+
+               if (err)
+                       goto cfg_error;
+       }
+       release_region(cfg[idx], 2);
+
+#endif /* MSND_CLASSIC */
+
+       set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+       chip->type = msndClassic;
+#else
+       chip->type = msndPinnacle;
+#endif
+       chip->io = io[idx];
+       chip->irq = irq[idx];
+       chip->base = mem[idx];
+
+       chip->calibrate_signal = calibrate_signal ? 1 : 0;
+       chip->recsrc = 0;
+       chip->dspq_data_buff = DSPQ_DATA_BUFF;
+       chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+       if (write_ndelay[idx])
+               clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+       else
+               set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+       if (digital[idx])
+               set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+       spin_lock_init(&chip->lock);
+       err = snd_msnd_probe(card);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": Probe failed\n");
+               snd_card_free(card);
+               return err;
+       }
+
+       err = snd_msnd_attach(card);
+       if (err < 0) {
+               printk(KERN_ERR LOGNAME ": Attach failed\n");
+               snd_card_free(card);
+               return err;
+       }
+       dev_set_drvdata(pdev, card);
+
+       return 0;
+
+#ifndef MSND_CLASSIC
+cfg_error:
+       release_region(cfg[idx], 2);
+       snd_card_free(card);
+       return err;
+#endif
+}
+
+static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
+{
+       snd_msnd_unload(dev_get_drvdata(pdev));
+       dev_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+#define DEV_NAME "msnd-pinnacle"
+
+static struct isa_driver snd_msnd_driver = {
+       .match          = snd_msnd_isa_match,
+       .probe          = snd_msnd_isa_probe,
+       .remove         = __devexit_p(snd_msnd_isa_remove),
+       /* FIXME: suspend, resume */
+       .driver         = {
+               .name   = DEV_NAME
+       },
+};
+
+#ifdef CONFIG_PNP
+static int __devinit snd_msnd_pnp_detect(struct pnp_card_link *pcard,
+                                        const struct pnp_card_device_id *pid)
+{
+       static int idx;
+       struct pnp_dev *pnp_dev;
+       struct pnp_dev *mpu_dev;
+       struct snd_card *card;
+       struct snd_msnd *chip;
+       int ret;
+
+       for ( ; idx < SNDRV_CARDS; idx++) {
+               if (has_isapnp(idx))
+                       break;
+       }
+       if (idx >= SNDRV_CARDS)
+               return -ENODEV;
+
+       /*
+        * Check that we still have room for another sound card ...
+        */
+       pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+       if (!pnp_dev)
+               return -ENODEV;
+
+       mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
+       if (!mpu_dev)
+               return -ENODEV;
+
+       if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
+               printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
+               return -EBUSY;
+       }
+
+       if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
+               printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Create a new ALSA sound card entry, in anticipation
+        * of detecting our hardware ...
+        */
+       ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
+                             sizeof(struct snd_msnd), &card);
+       if (ret < 0)
+               return ret;
+
+       chip = card->private_data;
+       chip->card = card;
+       snd_card_set_dev(card, &pcard->card->dev);
+
+       /*
+        * Read the correct parameters off the ISA PnP bus ...
+        */
+       io[idx] = pnp_port_start(pnp_dev, 0);
+       irq[idx] = pnp_irq(pnp_dev, 0);
+       mem[idx] = pnp_mem_start(pnp_dev, 0);
+       mpu_io[idx] = pnp_port_start(mpu_dev, 0);
+       mpu_irq[idx] = pnp_irq(mpu_dev, 0);
+
+       set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+       chip->type = msndClassic;
+#else
+       chip->type = msndPinnacle;
+#endif
+       chip->io = io[idx];
+       chip->irq = irq[idx];
+       chip->base = mem[idx];
+
+       chip->calibrate_signal = calibrate_signal ? 1 : 0;
+       chip->recsrc = 0;
+       chip->dspq_data_buff = DSPQ_DATA_BUFF;
+       chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+       if (write_ndelay[idx])
+               clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+       else
+               set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+       if (digital[idx])
+               set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+       spin_lock_init(&chip->lock);
+       ret = snd_msnd_probe(card);
+       if (ret < 0) {
+               printk(KERN_ERR LOGNAME ": Probe failed\n");
+               goto _release_card;
+       }
+
+       ret = snd_msnd_attach(card);
+       if (ret < 0) {
+               printk(KERN_ERR LOGNAME ": Attach failed\n");
+               goto _release_card;
+       }
+
+       pnp_set_card_drvdata(pcard, card);
+       ++idx;
+       return 0;
+
+_release_card:
+       snd_card_free(card);
+       return ret;
+}
+
+static void __devexit snd_msnd_pnp_remove(struct pnp_card_link *pcard)
+{
+       snd_msnd_unload(pnp_get_card_drvdata(pcard));
+       pnp_set_card_drvdata(pcard, NULL);
+}
+
+static int isa_registered;
+static int pnp_registered;
+
+static struct pnp_card_device_id msnd_pnpids[] = {
+       /* Pinnacle PnP */
+       { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
+       { .id = "" }    /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
+
+static struct pnp_card_driver msnd_pnpc_driver = {
+       .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+       .name = "msnd_pinnacle",
+       .id_table = msnd_pnpids,
+       .probe = snd_msnd_pnp_detect,
+       .remove = __devexit_p(snd_msnd_pnp_remove),
+};
+#endif /* CONFIG_PNP */
+
+static int __init snd_msnd_init(void)
+{
+       int err;
+
+       err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+       if (!err)
+               isa_registered = 1;
+
+       err = pnp_register_card_driver(&msnd_pnpc_driver);
+       if (!err)
+               pnp_registered = 1;
+
+       if (isa_registered)
+               err = 0;
+#endif
+       return err;
+}
+
+static void __exit snd_msnd_exit(void)
+{
+#ifdef CONFIG_PNP
+       if (pnp_registered)
+               pnp_unregister_card_driver(&msnd_pnpc_driver);
+       if (isa_registered)
+#endif
+               isa_unregister_driver(&snd_msnd_driver);
+}
+
+module_init(snd_msnd_init);
+module_exit(snd_msnd_exit);
+
diff --git a/sound/isa/msnd/msnd_pinnacle.h b/sound/isa/msnd/msnd_pinnacle.h
new file mode 100644 (file)
index 0000000..48318d1
--- /dev/null
@@ -0,0 +1,181 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO                              0x08
+
+#define IREG_LOGDEVICE                         0x07
+#define IREG_ACTIVATE                          0x30
+#define LD_ACTIVATE                            0x01
+#define LD_DISACTIVATE                         0x00
+#define IREG_EECONTROL                         0x3F
+#define IREG_MEMBASEHI                         0x40
+#define IREG_MEMBASELO                         0x41
+#define IREG_MEMCONTROL                                0x42
+#define IREG_MEMRANGEHI                                0x43
+#define IREG_MEMRANGELO                                0x44
+#define MEMTYPE_8BIT                           0x00
+#define MEMTYPE_16BIT                          0x02
+#define MEMTYPE_RANGE                          0x00
+#define MEMTYPE_HIADDR                         0x01
+#define IREG_IO0_BASEHI                                0x60
+#define IREG_IO0_BASELO                                0x61
+#define IREG_IO1_BASEHI                                0x62
+#define IREG_IO1_BASELO                                0x63
+#define IREG_IRQ_NUMBER                                0x70
+#define IREG_IRQ_TYPE                          0x71
+#define IRQTYPE_HIGH                           0x02
+#define IRQTYPE_LOW                            0x00
+#define IRQTYPE_LEVEL                          0x01
+#define IRQTYPE_EDGE                           0x00
+
+#define        HP_DSPR                                 0x04
+#define        HP_BLKS                                 0x04
+
+#define HPDSPRESET_OFF                         2
+#define HPDSPRESET_ON                          0
+
+#define HPBLKSEL_0                             2
+#define HPBLKSEL_1                             3
+
+#define        HIMT_DAT_OFF                            0x03
+
+#define        HIDSP_PLAY_UNDER                        0x00
+#define        HIDSP_INT_PLAY_UNDER                    0x01
+#define        HIDSP_SSI_TX_UNDER                      0x02
+#define HIDSP_RECQ_OVERFLOW                    0x08
+#define HIDSP_INT_RECORD_OVER                  0x09
+#define HIDSP_SSI_RX_OVERFLOW                  0x0a
+
+#define        HIDSP_MIDI_IN_OVER                      0x10
+
+#define        HIDSP_MIDI_FRAME_ERR                    0x11
+#define        HIDSP_MIDI_PARITY_ERR                   0x12
+#define        HIDSP_MIDI_OVERRUN_ERR                  0x13
+
+#define HIDSP_INPUT_CLIPPING                   0x20
+#define        HIDSP_MIX_CLIPPING                      0x30
+#define HIDSP_DAT_IN_OFF                       0x21
+
+#define TIME_PRO_RESET_DONE                    0x028A
+#define TIME_PRO_SYSEX                         0x001E
+#define TIME_PRO_RESET                         0x0032
+
+#define DAR_BUFF_SIZE                          0x1000
+
+#define MIDQ_BUFF_SIZE                         0x800
+#define DSPQ_BUFF_SIZE                         0x5A0
+
+#define DSPQ_DATA_BUFF                         0x7860
+
+#define MOP_WAVEHDR                            0
+#define MOP_EXTOUT                             1
+#define MOP_HWINIT                             0xfe
+#define MOP_NONE                               0xff
+#define MOP_MAX                                        1
+
+#define MIP_EXTIN                              0
+#define MIP_WAVEHDR                            1
+#define MIP_HWINIT                             0xfe
+#define MIP_MAX                                        1
+
+/* Pinnacle/Fiji SMA Common Data */
+#define SMA_wCurrPlayBytes                     0x0000
+#define SMA_wCurrRecordBytes                   0x0002
+#define SMA_wCurrPlayVolLeft                   0x0004
+#define SMA_wCurrPlayVolRight                  0x0006
+#define SMA_wCurrInVolLeft                     0x0008
+#define SMA_wCurrInVolRight                    0x000a
+#define SMA_wCurrMHdrVolLeft                   0x000c
+#define SMA_wCurrMHdrVolRight                  0x000e
+#define SMA_dwCurrPlayPitch                    0x0010
+#define SMA_dwCurrPlayRate                     0x0014
+#define SMA_wCurrMIDIIOPatch                   0x0018
+#define SMA_wCurrPlayFormat                    0x001a
+#define SMA_wCurrPlaySampleSize                        0x001c
+#define SMA_wCurrPlayChannels                  0x001e
+#define SMA_wCurrPlaySampleRate                        0x0020
+#define SMA_wCurrRecordFormat                  0x0022
+#define SMA_wCurrRecordSampleSize              0x0024
+#define SMA_wCurrRecordChannels                        0x0026
+#define SMA_wCurrRecordSampleRate              0x0028
+#define SMA_wCurrDSPStatusFlags                        0x002a
+#define SMA_wCurrHostStatusFlags               0x002c
+#define SMA_wCurrInputTagBits                  0x002e
+#define SMA_wCurrLeftPeak                      0x0030
+#define SMA_wCurrRightPeak                     0x0032
+#define SMA_bMicPotPosLeft                     0x0034
+#define SMA_bMicPotPosRight                    0x0035
+#define SMA_bMicPotMaxLeft                     0x0036
+#define SMA_bMicPotMaxRight                    0x0037
+#define SMA_bInPotPosLeft                      0x0038
+#define SMA_bInPotPosRight                     0x0039
+#define SMA_bAuxPotPosLeft                     0x003a
+#define SMA_bAuxPotPosRight                    0x003b
+#define SMA_bInPotMaxLeft                      0x003c
+#define SMA_bInPotMaxRight                     0x003d
+#define SMA_bAuxPotMaxLeft                     0x003e
+#define SMA_bAuxPotMaxRight                    0x003f
+#define SMA_bInPotMaxMethod                    0x0040
+#define SMA_bAuxPotMaxMethod                   0x0041
+#define SMA_wCurrMastVolLeft                   0x0042
+#define SMA_wCurrMastVolRight                  0x0044
+#define SMA_wCalFreqAtoD                       0x0046
+#define SMA_wCurrAuxVolLeft                    0x0048
+#define SMA_wCurrAuxVolRight                   0x004a
+#define SMA_wCurrPlay1VolLeft                  0x004c
+#define SMA_wCurrPlay1VolRight                 0x004e
+#define SMA_wCurrPlay2VolLeft                  0x0050
+#define SMA_wCurrPlay2VolRight                 0x0052
+#define SMA_wCurrPlay3VolLeft                  0x0054
+#define SMA_wCurrPlay3VolRight                 0x0056
+#define SMA_wCurrPlay4VolLeft                  0x0058
+#define SMA_wCurrPlay4VolRight                 0x005a
+#define SMA_wCurrPlay1PeakLeft                 0x005c
+#define SMA_wCurrPlay1PeakRight                        0x005e
+#define SMA_wCurrPlay2PeakLeft                 0x0060
+#define SMA_wCurrPlay2PeakRight                        0x0062
+#define SMA_wCurrPlay3PeakLeft                 0x0064
+#define SMA_wCurrPlay3PeakRight                        0x0066
+#define SMA_wCurrPlay4PeakLeft                 0x0068
+#define SMA_wCurrPlay4PeakRight                        0x006a
+#define SMA_wCurrPlayPeakLeft                  0x006c
+#define SMA_wCurrPlayPeakRight                 0x006e
+#define SMA_wCurrDATSR                         0x0070
+#define SMA_wCurrDATRXCHNL                     0x0072
+#define SMA_wCurrDATTXCHNL                     0x0074
+#define SMA_wCurrDATRXRate                     0x0076
+#define SMA_dwDSPPlayCount                     0x0078
+#define SMA__size                              0x007c
+
+#define INITCODEFILE           "turtlebeach/pndspini.bin"
+#define PERMCODEFILE           "turtlebeach/pndsperm.bin"
+#define LONGNAME               "MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
new file mode 100644 (file)
index 0000000..494058a
--- /dev/null
@@ -0,0 +1,343 @@
+/***************************************************************************
+                         msnd_pinnacle_mixer.c  -  description
+                            -------------------
+    begin              : Fre Jun 7 2002
+    copyright          : (C) 2002 by karsten wiese
+    email              : annabellesgarden@yahoo.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                        *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                  *
+ *                                                                        *
+ ***************************************************************************/
+
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+
+#define MSND_MIXER_VOLUME      0
+#define MSND_MIXER_PCM         1
+#define MSND_MIXER_AUX         2       /* Input source 1  (aux1) */
+#define MSND_MIXER_IMIX                3       /*  Recording monitor  */
+#define MSND_MIXER_SYNTH       4
+#define MSND_MIXER_SPEAKER     5
+#define MSND_MIXER_LINE                6
+#define MSND_MIXER_MIC         7
+#define MSND_MIXER_RECLEV      11      /* Recording level */
+#define MSND_MIXER_IGAIN       12      /* Input gain */
+#define MSND_MIXER_OGAIN       13      /* Output gain */
+#define MSND_MIXER_DIGITAL     17      /* Digital (input) 1 */
+
+/*     Device mask bits        */
+
+#define MSND_MASK_VOLUME       (1 << MSND_MIXER_VOLUME)
+#define MSND_MASK_SYNTH                (1 << MSND_MIXER_SYNTH)
+#define MSND_MASK_PCM          (1 << MSND_MIXER_PCM)
+#define MSND_MASK_SPEAKER      (1 << MSND_MIXER_SPEAKER)
+#define MSND_MASK_LINE         (1 << MSND_MIXER_LINE)
+#define MSND_MASK_MIC          (1 << MSND_MIXER_MIC)
+#define MSND_MASK_IMIX         (1 << MSND_MIXER_IMIX)
+#define MSND_MASK_RECLEV       (1 << MSND_MIXER_RECLEV)
+#define MSND_MASK_IGAIN                (1 << MSND_MIXER_IGAIN)
+#define MSND_MASK_OGAIN                (1 << MSND_MIXER_OGAIN)
+#define MSND_MASK_AUX          (1 << MSND_MIXER_AUX)
+#define MSND_MASK_DIGITAL      (1 << MSND_MIXER_DIGITAL)
+
+static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[3] = {
+               "Analog", "MASS", "SPDIF",
+       };
+       struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+       unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = items;
+       if (uinfo->value.enumerated.item >= items)
+               uinfo->value.enumerated.item = items - 1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+       /* MSND_MASK_IMIX is the default */
+       ucontrol->value.enumerated.item[0] = 0;
+
+       if (chip->recsrc & MSND_MASK_SYNTH) {
+               ucontrol->value.enumerated.item[0] = 1;
+       } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
+                test_bit(F_HAVEDIGITAL, &chip->flags)) {
+               ucontrol->value.enumerated.item[0] = 2;
+       }
+
+
+       return 0;
+}
+
+static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
+{
+       unsigned newrecsrc;
+       int change;
+       unsigned char msndbyte;
+
+       switch (val) {
+       case 0:
+               newrecsrc = MSND_MASK_IMIX;
+               msndbyte = HDEXAR_SET_ANA_IN;
+               break;
+       case 1:
+               newrecsrc = MSND_MASK_SYNTH;
+               msndbyte = HDEXAR_SET_SYNTH_IN;
+               break;
+       case 2:
+               newrecsrc = MSND_MASK_DIGITAL;
+               msndbyte = HDEXAR_SET_DAT_IN;
+               break;
+       default:
+               return -EINVAL;
+       }
+       change  = newrecsrc != chip->recsrc;
+       if (change) {
+               change = 0;
+               if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
+                       if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
+                               chip->recsrc = newrecsrc;
+                               change = 1;
+                       }
+       }
+       return change;
+}
+
+static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+       return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
+}
+
+
+static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 100;
+       return 0;
+}
+
+static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+       int addr = kcontrol->private_value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&msnd->mixer_lock, flags);
+       ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
+       ucontrol->value.integer.value[0] /= 0xFFFF;
+       ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
+       ucontrol->value.integer.value[1] /= 0xFFFF;
+       spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+       return 0;
+}
+
+#define update_volm(a, b)                                              \
+       do {                                                            \
+               writew((dev->left_levels[a] >> 1) *                     \
+                      readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+                      dev->SMA + SMA_##b##Left);                       \
+               writew((dev->right_levels[a] >> 1)  *                   \
+                      readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+                      dev->SMA + SMA_##b##Right);                      \
+       } while (0);
+
+#define update_potm(d, s, ar)                                          \
+       do {                                                            \
+               writeb((dev->left_levels[d] >> 8) *                     \
+                      readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+                      dev->SMA + SMA_##s##Left);                       \
+               writeb((dev->right_levels[d] >> 8) *                    \
+                      readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+                      dev->SMA + SMA_##s##Right);                      \
+               if (snd_msnd_send_word(dev, 0, 0, ar) == 0)             \
+                       snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);       \
+       } while (0);
+
+#define update_pot(d, s, ar)                                           \
+       do {                                                            \
+               writeb(dev->left_levels[d] >> 8,                        \
+                      dev->SMA + SMA_##s##Left);                       \
+               writeb(dev->right_levels[d] >> 8,                       \
+                      dev->SMA + SMA_##s##Right);                      \
+               if (snd_msnd_send_word(dev, 0, 0, ar) == 0)             \
+                       snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);       \
+       } while (0);
+
+
+static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
+{
+       int bLeft, bRight;
+       int wLeft, wRight;
+       int updatemaster = 0;
+
+       if (d >= LEVEL_ENTRIES)
+               return -EINVAL;
+
+       bLeft = left * 0xff / 100;
+       wLeft = left * 0xffff / 100;
+
+       bRight = right * 0xff / 100;
+       wRight = right * 0xffff / 100;
+
+       dev->left_levels[d] = wLeft;
+       dev->right_levels[d] = wRight;
+
+       switch (d) {
+               /* master volume unscaled controls */
+       case MSND_MIXER_LINE:                   /* line pot control */
+               /* scaled by IMIX in digital mix */
+               writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
+               writeb(bRight, dev->SMA + SMA_bInPotPosRight);
+               if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+                       snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+               break;
+       case MSND_MIXER_MIC:                    /* mic pot control */
+               if (dev->type == msndClassic)
+                       return -EINVAL;
+               /* scaled by IMIX in digital mix */
+               writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
+               writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
+               if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+                       snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+               break;
+       case MSND_MIXER_VOLUME:         /* master volume */
+               writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
+               writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
+               /* fall through */
+
+       case MSND_MIXER_AUX:                    /* aux pot control */
+               /* scaled by master volume */
+               /* fall through */
+
+               /* digital controls */
+       case MSND_MIXER_SYNTH:                  /* synth vol (dsp mix) */
+       case MSND_MIXER_PCM:                    /* pcm vol (dsp mix) */
+       case MSND_MIXER_IMIX:                   /* input monitor (dsp mix) */
+               /* scaled by master volume */
+               updatemaster = 1;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (updatemaster) {
+               /* update master volume scaled controls */
+               update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+               update_volm(MSND_MIXER_IMIX, wCurrInVol);
+               if (dev->type == msndPinnacle)
+                       update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+               update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+       }
+
+       return 0;
+}
+
+static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+       int change, addr = kcontrol->private_value;
+       int left, right;
+       unsigned long flags;
+
+       left = ucontrol->value.integer.value[0] % 101;
+       right = ucontrol->value.integer.value[1] % 101;
+       spin_lock_irqsave(&msnd->mixer_lock, flags);
+       change = msnd->left_levels[addr] != left
+               || msnd->right_levels[addr] != right;
+       snd_msndmix_set(msnd, addr, left, right);
+       spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+       return change;
+}
+
+
+#define DUMMY_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_msndmix_volume_info, \
+  .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
+  .private_value = addr }
+
+
+static struct snd_kcontrol_new snd_msnd_controls[] = {
+DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
+DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
+DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
+DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
+DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
+DUMMY_VOLUME("Monitor",        0, MSND_MIXER_IMIX),
+{
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
+       .info = snd_msndmix_info_mux,
+       .get = snd_msndmix_get_mux,
+       .put = snd_msndmix_put_mux,
+}
+};
+
+
+int __devinit snd_msndmix_new(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       unsigned int idx;
+       int err;
+
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
+       spin_lock_init(&chip->mixer_lock);
+       strcpy(card->mixername, "MSND Pinnacle Mixer");
+
+       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+               err = snd_ctl_add(card,
+                                 snd_ctl_new1(snd_msnd_controls + idx, chip));
+               if (err < 0)
+                       return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(snd_msndmix_new);
+
+void snd_msndmix_setup(struct snd_msnd *dev)
+{
+       update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+       update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+       update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+       update_volm(MSND_MIXER_IMIX, wCurrInVol);
+       if (dev->type == msndPinnacle) {
+               update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+               update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+       }
+}
+EXPORT_SYMBOL(snd_msndmix_setup);
+
+int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
+{
+       dev->recsrc = -1;
+       return snd_msndmix_set_mux(dev, recsrc);
+}
+EXPORT_SYMBOL(snd_msndmix_force_recsrc);
index b848d10018641c3e280d024da3ed8521fde90be8..ef95279da7a3a47a7bcfe5b21674e6c0f063ce7d 100644 (file)
@@ -179,12 +179,13 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
        unsigned char result;
 #if 0
        outb(0x1d, port);       /* password */
-       printk("read [0x%lx] = 0x%x\n", port, inb(port));
+       printk(KERN_DEBUG "read [0x%lx] = 0x%x\n", port, inb(port));
 #endif
        outb(reg, chip->port);  /* register */
        result = inb(chip->port + 1);
 #if 0
-       printk("read [0x%lx] = 0x%x [0x%x]\n", port, result, inb(port));
+       printk(KERN_DEBUG "read [0x%lx] = 0x%x [0x%x]\n",
+              port, result, inb(port));
 #endif
        return result;
 }
@@ -233,7 +234,10 @@ static int __devinit snd_opl3sa2_detect(struct snd_card *card)
                snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
                return -EBUSY;
        }
-       // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a));
+       /*
+       snd_printk(KERN_DEBUG "REG 0A = 0x%x\n",
+                  snd_opl3sa2_read(chip, 0x0a));
+       */
        chip->version = 0;
        tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
        if (tmp == 0xff) {
@@ -619,25 +623,28 @@ static void snd_opl3sa2_free(struct snd_card *card)
 {
        struct snd_opl3sa2 *chip = card->private_data;
        if (chip->irq >= 0)
-               free_irq(chip->irq, (void *)chip);
+               free_irq(chip->irq, card);
        release_and_free_resource(chip->res_port);
 }
 
-static struct snd_card *snd_opl3sa2_card_new(int dev)
+static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_opl3sa2 *chip;
+       int err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2));
-       if (card == NULL)
-               return NULL;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_opl3sa2), &card);
+       if (err < 0)
+               return err;
        strcpy(card->driver, "OPL3SA2");
-       strcpy(card->shortname, "Yamaha OPL3-SA2");
+       strcpy(card->shortname, "Yamaha OPL3-SA");
        chip = card->private_data;
        spin_lock_init(&chip->reg_lock);
        chip->irq = -1;
        card->private_free = snd_opl3sa2_free;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
@@ -729,9 +736,9 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_opl3sa2_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_opl3sa2_card_new(dev, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
@@ -795,9 +802,9 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_opl3sa2_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_opl3sa2_card_new(dev, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
@@ -876,9 +883,9 @@ static int __devinit snd_opl3sa2_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       card = snd_opl3sa2_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_opl3sa2_card_new(dev, &card);
+       if (err < 0)
+               return err;
        snd_card_set_dev(card, pdev);
        if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
                snd_card_free(card);
index 440755cc00137c663e39c11e258c76ca5d944bed..02e30d7c6a93b216296ff5298916be79053195ff 100644 (file)
@@ -1228,9 +1228,10 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
        struct snd_pcm *pcm;
        struct snd_rawmidi *rmidi;
 
-       if (!(card = snd_card_new(index, id, THIS_MODULE,
-                                 sizeof(struct snd_miro))))
-               return -ENOMEM;
+       error = snd_card_create(index, id, THIS_MODULE,
+                               sizeof(struct snd_miro), &card);
+       if (error < 0)
+               return error;
 
        card->private_free = snd_card_miro_free;
        miro = card->private_data;
index 19706b0d84978c5307166826b9aed76a0c40f46e..5cd555325b9d443285d2d00138e9b990a33169c8 100644 (file)
@@ -252,7 +252,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
 #endif /* OPTi93X */
 
        default:
-               snd_printk("chip %d not supported\n", hardware);
+               snd_printk(KERN_ERR "chip %d not supported\n", hardware);
                return -ENODEV;
        }
        return 0;
@@ -294,7 +294,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
 #endif /* OPTi93X */
 
        default:
-               snd_printk("chip %d not supported\n", chip->hardware);
+               snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
        }
 
        spin_unlock_irqrestore(&chip->lock, flags);
@@ -336,7 +336,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
 #endif /* OPTi93X */
 
        default:
-               snd_printk("chip %d not supported\n", chip->hardware);
+               snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
        }
 
        spin_unlock_irqrestore(&chip->lock, flags);
@@ -412,7 +412,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
 #endif /* OPTi93X */
 
        default:
-               snd_printk("chip %d not supported\n", chip->hardware);
+               snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
                return -EINVAL;
        }
 
@@ -430,7 +430,8 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
                wss_base_bits = 0x02;
                break;
        default:
-               snd_printk("WSS port 0x%lx not valid\n", chip->wss_base);
+               snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
+                          chip->wss_base);
                goto __skip_base;
        }
        snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -455,7 +456,7 @@ __skip_base:
                irq_bits = 0x04;
                break;
        default:
-               snd_printk("WSS irq # %d not valid\n", chip->irq);
+               snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
                goto __skip_resources;
        }
 
@@ -470,13 +471,14 @@ __skip_base:
                dma_bits = 0x03;
                break;
        default:
-               snd_printk("WSS dma1 # %d not valid\n", chip->dma1);
+               snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
+                          chip->dma1);
                goto __skip_resources;
        }
 
 #if defined(CS4231) || defined(OPTi93X)
        if (chip->dma1 == chip->dma2) {
-               snd_printk("don't want to share dmas\n");
+               snd_printk(KERN_ERR "don't want to share dmas\n");
                return -EBUSY;
        }
 
@@ -485,7 +487,8 @@ __skip_base:
        case 1:
                break;
        default:
-               snd_printk("WSS dma2 # %d not valid\n", chip->dma2);
+               snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
+                          chip->dma2);
                goto __skip_resources;
        }
        dma_bits |= 0x04;
@@ -516,7 +519,8 @@ __skip_resources:
                        mpu_port_bits = 0x00;
                        break;
                default:
-                       snd_printk("MPU-401 port 0x%lx not valid\n",
+                       snd_printk(KERN_WARNING
+                                  "MPU-401 port 0x%lx not valid\n",
                                chip->mpu_port);
                        goto __skip_mpu;
                }
@@ -535,7 +539,7 @@ __skip_resources:
                        mpu_irq_bits = 0x01;
                        break;
                default:
-                       snd_printk("MPU-401 irq # %d not valid\n",
+                       snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
                                chip->mpu_irq);
                        goto __skip_mpu;
                }
@@ -726,7 +730,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        if (chip->wss_base == SNDRV_AUTO_PORT) {
                chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
                if (chip->wss_base < 0) {
-                       snd_printk("unable to find a free WSS port\n");
+                       snd_printk(KERN_ERR "unable to find a free WSS port\n");
                        return -EBUSY;
                }
        }
@@ -815,14 +819,8 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
                                   chip->fm_port, chip->fm_port + 4 - 1);
                }
                if (opl3) {
-#ifdef CS4231
-                       const int t1dev = 1;
-#else
-                       const int t1dev = 0;
-#endif
-                       if ((error = snd_opl3_timer_new(opl3, t1dev, t1dev+1)) < 0)
-                               return error;
-                       if ((error = snd_opl3_hwdep_new(opl3, 0, 1, &synth)) < 0)
+                       error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
+                       if (error < 0)
                                return error;
                }
        }
@@ -830,15 +828,18 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        return snd_card_register(card);
 }
 
-static struct snd_card *snd_opti9xx_card_new(void)
+static int snd_opti9xx_card_new(struct snd_card **cardp)
 {
        struct snd_card *card;
+       int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, sizeof(struct snd_opti9xx));
-       if (! card)
-               return NULL;
+       err = snd_card_create(index, id, THIS_MODULE,
+                             sizeof(struct snd_opti9xx), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_card_opti9xx_free;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_opti9xx_isa_match(struct device *devptr,
@@ -897,15 +898,15 @@ static int __devinit snd_opti9xx_isa_probe(struct device *devptr,
 #if defined(CS4231) || defined(OPTi93X)
        if (dma2 == SNDRV_AUTO_DMA) {
                if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) {
-                       snd_printk("unable to find a free DMA2\n");
+                       snd_printk(KERN_ERR "unable to find a free DMA2\n");
                        return -EBUSY;
                }
        }
 #endif
 
-       card = snd_opti9xx_card_new();
-       if (! card)
-               return -ENOMEM;
+       error = snd_opti9xx_card_new(&card);
+       if (error < 0)
+               return error;
 
        if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) {
                snd_card_free(card);
@@ -950,9 +951,9 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
                return -EBUSY;
        if (! isapnp)
                return -ENODEV;
-       card = snd_opti9xx_card_new();
-       if (! card)
-               return -ENOMEM;
+       error = snd_opti9xx_card_new(&card);
+       if (error < 0)
+               return error;
        chip = card->private_data;
 
        hw = snd_card_opti9xx_pnp(chip, pcard, pid);
index c8c8e214c843421a6288a30b8634cf5a76138134..cafc3a7316a89c4948deaf4d51e7b53fa3cce1c7 100644 (file)
@@ -108,9 +108,10 @@ static int __devinit snd_card_es968_probe(int dev,
        struct snd_card *card;
        struct snd_card_es968 *acard;
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct snd_card_es968))) == NULL)
-               return -ENOMEM;
+       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                               sizeof(struct snd_card_es968), &card);
+       if (error < 0)
+               return error;
        acard = card->private_data;
        if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
                snd_card_free(card);
index 2c201f78ce50a0abd79238c51d81e8f8b8482952..519c36346dec5e232ed162bb7a9552a777acc068 100644 (file)
@@ -324,14 +324,18 @@ static void snd_sb16_free(struct snd_card *card)
 #define is_isapnp_selected(dev)                0
 #endif
 
-static struct snd_card *snd_sb16_card_new(int dev)
+static int snd_sb16_card_new(int dev, struct snd_card **cardp)
 {
-       struct snd_card *card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                       sizeof(struct snd_card_sb16));
-       if (card == NULL)
-               return NULL;
+       struct snd_card *card;
+       int err;
+
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_card_sb16), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_sb16_free;
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit snd_sb16_probe(struct snd_card *card, int dev)
@@ -489,9 +493,9 @@ static int __devinit snd_sb16_isa_probe1(int dev, struct device *pdev)
        struct snd_card *card;
        int err;
 
-       card = snd_sb16_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_sb16_card_new(dev, &card);
+       if (err < 0)
+               return err;
 
        acard = card->private_data;
        /* non-PnP FM port address is hardwired with base port address */
@@ -610,9 +614,9 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
        for ( ; dev < SNDRV_CARDS; dev++) {
                if (!enable[dev] || !isapnp[dev])
                        continue;
-               card = snd_sb16_card_new(dev);
-               if (! card)
-                       return -ENOMEM;
+               res = snd_sb16_card_new(dev, &card);
+               if (res < 0)
+                       return res;
                snd_card_set_dev(card, &pcard->card->dev);
                if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
                    (res = snd_sb16_probe(card, dev)) < 0) {
index ea06877be4b135fb8256de12ebe416dc9df46901..3cd57ee54660716a8182d9c33e2771b4263500f6 100644 (file)
@@ -103,10 +103,10 @@ static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev)
        struct snd_opl3 *opl3;
        int err;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_sb8));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_sb8), &card);
+       if (err < 0)
+               return err;
        acard = card->private_data;
        card->private_free = snd_sb8_free;
 
index 406a431af91ec6880d548b39b0f423c9bb01a56b..475220bbcc9626085f2522a0c75246ef36115833 100644 (file)
@@ -182,7 +182,7 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
 
 static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[5] = {
+       static const char *texts[5] = {
                "CD", "Mic", "Line", "Synth", "Master"
        };
 
@@ -268,13 +268,74 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
        return change;
 }
 
+/*
+ * ALS4000 mono recording control switch
+ */
+
+static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
+                                            struct snd_ctl_elem_info *uinfo)
+{
+       static const char *texts[3] = {
+               "L chan only", "R chan only", "L ch/2 + R ch/2"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 3;
+       if (uinfo->value.enumerated.item > 2)
+               uinfo->value.enumerated.item = 2;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       unsigned char oval;
+
+       spin_lock_irqsave(&sb->mixer_lock, flags);
+       oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+       spin_unlock_irqrestore(&sb->mixer_lock, flags);
+       oval >>= 6;
+       if (oval > 2)
+               oval = 2;
+
+       ucontrol->value.enumerated.item[0] = oval;
+       return 0;
+}
+
+static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int change;
+       unsigned char nval, oval;
+
+       if (ucontrol->value.enumerated.item[0] > 2)
+               return -EINVAL;
+       spin_lock_irqsave(&sb->mixer_lock, flags);
+       oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+
+       nval = (oval & ~(3 << 6))
+            | (ucontrol->value.enumerated.item[0] << 6);
+       change = nval != oval;
+       if (change)
+               snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
+       spin_unlock_irqrestore(&sb->mixer_lock, flags);
+       return change;
+}
+
 /*
  * SBPRO input multiplexer
  */
 
 static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[3] = {
+       static const char *texts[3] = {
                "Mic", "CD", "Line"
        };
 
@@ -442,6 +503,12 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
                        .get = snd_dt019x_input_sw_get,
                        .put = snd_dt019x_input_sw_put,
                },
+               [SB_MIX_MONO_CAPTURE_ALS4K] = {
+                       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+                       .info = snd_als4k_mono_capture_route_info,
+                       .get = snd_als4k_mono_capture_route_get,
+                       .put = snd_als4k_mono_capture_route_put,
+               },
        };
        struct snd_kcontrol *ctl;
        int err;
@@ -636,6 +703,8 @@ static struct sbmix_elem snd_dt019x_ctl_capture_source =
        };
 
 static struct sbmix_elem *snd_dt019x_controls[] = {
+       /* ALS4000 below has some parts which we might be lacking,
+        * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
        &snd_dt019x_ctl_master_play_vol,
        &snd_dt019x_ctl_pcm_play_vol,
        &snd_dt019x_ctl_synth_play_vol,
@@ -666,18 +735,21 @@ static unsigned char snd_dt019x_init_values[][2] = {
 /*
  * ALS4000 specific mixer elements
  */
-/* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl! */
 static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
        SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
-static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
-       SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
-/* FIXME: mono playback switch also available on DT019X? */
+static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = {
+               .name = "Master Mono Capture Route",
+               .type = SB_MIX_MONO_CAPTURE_ALS4K
+       };
 static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
        SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
 static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
        SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
-static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
-       SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
+static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback =
+       SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
+static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback =
+       SB_SINGLE("Digital Loopback Switch",
+                 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01);
 /* FIXME: functionality of 3D controls might be swapped, I didn't find
  * a description of how to identify what is supposed to be what */
 static struct sbmix_elem snd_als4000_3d_control_switch =
@@ -694,6 +766,9 @@ static struct sbmix_elem snd_als4000_3d_control_delay =
        SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
 static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
        SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
+static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch =
+       SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
+                 SB_ALS4000_FMDAC, 5, 0x01);
 #ifdef NOT_AVAILABLE
 static struct sbmix_elem snd_als4000_ctl_fmdac =
        SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
@@ -702,35 +777,37 @@ static struct sbmix_elem snd_als4000_ctl_qsound =
 #endif
 
 static struct sbmix_elem *snd_als4000_controls[] = {
-       &snd_sb16_ctl_master_play_vol,
-       &snd_dt019x_ctl_pcm_play_switch,
-       &snd_sb16_ctl_pcm_play_vol,
-       &snd_sb16_ctl_synth_capture_route,
-       &snd_dt019x_ctl_synth_play_switch,
-       &snd_sb16_ctl_synth_play_vol,
-       &snd_sb16_ctl_cd_capture_route,
-       &snd_sb16_ctl_cd_play_switch,
-       &snd_sb16_ctl_cd_play_vol,
-       &snd_sb16_ctl_line_capture_route,
-       &snd_sb16_ctl_line_play_switch,
-       &snd_sb16_ctl_line_play_vol,
-       &snd_sb16_ctl_mic_capture_route,
-       &snd_als4000_ctl_mic_20db_boost,
-       &snd_sb16_ctl_auto_mic_gain,
-       &snd_sb16_ctl_mic_play_switch,
-       &snd_sb16_ctl_mic_play_vol,
-       &snd_sb16_ctl_pc_speaker_vol,
-       &snd_sb16_ctl_capture_vol,
-       &snd_sb16_ctl_play_vol,
-       &snd_als4000_ctl_master_mono_playback_switch,
-       &snd_als4000_ctl_master_mono_capture_route,
-       &snd_als4000_ctl_mono_playback_switch,
-       &snd_als4000_ctl_mixer_loopback,
-       &snd_als4000_3d_control_switch,
-       &snd_als4000_3d_control_ratio,
-       &snd_als4000_3d_control_freq,
-       &snd_als4000_3d_control_delay,
-       &snd_als4000_3d_control_poweroff_switch,
+                                               /* ALS4000a.PDF regs page */
+       &snd_sb16_ctl_master_play_vol,          /* MX30/31 12 */
+       &snd_dt019x_ctl_pcm_play_switch,        /* MX4C    16 */
+       &snd_sb16_ctl_pcm_play_vol,             /* MX32/33 12 */
+       &snd_sb16_ctl_synth_capture_route,      /* MX3D/3E 14 */
+       &snd_dt019x_ctl_synth_play_switch,      /* MX4C    16 */
+       &snd_sb16_ctl_synth_play_vol,           /* MX34/35 12/13 */
+       &snd_sb16_ctl_cd_capture_route,         /* MX3D/3E 14 */
+       &snd_sb16_ctl_cd_play_switch,           /* MX3C    14 */
+       &snd_sb16_ctl_cd_play_vol,              /* MX36/37 13 */
+       &snd_sb16_ctl_line_capture_route,       /* MX3D/3E 14 */
+       &snd_sb16_ctl_line_play_switch,         /* MX3C    14 */
+       &snd_sb16_ctl_line_play_vol,            /* MX38/39 13 */
+       &snd_sb16_ctl_mic_capture_route,        /* MX3D/3E 14 */
+       &snd_als4000_ctl_mic_20db_boost,        /* MX4D    16 */
+       &snd_sb16_ctl_mic_play_switch,          /* MX3C    14 */
+       &snd_sb16_ctl_mic_play_vol,             /* MX3A    13 */
+       &snd_sb16_ctl_pc_speaker_vol,           /* MX3B    14 */
+       &snd_sb16_ctl_capture_vol,              /* MX3F/40 15 */
+       &snd_sb16_ctl_play_vol,                 /* MX41/42 15 */
+       &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */
+       &snd_als4k_ctl_master_mono_capture_route, /* MX4B  16 */
+       &snd_als4000_ctl_mono_playback_switch,  /* MX4C    16 */
+       &snd_als4000_ctl_mixer_analog_loopback, /* MX4D    16 */
+       &snd_als4000_ctl_mixer_digital_loopback, /* CR3    21 */
+       &snd_als4000_3d_control_switch,          /* MX50   17 */
+       &snd_als4000_3d_control_ratio,           /* MX50   17 */
+       &snd_als4000_3d_control_freq,            /* MX50   17 */
+       &snd_als4000_3d_control_delay,           /* MX51   18 */
+       &snd_als4000_3d_control_poweroff_switch,        /* MX51    18 */
+       &snd_als4000_ctl_3db_freq_control_switch,       /* MX4F    17 */
 #ifdef NOT_AVAILABLE
        &snd_als4000_ctl_fmdac,
        &snd_als4000_ctl_qsound,
@@ -905,13 +982,14 @@ static unsigned char dt019x_saved_regs[] = {
 };
 
 static unsigned char als4000_saved_regs[] = {
+       /* please verify in dsheet whether regs to be added
+          are actually real H/W or just dummy */
        SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
        SB_DSP4_OUTPUT_SW,
        SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
        SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
        SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
        SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
-       SB_DSP4_MIC_AGC,
        SB_DSP4_MIC_DEV,
        SB_DSP4_SPEAKER_DEV,
        SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
@@ -919,8 +997,10 @@ static unsigned char als4000_saved_regs[] = {
        SB_DT019X_OUTPUT_SW2,
        SB_ALS4000_MONO_IO_CTRL,
        SB_ALS4000_MIC_IN_GAIN,
+       SB_ALS4000_FMDAC,
        SB_ALS4000_3D_SND_FX,
        SB_ALS4000_3D_TIME_DELAY,
+       SB_ALS4000_CR3_CONFIGURATION,
 };
 
 static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
index ca35924dc3b3d05efa49db7051048c5d7b0d4e36..782010608ef425e51f26e56d4a41335d6459dd9e 100644 (file)
@@ -489,9 +489,9 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
        char __iomem *vmss_port;
 
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if (xirq == SNDRV_AUTO_IRQ) {
                xirq = snd_legacy_find_free_irq(possible_irqs);
@@ -576,10 +576,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
                snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
                           0x388, 0x388 + 2);
        } else {
-               err = snd_opl3_timer_new(opl3, 0, 1);
-               if (err < 0)
-                       goto err_unmap2;
-
                err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
                if (err < 0)
                        goto err_unmap2;
index 2c7503bf12714ade916d128576e7a2edc6c8300e..6fe27b9d944035a9ab0ec82d54500ec60401f02c 100644 (file)
@@ -243,9 +243,9 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
        struct snd_card *card;
        struct snd_wss *chip;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        xirq = irq[dev];
        if (xirq == SNDRV_AUTO_IRQ) {
index 48a16d865834b023704eea64b0c27d062bc6dc94..66187122377c544cbc2059a9e8c0ecd9fa5a594a 100644 (file)
@@ -89,9 +89,6 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
 #endif
 
 
-#define MPU401_IO(i)     ((i) + 0)
-#define MIDI_DATA_IO(i)  ((i) + 0)
-#define MIDI_CTRL_IO(i)  ((i) + 1)
 #define HOST_CTRL_IO(i)  ((i) + 2)
 #define HOST_DATA_IO(i)  ((i) + 3)
 #define ODIE_ADDR_IO(i)  ((i) + 4)
@@ -129,9 +126,6 @@ enum GA_REG {
 #define DMA_8BIT  0x80
 
 
-#define AD1845_FREQ_SEL_MSB    0x16
-#define AD1845_FREQ_SEL_LSB    0x17
-
 enum card_type {
        SSCAPE,
        SSCAPE_PNP,
@@ -141,8 +135,6 @@ enum card_type {
 struct soundscape {
        spinlock_t lock;
        unsigned io_base;
-       unsigned wss_base;
-       int codec_type;
        int ic_type;
        enum card_type type;
        struct resource *io_res;
@@ -330,7 +322,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
  */
 static inline int verify_mpu401(const struct snd_mpu401 * mpu)
 {
-       return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80);
+       return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
 }
 
 /*
@@ -338,7 +330,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu)
  */
 static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
 {
-       outb(0, MIDI_DATA_IO(mpu->port));
+       outb(0, MPU401D(mpu));
 }
 
 /*
@@ -396,20 +388,20 @@ static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned ti
  */
 static int obp_startup_ack(struct soundscape *s, unsigned timeout)
 {
-       while (timeout != 0) {
+       unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+
+       do {
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_uninterruptible(1);
-
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
                spin_unlock_irqrestore(&s->lock, flags);
                if ((x & 0xfe) == 0xfe)
                        return 1;
 
-               --timeout;
-       } /* while */
+               msleep(10);
+       } while (time_before(jiffies, end_time));
 
        return 0;
 }
@@ -423,20 +415,20 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
  */
 static int host_startup_ack(struct soundscape *s, unsigned timeout)
 {
-       while (timeout != 0) {
+       unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+
+       do {
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_uninterruptible(1);
-
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
                spin_unlock_irqrestore(&s->lock, flags);
                if (x == 0xfe)
                        return 1;
 
-               --timeout;
-       } /* while */
+               msleep(10);
+       } while (time_before(jiffies, end_time));
 
        return 0;
 }
@@ -532,10 +524,10 @@ static int upload_dma_data(struct soundscape *s,
         * give it 5 seconds (max) ...
         */
        ret = 0;
-       if (!obp_startup_ack(s, 5)) {
+       if (!obp_startup_ack(s, 5000)) {
                snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
                ret = -EAGAIN;
-       } else if (!host_startup_ack(s, 5)) {
+       } else if (!host_startup_ack(s, 5000)) {
                snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
                ret = -EAGAIN;
        }
@@ -732,13 +724,7 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
-       set_host_mode_unsafe(s->io_base);
-
-       if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) {
-               uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100);
-       }
-
-       set_midi_mode_unsafe(s->io_base);
+       uctl->value.integer.value[0] = s->midi_vol;
        spin_unlock_irqrestore(&s->lock, flags);
        return 0;
 }
@@ -773,6 +759,7 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
        change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
                  && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
                  && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
+       s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
       __skip_change:
 
        /*
@@ -815,12 +802,11 @@ static unsigned __devinit get_irq_config(int irq)
  * Perform certain arcane port-checks to see whether there
  * is a SoundScape board lurking behind the given ports.
  */
-static int __devinit detect_sscape(struct soundscape *s)
+static int __devinit detect_sscape(struct soundscape *s, long wss_io)
 {
        unsigned long flags;
        unsigned d;
        int retval = 0;
-       int codec = s->wss_base;
 
        spin_lock_irqsave(&s->lock, flags);
 
@@ -836,13 +822,11 @@ static int __devinit detect_sscape(struct soundscape *s)
        if ((d & 0x80) != 0)
                goto _done;
 
-       if (d == 0) {
-               s->codec_type = 1;
+       if (d == 0)
                s->ic_type = IC_ODIE;
-       } else if ((d & 0x60) != 0) {
-               s->codec_type = 2;
+       else if ((d & 0x60) != 0)
                s->ic_type = IC_OPUS;
-       else
+       else
                goto _done;
 
        outb(0xfa, ODIE_ADDR_IO(s->io_base));
@@ -862,10 +846,10 @@ static int __devinit detect_sscape(struct soundscape *s)
        sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
 
        if (s->type == SSCAPE_VIVO)
-               codec += 4;
+               wss_io += 4;
        /* wait for WSS codec */
        for (d = 0; d < 500; d++) {
-               if ((inb(codec) & 0x80) == 0)
+               if ((inb(wss_io) & 0x80) == 0)
                        break;
                spin_unlock_irqrestore(&s->lock, flags);
                msleep(1);
@@ -954,82 +938,6 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
 }
 
 
-/*
- * Override for the CS4231 playback format function.
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_playback_format(struct snd_wss *chip,
-                                  struct snd_pcm_hw_params *params,
-                                  unsigned char format)
-{
-       unsigned long flags;
-       unsigned rate = params_rate(params);
-
-       /*
-        * The AD1845 can't handle sample frequencies
-        * outside of 4 kHZ to 50 kHZ
-        */
-       if (rate > 50000)
-               rate = 50000;
-       else if (rate < 4000)
-               rate = 4000;
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-
-       /*
-        * Program the AD1845 correctly for the playback stream.
-        * Note that we do NOT need to toggle the MCE bit because
-        * the PLAYBACK_ENABLE bit of the Interface Configuration
-        * register is set.
-        * 
-        * NOTE: We seem to need to write to the MSB before the LSB
-        *       to get the correct sample frequency.
-        */
-       snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
-       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/*
- * Override for the CS4231 capture format function. 
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_capture_format(struct snd_wss *chip,
-                                 struct snd_pcm_hw_params *params,
-                                 unsigned char format)
-{
-       unsigned long flags;
-       unsigned rate = params_rate(params);
-
-       /*
-        * The AD1845 can't handle sample frequencies 
-        * outside of 4 kHZ to 50 kHZ
-        */
-       if (rate > 50000)
-               rate = 50000;
-       else if (rate < 4000)
-               rate = 4000;
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-
-       /*
-        * Program the AD1845 correctly for the playback stream.
-        * Note that we do NOT need to toggle the MCE bit because
-        * the CAPTURE_ENABLE bit of the Interface Configuration
-        * register is set.
-        *
-        * NOTE: We seem to need to write to the MSB before the LSB
-        *       to get the correct sample frequency.
-        */
-       snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
-       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
 /*
  * Create an AD1845 PCM subdevice on the SoundScape. The AD1845
  * is very much like a CS4231, with a few extra bits. We will
@@ -1055,11 +963,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                unsigned long flags;
                struct snd_pcm *pcm;
 
-#define AD1845_FREQ_SEL_ENABLE  0x08
-
-#define AD1845_PWR_DOWN_CTRL   0x1b
-#define AD1845_CRYS_CLOCK_SEL  0x1d
-
 /*
  * It turns out that the PLAYBACK_ENABLE bit is set
  * by the lowlevel driver ...
@@ -1074,7 +977,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
  */
 
                if (sscape->type != SSCAPE_VIVO) {
-                       int val;
                        /*
                         * The input clock frequency on the SoundScape must
                         * be 14.31818 MHz, because we must set this register
@@ -1082,22 +984,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                         */
                        snd_wss_mce_up(chip);
                        spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
+                       snd_wss_out(chip, AD1845_CLOCK, 0x20);
                        spin_unlock_irqrestore(&chip->reg_lock, flags);
                        snd_wss_mce_down(chip);
 
-                       /*
-                        * More custom configuration:
-                        * a) select "mode 2" and provide a current drive of 8mA
-                        * b) enable frequency selection (for capture/playback)
-                        */
-                       spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_wss_out(chip, CS4231_MISC_INFO,
-                                   CS4231_MODE2 | 0x10);
-                       val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
-                       snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
-                                   val | AD1845_FREQ_SEL_ENABLE);
-                       spin_unlock_irqrestore(&chip->reg_lock, flags);
                }
 
                err = snd_wss_pcm(chip, 0, &pcm);
@@ -1113,11 +1003,13 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                                            "for AD1845 chip\n");
                        goto _error;
                }
-               err = snd_wss_timer(chip, 0, NULL);
-               if (err < 0) {
-                       snd_printk(KERN_ERR "sscape: No timer device "
-                                           "for AD1845 chip\n");
-                       goto _error;
+               if (chip->hardware != WSS_HW_AD1848) {
+                       err = snd_wss_timer(chip, 0, NULL);
+                       if (err < 0) {
+                               snd_printk(KERN_ERR "sscape: No timer device "
+                                                   "for AD1845 chip\n");
+                               goto _error;
+                       }
                }
 
                if (sscape->type != SSCAPE_VIVO) {
@@ -1128,8 +1020,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
                                                    "MIDI mixer control\n");
                                goto _error;
                        }
-                       chip->set_playback_format = ad1845_playback_format;
-                       chip->set_capture_format = ad1845_capture_format;
                }
 
                strcpy(card->driver, "SoundScape");
@@ -1157,7 +1047,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        unsigned dma_cfg;
        unsigned irq_cfg;
        unsigned mpu_irq_cfg;
-       unsigned xport;
        struct resource *io_res;
        struct resource *wss_res;
        unsigned long flags;
@@ -1177,15 +1066,15 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
                printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
                return -ENXIO;
        }
-       xport = port[dev];
 
        /*
         * Grab IO ports that we will need to probe so that we
         * can detect and control this hardware ...
         */
-       io_res = request_region(xport, 8, "SoundScape");
+       io_res = request_region(port[dev], 8, "SoundScape");
        if (!io_res) {
-               snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
+               snd_printk(KERN_ERR
+                          "sscape: can't grab port 0x%lx\n", port[dev]);
                return -EBUSY;
        }
        wss_res = NULL;
@@ -1212,10 +1101,9 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        spin_lock_init(&sscape->fwlock);
        sscape->io_res = io_res;
        sscape->wss_res = wss_res;
-       sscape->io_base = xport;
-       sscape->wss_base = wss_port[dev];
+       sscape->io_base = port[dev];
 
-       if (!detect_sscape(sscape)) {
+       if (!detect_sscape(sscape, wss_port[dev])) {
                printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
                err = -ENODEV;
                goto _release_dma;
@@ -1288,12 +1176,11 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
        }
 #define MIDI_DEVNUM  0
        if (sscape->type != SSCAPE_VIVO) {
-               err = create_mpu401(card, MIDI_DEVNUM,
-                                   MPU401_IO(xport), mpu_irq[dev]);
+               err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
                if (err < 0) {
                        printk(KERN_ERR "sscape: Failed to create "
-                                       "MPU-401 device at 0x%x\n",
-                                       MPU401_IO(xport));
+                                       "MPU-401 device at 0x%lx\n",
+                                       port[dev]);
                        goto _release_dma;
                }
 
@@ -1357,10 +1244,10 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
        struct soundscape *sscape;
        int ret;
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct soundscape));
-       if (!card)
-               return -ENOMEM;
+       ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct soundscape), &card);
+       if (ret < 0)
+               return ret;
 
        sscape = get_card_soundscape(card);
        sscape->type = SSCAPE;
@@ -1462,10 +1349,10 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
         * Create a new ALSA sound card entry, in anticipation
         * of detecting our hardware ...
         */
-       card = snd_card_new(index[idx], id[idx], THIS_MODULE,
-                           sizeof(struct soundscape));
-       if (!card)
-               return -ENOMEM;
+       ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
+                             sizeof(struct soundscape), &card);
+       if (ret < 0)
+               return ret;
 
        sscape = get_card_soundscape(card);
 
index 4c095bc7c7291165c91163293b2390ce14d60f46..a34ae7b1f7d0b71c2db484bccfb2294ee6e7d578 100644 (file)
@@ -338,15 +338,16 @@ snd_wavefront_free(struct snd_card *card)
        }
 }
 
-static struct snd_card *snd_wavefront_card_new(int dev)
+static int snd_wavefront_card_new(int dev, struct snd_card **cardp)
 {
        struct snd_card *card;
        snd_wavefront_card_t *acard;
+       int err;
 
-       card = snd_card_new (index[dev], id[dev], THIS_MODULE,
-                            sizeof(snd_wavefront_card_t));
-       if (card == NULL)
-               return NULL;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(snd_wavefront_card_t), &card);
+       if (err < 0)
+               return err;
 
        acard = card->private_data;
        acard->wavefront.irq = -1;
@@ -357,7 +358,8 @@ static struct snd_card *snd_wavefront_card_new(int dev)
        acard->wavefront.card = card;
        card->private_free = snd_wavefront_free;
 
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit
@@ -551,11 +553,11 @@ static int __devinit snd_wavefront_isa_match(struct device *pdev,
                return 0;
 #endif
        if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
-               snd_printk("specify CS4232 port\n");
+               snd_printk(KERN_ERR "specify CS4232 port\n");
                return 0;
        }
        if (ics2115_port[dev] == SNDRV_AUTO_PORT) {
-               snd_printk("specify ICS2115 port\n");
+               snd_printk(KERN_ERR "specify ICS2115 port\n");
                return 0;
        }
        return 1;
@@ -567,9 +569,9 @@ static int __devinit snd_wavefront_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       card = snd_wavefront_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       err = snd_wavefront_card_new(dev, &card);
+       if (err < 0)
+               return err;
        snd_card_set_dev(card, pdev);
        if ((err = snd_wavefront_probe(card, dev)) < 0) {
                snd_card_free(card);
@@ -616,9 +618,9 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       card = snd_wavefront_card_new(dev);
-       if (! card)
-               return -ENOMEM;
+       res = snd_wavefront_card_new(dev, &card);
+       if (res < 0)
+               return res;
 
        if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) {
                if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
index 4c410820a994affcdc5f3ed448b8ad4e96343e06..beb312cca75b7bbea9598073eb2128010a346fe2 100644 (file)
@@ -633,7 +633,7 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
                wbuf[1] = i >> 7;
 
                if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
-                       snd_printk("cannot identify sample "
+                       snd_printk(KERN_WARNING "cannot identify sample "
                                   "type of slot %d\n", i);
                        dev->sample_status[i] = WF_ST_EMPTY;
                        continue;
index 3d6c5f2838af41156d7cd8d07f480e58f7dd6e04..5d2ba1b749abef59839210b177944cd3c9a8a24c 100644 (file)
@@ -181,25 +181,6 @@ static void snd_wss_wait(struct snd_wss *chip)
                udelay(100);
 }
 
-static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
-                           unsigned char mask, unsigned char value)
-{
-       unsigned char tmp = (chip->image[reg] & mask) | value;
-
-       snd_wss_wait(chip);
-#ifdef CONFIG_SND_DEBUG
-       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
-       chip->image[reg] = tmp;
-       if (!chip->calibrate_mute) {
-               wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-               wmb();
-               wss_outb(chip, CS4231P(REG), tmp);
-               mb();
-       }
-}
-
 static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
                         unsigned char value)
 {
@@ -219,7 +200,8 @@ void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
        snd_wss_wait(chip);
 #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+               snd_printk(KERN_DEBUG "out: auto calibration time out "
+                          "- reg = 0x%x, value = 0x%x\n", reg, value);
 #endif
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
        wss_outb(chip, CS4231P(REG), value);
@@ -235,7 +217,8 @@ unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
        snd_wss_wait(chip);
 #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+               snd_printk(KERN_DEBUG "in: auto calibration time out "
+                          "- reg = 0x%x\n", reg);
 #endif
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
        mb();
@@ -252,7 +235,7 @@ void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
        wss_outb(chip, CS4231P(REG), val);
        chip->eimage[CS4236_REG(reg)] = val;
 #if 0
-       printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+       printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
 #endif
 }
 EXPORT_SYMBOL(snd_cs4236_ext_out);
@@ -268,7 +251,8 @@ unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
        {
                unsigned char res;
                res = wss_inb(chip, CS4231P(REG));
-               printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
+               printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
+                      reg, res);
                return res;
        }
 #endif
@@ -394,13 +378,16 @@ void snd_wss_mce_up(struct snd_wss *chip)
        snd_wss_wait(chip);
 #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("mce_up - auto calibration time out (0)\n");
+               snd_printk(KERN_DEBUG
+                          "mce_up - auto calibration time out (0)\n");
 #endif
        spin_lock_irqsave(&chip->reg_lock, flags);
        chip->mce_bit |= CS4231_MCE;
        timeout = wss_inb(chip, CS4231P(REGSEL));
        if (timeout == 0x80)
-               snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+               snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
+                          "serious init problem - codec still busy\n",
+                          chip->port);
        if (!(timeout & CS4231_MCE))
                wss_outb(chip, CS4231P(REGSEL),
                         chip->mce_bit | (timeout & 0x1f));
@@ -419,7 +406,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
 
 #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
+               snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
+                          "auto calibration time out (0)\n",
+                          (long)CS4231P(REGSEL));
 #endif
        spin_lock_irqsave(&chip->reg_lock, flags);
        chip->mce_bit &= ~CS4231_MCE;
@@ -427,7 +416,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        if (timeout == 0x80)
-               snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+               snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
+                          "serious init problem - codec still busy\n",
+                          chip->port);
        if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
                return;
 
@@ -565,7 +556,7 @@ static unsigned char snd_wss_get_format(struct snd_wss *chip,
        if (channels > 1)
                rformat |= CS4231_STEREO;
 #if 0
-       snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+       snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
 #endif
        return rformat;
 }
@@ -587,7 +578,15 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
                             chip->image[CS4231_RIGHT_INPUT]);
                snd_wss_dout(chip, CS4231_LOOPBACK,
                             chip->image[CS4231_LOOPBACK]);
+       } else {
+               snd_wss_dout(chip, CS4231_LEFT_INPUT,
+                            0);
+               snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+                            0);
+               snd_wss_dout(chip, CS4231_LOOPBACK,
+                            0xfd);
        }
+
        snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
                     mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
        snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
@@ -630,7 +629,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
        int full_calib = 1;
 
        mutex_lock(&chip->mce_mutex);
-       snd_wss_calibrate_mute(chip, 1);
        if (chip->hardware == WSS_HW_CS4231A ||
            (chip->hardware & WSS_HW_CS4232_MASK)) {
                spin_lock_irqsave(&chip->reg_lock, flags);
@@ -646,6 +644,24 @@ static void snd_wss_playback_format(struct snd_wss *chip,
                        full_calib = 0;
                }
                spin_unlock_irqrestore(&chip->reg_lock, flags);
+       } else if (chip->hardware == WSS_HW_AD1845) {
+               unsigned rate = params_rate(params);
+
+               /*
+                * Program the AD1845 correctly for the playback stream.
+                * Note that we do NOT need to toggle the MCE bit because
+                * the PLAYBACK_ENABLE bit of the Interface Configuration
+                * register is set.
+                *
+                * NOTE: We seem to need to write to the MSB before the LSB
+                *       to get the correct sample frequency.
+                */
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
+               snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+               snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+               full_calib = 0;
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
        }
        if (full_calib) {
                snd_wss_mce_up(chip);
@@ -663,7 +679,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
                        udelay(100);    /* this seems to help */
                snd_wss_mce_down(chip);
        }
-       snd_wss_calibrate_mute(chip, 0);
        mutex_unlock(&chip->mce_mutex);
 }
 
@@ -675,7 +690,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
        int full_calib = 1;
 
        mutex_lock(&chip->mce_mutex);
-       snd_wss_calibrate_mute(chip, 1);
        if (chip->hardware == WSS_HW_CS4231A ||
            (chip->hardware & WSS_HW_CS4232_MASK)) {
                spin_lock_irqsave(&chip->reg_lock, flags);
@@ -690,6 +704,24 @@ static void snd_wss_capture_format(struct snd_wss *chip,
                        full_calib = 0;
                }
                spin_unlock_irqrestore(&chip->reg_lock, flags);
+       } else if (chip->hardware == WSS_HW_AD1845) {
+               unsigned rate = params_rate(params);
+
+               /*
+                * Program the AD1845 correctly for the capture stream.
+                * Note that we do NOT need to toggle the MCE bit because
+                * the PLAYBACK_ENABLE bit of the Interface Configuration
+                * register is set.
+                *
+                * NOTE: We seem to need to write to the MSB before the LSB
+                *       to get the correct sample frequency.
+                */
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
+               snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+               snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+               full_calib = 0;
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
        }
        if (full_calib) {
                snd_wss_mce_up(chip);
@@ -714,7 +746,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
                spin_unlock_irqrestore(&chip->reg_lock, flags);
                snd_wss_mce_down(chip);
        }
-       snd_wss_calibrate_mute(chip, 0);
        mutex_unlock(&chip->mce_mutex);
 }
 
@@ -771,10 +802,11 @@ static void snd_wss_init(struct snd_wss *chip)
 {
        unsigned long flags;
 
+       snd_wss_calibrate_mute(chip, 1);
        snd_wss_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (1)\n");
+       snd_printk(KERN_DEBUG "init: (1)\n");
 #endif
        snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -789,18 +821,20 @@ static void snd_wss_init(struct snd_wss *chip)
        snd_wss_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (2)\n");
+       snd_printk(KERN_DEBUG "init: (2)\n");
 #endif
 
        snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
+       snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
        snd_wss_out(chip,
                    CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_wss_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (3) - afei = 0x%x\n",
+       snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
                   chip->image[CS4231_ALT_FEATURE_1]);
 #endif
 
@@ -817,7 +851,7 @@ static void snd_wss_init(struct snd_wss *chip)
        snd_wss_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (4)\n");
+       snd_printk(KERN_DEBUG "init: (4)\n");
 #endif
 
        snd_wss_mce_up(chip);
@@ -827,9 +861,10 @@ static void snd_wss_init(struct snd_wss *chip)
                            chip->image[CS4231_REC_FORMAT]);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_wss_mce_down(chip);
+       snd_wss_calibrate_mute(chip, 0);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (5)\n");
+       snd_printk(KERN_DEBUG "init: (5)\n");
 #endif
 }
 
@@ -885,8 +920,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
                mutex_unlock(&chip->open_mutex);
                return;
        }
-       snd_wss_calibrate_mute(chip, 1);
-
        /* disable IRQ */
        spin_lock_irqsave(&chip->reg_lock, flags);
        if (!(chip->hardware & WSS_HW_AD1848_MASK))
@@ -919,8 +952,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
        wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 
-       snd_wss_calibrate_mute(chip, 0);
-
        chip->mode = 0;
        mutex_unlock(&chip->open_mutex);
 }
@@ -1113,7 +1144,7 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
        if (chip->hardware & WSS_HW_AD1848_MASK)
                wss_outb(chip, CS4231P(STATUS), 0);
        else
-               snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
+               snd_wss_out(chip, CS4231_IRQ_STATUS, status);
        spin_unlock(&chip->reg_lock);
        return IRQ_HANDLED;
 }
@@ -1278,7 +1309,8 @@ static int snd_wss_probe(struct snd_wss *chip)
                } else if (rev == 0x03) {
                        chip->hardware = WSS_HW_CS4236B;
                } else {
-                       snd_printk("unknown CS chip with version 0x%x\n", rev);
+                       snd_printk(KERN_ERR
+                                  "unknown CS chip with version 0x%x\n", rev);
                        return -ENODEV;         /* unknown CS4231 chip? */
                }
        }
@@ -1314,6 +1346,10 @@ static int snd_wss_probe(struct snd_wss *chip)
                chip->image[CS4231_ALT_FEATURE_2] =
                        chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
        }
+       /* enable fine grained frequency selection */
+       if (chip->hardware == WSS_HW_AD1845)
+               chip->image[AD1845_PWR_DOWN] = 8;
+
        ptr = (unsigned char *) &chip->image;
        regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
        snd_wss_mce_down(chip);
@@ -1342,7 +1378,10 @@ static int snd_wss_probe(struct snd_wss *chip)
                                case 6:
                                        break;
                                default:
-                                       snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
+                                       snd_printk(KERN_WARNING
+                                               "unknown CS4235 chip "
+                                               "(enhanced version = 0x%x)\n",
+                                               id);
                                }
                        } else if ((id & 0x1f) == 0x0b) {       /* CS4236/B */
                                switch (id >> 5) {
@@ -1353,7 +1392,10 @@ static int snd_wss_probe(struct snd_wss *chip)
                                        chip->hardware = WSS_HW_CS4236B;
                                        break;
                                default:
-                                       snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
+                                       snd_printk(KERN_WARNING
+                                               "unknown CS4236 chip "
+                                               "(enhanced version = 0x%x)\n",
+                                               id);
                                }
                        } else if ((id & 0x1f) == 0x08) {       /* CS4237B */
                                chip->hardware = WSS_HW_CS4237B;
@@ -1364,7 +1406,10 @@ static int snd_wss_probe(struct snd_wss *chip)
                                case 7:
                                        break;
                                default:
-                                       snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
+                                       snd_printk(KERN_WARNING
+                                               "unknown CS4237B chip "
+                                               "(enhanced version = 0x%x)\n",
+                                               id);
                                }
                        } else if ((id & 0x1f) == 0x09) {       /* CS4238B */
                                chip->hardware = WSS_HW_CS4238B;
@@ -1374,7 +1419,10 @@ static int snd_wss_probe(struct snd_wss *chip)
                                case 7:
                                        break;
                                default:
-                                       snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
+                                       snd_printk(KERN_WARNING
+                                               "unknown CS4238B chip "
+                                               "(enhanced version = 0x%x)\n",
+                                               id);
                                }
                        } else if ((id & 0x1f) == 0x1e) {       /* CS4239 */
                                chip->hardware = WSS_HW_CS4239;
@@ -1384,10 +1432,15 @@ static int snd_wss_probe(struct snd_wss *chip)
                                case 6:
                                        break;
                                default:
-                                       snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
+                                       snd_printk(KERN_WARNING
+                                               "unknown CS4239 chip "
+                                               "(enhanced version = 0x%x)\n",
+                                               id);
                                }
                        } else {
-                               snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
+                               snd_printk(KERN_WARNING
+                                          "unknown CS4236/CS423xB chip "
+                                          "(enhanced version = 0x%x)\n", id);
                        }
                }
        }
@@ -1618,7 +1671,8 @@ static void snd_wss_resume(struct snd_wss *chip)
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        if (timeout == 0x80)
-               snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+               snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
+                          "- codec still busy\n", chip->port);
        if ((timeout & CS4231_MCE) == 0 ||
            !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
                return;
@@ -1628,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
 }
 #endif /* CONFIG_PM */
 
-static int snd_wss_free(struct snd_wss *chip)
+int snd_wss_free(struct snd_wss *chip)
 {
        release_and_free_resource(chip->res_port);
        release_and_free_resource(chip->res_cport);
@@ -1651,6 +1705,7 @@ static int snd_wss_free(struct snd_wss *chip)
        kfree(chip);
        return 0;
 }
+EXPORT_SYMBOL(snd_wss_free);
 
 static int snd_wss_dev_free(struct snd_device *device)
 {
@@ -1820,7 +1875,8 @@ int snd_wss_create(struct snd_card *card,
 #if 0
        if (chip->hardware & WSS_HW_CS4232_MASK) {
                if (chip->res_cport == NULL)
-                       snd_printk("CS4232 control port features are not accessible\n");
+                       snd_printk(KERN_ERR "CS4232 control port features are "
+                                  "not accessible\n");
        }
 #endif
 
index 1881cec11e78d221b55f4132219ec48c0cc9c147..3e763d6a5d67802d6f736e4df0dccfd88eff2224 100644 (file)
@@ -636,9 +636,10 @@ au1000_init(void)
        struct snd_card *card;
        struct snd_au1000 *au1000;
 
-       card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(struct snd_au1000));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(-1, "AC97", THIS_MODULE,
+                             sizeof(struct snd_au1000), &card);
+       if (err < 0)
+               return err;
 
        card->private_free = snd_au1000_free;
        au1000 = card->private_data;
@@ -678,7 +679,7 @@ au1000_init(void)
                return err;
        }
 
-       printk( KERN_INFO "ALSA AC97: Driver Initialized\n" );
+       printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
        au1000_card = card;
        return 0;
 }
index db495be01861ffee559d34221ff82a8624214502..c52691c2fc46df746aee9136545f1c4ed6aa1447 100644 (file)
@@ -878,9 +878,9 @@ static int __devinit hal2_probe(struct platform_device *pdev)
        struct snd_hal2 *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = hal2_create(card, &chip);
        if (err < 0) {
index 4c63504348dc4ba155cfd8ab79a4e03347db8d84..66f3b48ceafcdcbedb7e4700a4ae8a341283cd3f 100644 (file)
@@ -936,9 +936,9 @@ static int __devinit snd_sgio2audio_probe(struct platform_device *pdev)
        struct snd_sgio2audio *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_sgio2audio_create(card, &chip);
        if (err < 0) {
index 7cf9913a47b26ca4e3adb02a25e2538542913463..d12bd98a37ba6f207190df984ae113be1e5e8dcd 100644 (file)
@@ -280,7 +280,7 @@ static void wait_for_calibration(ad1848_info * devc)
        while (timeout > 0 && (ad_read(devc, 11) & 0x20))
                timeout--;
        if (ad_read(devc, 11) & 0x20)
-               if ( (devc->model != MD_1845) || (devc->model != MD_1845_SSCAPE))
+               if ((devc->model != MD_1845) && (devc->model != MD_1845_SSCAPE))
                        printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n");
 }
 
@@ -2107,7 +2107,7 @@ int ad1848_control(int cmd, int arg)
        switch (cmd)
        {
                case AD1848_SET_XTAL:   /* Change clock frequency of AD1845 (only ) */
-                       if (devc->model != MD_1845 || devc->model != MD_1845_SSCAPE)
+                       if (devc->model != MD_1845 && devc->model != MD_1845_SSCAPE)
                                return -EINVAL;
                        spin_lock_irqsave(&devc->lock,flags);
                        ad_enter_MCE(devc);
index 1e90d769b62e3ef63181f809a5ccd36e819d126b..1bfcf7e8854632a7b395f9143b9fb3c3d0408545 100644 (file)
@@ -439,7 +439,7 @@ int DMAbuf_sync(int dev)
                        DMAbuf_launch_output(dev, dmap);
                adev->dmap_out->flags |= DMA_SYNCING;
                adev->dmap_out->underrun_count = 0;
-               while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && 
+               while (!signal_pending(current) && n++ < adev->dmap_out->nbufs &&
                       adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
                        long t = dmabuf_timeout(dmap);
                        spin_unlock_irqrestore(&dmap->lock,flags);
index 25f3a22c52ee0891fbc5ceeee6ea47a12fc5ee14..7f377ec3486d9f822c14fe2c77fb35d85f49cfd2 100644 (file)
@@ -156,9 +156,7 @@ static int __init config_pas_hw(struct address_info *hw_config)
                                                 * 0x80
                                                 */ , 0xB88);
 
-       pas_write(0x80
-                 | joystick?0x40:0
-                 ,0xF388);
+       pas_write(0x80 | (joystick ? 0x40 : 0), 0xF388);
 
        if (pas_irq < 0 || pas_irq > 15)
        {
index 16ed06950dc1b5c363d4740009b0d1bc5fa3c194..16517a5a1301fb7badfbfae17af36dfab4b46787 100644 (file)
@@ -457,10 +457,9 @@ static void pss_mixer_reset(pss_confdata *devc)
        }
 }
 
-static int set_volume_mono(unsigned __user *p, int *aleft)
+static int set_volume_mono(unsigned __user *p, unsigned int *aleft)
 {
-       int left;
-       unsigned volume;
+       unsigned int left, volume;
        if (get_user(volume, p))
                return -EFAULT;
        
@@ -471,10 +470,11 @@ static int set_volume_mono(unsigned __user *p, int *aleft)
        return 0;
 }
 
-static int set_volume_stereo(unsigned __user *p, int *aleft, int *aright)
+static int set_volume_stereo(unsigned __user *p,
+                            unsigned int *aleft,
+                            unsigned int *aright)
 {
-       int left, right;
-       unsigned volume;
+       unsigned int left, right, volume;
        if (get_user(volume, p))
                return -EFAULT;
 
index 5c215f787ca9340e5cb2ad33da47c9658bb2dfcc..c79874696becfdf81c4f42793ff44eee35bd103e 100644 (file)
@@ -212,7 +212,6 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
 {
        unsigned char event_rec[EV_SZ], ev_code;
        int p = 0, c, ev_size;
-       int err;
        int mode = translate_mode(file);
 
        dev = dev >> 4;
@@ -285,7 +284,7 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
                {
                        if (!midi_opened[event_rec[2]])
                        {
-                               int mode;
+                               int err, mode;
                                int dev = event_rec[2];
 
                                if (dev >= max_mididev || midi_devs[dev]==NULL)
index 41f870f8a11d21390e1caa473326d659274e28fc..6055fd6d3b38ee90ba6d19895363ef33db38f275 100644 (file)
@@ -975,9 +975,9 @@ snd_harmony_probe(struct parisc_device *padev)
        struct snd_card *card;
        struct snd_harmony *h;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_harmony_create(card, padev, &h);
        if (err < 0)
index 82b9bddcdcd68efe994fc8c38ed54336c4fb2efc..ca25e6179d7671b0b5c3d7a9a3922088606e1ec1 100644 (file)
@@ -400,6 +400,26 @@ config SND_INDIGODJ
          To compile this driver as a module, choose M here: the module
          will be called snd-indigodj
 
+config SND_INDIGOIOX
+       tristate "(Echoaudio) Indigo IOx"
+       select FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Indigo IOx.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-indigoiox
+
+config SND_INDIGODJX
+       tristate "(Echoaudio) Indigo DJx"
+       select FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Indigo DJx.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-indigodjx
+
 config SND_EMU10K1
        tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
        select FW_LOADER
@@ -744,7 +764,8 @@ config SND_VIRTUOSO
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for sound cards based on the
-         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
+         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
+         Essence STX.
          Support for the HDAV1.3 (Deluxe) is very experimental.
 
          To compile this driver as a module, choose M here: the module
index e2b843b4f9d0963c681c6fe877bddd48bdd2ee7c..97ee127ac33dece8127ff4edef6e30f898ae8bb9 100644 (file)
@@ -143,6 +143,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x43525970, 0xfffffff8, "CS4202",            NULL,           NULL },
 { 0x43585421, 0xffffffff, "HSD11246",          NULL,           NULL }, // SmartMC II
 { 0x43585428, 0xfffffff8, "Cx20468",           patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
+{ 0x43585430, 0xffffffff, "Cx20468-31",                patch_conexant, NULL },
 { 0x43585431, 0xffffffff, "Cx20551",           patch_cx20551,  NULL },
 { 0x44543031, 0xfffffff0, "DT0398",            NULL,           NULL },
 { 0x454d4328, 0xffffffff, "EM28028",           NULL,           NULL },  // same as TR28028?
@@ -383,7 +384,7 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho
 
 EXPORT_SYMBOL(snd_ac97_update_bits);
 
-/* no lock version - see snd_ac97_updat_bits() */
+/* no lock version - see snd_ac97_update_bits() */
 int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short mask, unsigned short value)
 {
@@ -1643,7 +1644,10 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97)
 {
        int err, idx;
 
-       //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG));
+       /*
+       printk(KERN_DEBUG "AC97_GPIO_CFG = %x\n",
+              snd_ac97_read(ac97,AC97_GPIO_CFG));
+       */
        snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
        snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH));
        snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff);
index 060ea59d5f02f02e74c06b28c68a5c37fb0a7446..73b17d526c8bb2cce8420d6f79f4ac88aae402b6 100644 (file)
@@ -125,6 +125,8 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe
         snd_iprintf(buffer, "PCI Subsys Device: 0x%04x\n\n",
                     ac97->subsystem_device);
 
+       snd_iprintf(buffer, "Flags: %x\n", ac97->flags);
+
        if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23) {
                val = snd_ac97_read(ac97, AC97_INT_PAGING);
                snd_ac97_update_bits(ac97, AC97_INT_PAGING,
index a7f38e63303f82120ceffacb4f08daf4b75f889d..d1f242bd0ac544584ad9c7f4349261c7c7f37588 100644 (file)
@@ -995,10 +995,10 @@ snd_ad1889_probe(struct pci_dev *pci,
        }
 
        /* (2) */
-       card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0);
+       err = snd_card_create(index[devno], id[devno], THIS_MODULE, 0, &card);
        /* XXX REVISIT: we can probably allocate chip in this call */
-       if (card == NULL)
-               return -ENOMEM;
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "AD1889");
        strcpy(card->shortname, "Analog Devices AD1889");
index 0f819ddb3ebfe0906a45f2166c6a32cbb0f26a88..fd135e3d8a84ef3c96bd9c35cd41f62c78256a3f 100644 (file)
@@ -51,7 +51,8 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531)
        int idx;
        
        for (idx = 0; idx < 0x19; idx++)
-               printk("ak4531 0x%x: 0x%x\n", idx, ak4531->regs[idx]);
+               printk(KERN_DEBUG "ak4531 0x%x: 0x%x\n",
+                      idx, ak4531->regs[idx]);
 }
 
 #endif
index 1a0fd65ec2809478d71f037f310f6a3f36a1823b..4edf270a7809c3b20fa5997caf23acd42bb72968 100644 (file)
@@ -2142,7 +2142,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
 {
        int err;
 
-       snd_ali_printk("resouces allocation ...\n");
+       snd_ali_printk("resources allocation ...\n");
        err = pci_request_regions(codec->pci, "ALI 5451");
        if (err < 0)
                return err;
@@ -2154,7 +2154,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
                return -EBUSY;
        }
        codec->irq = codec->pci->irq;
-       snd_ali_printk("resouces allocated.\n");
+       snd_ali_printk("resources allocated.\n");
        return 0;
 }
 static int snd_ali_dev_free(struct snd_device *device)
@@ -2307,9 +2307,9 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
 
        snd_ali_printk("probe ...\n");
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_ali_create(card, pci, pcm_channels, spdif, &codec);
        if (err < 0)
index 8df6824b51cda258d2627d6eb30cbba1824e50b8..009b4c8225a5b976f6f2437c70c8664bfeb81daf 100644 (file)
@@ -91,7 +91,7 @@
 #define DEBUG_PLAY_REC 0
 
 #if DEBUG_CALLS
-#define snd_als300_dbgcalls(format, args...) printk(format, ##args)
+#define snd_als300_dbgcalls(format, args...) printk(KERN_DEBUG format, ##args)
 #define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
 #define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
 #else
@@ -812,10 +812,10 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
 
-       if (card == NULL)
-               return -ENOMEM;
+       if (err < 0)
+               return err;
 
        chip_type = pci_id->driver_data;
 
index ba570053d4d538c74b0c5f8b127ba41c2759acd8..542a0c65a92c52cc39fa3371020eb6dae5cb7940 100644 (file)
@@ -889,12 +889,13 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
        pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
        pci_set_master(pci);
        
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 
-                           sizeof(*acard) /* private_data: acard */);
-       if (card == NULL) {
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 
+                             sizeof(*acard) /* private_data: acard */,
+                             &card);
+       if (err < 0) {
                pci_release_regions(pci);
                pci_disable_device(pci);
-               return -ENOMEM;
+               return err;
        }
 
        acard = card->private_data;
index 226fe8237d31997c445f0337b4effca37f57bf37..9ce8548c03e459a381b1fb2c6fb6fb9706b9480b 100644 (file)
@@ -1645,9 +1645,9 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
        struct atiixp *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA");
        strcpy(card->shortname, "ATI IXP");
index 0e6e5cc1c501e36f531baf07c23d31089f4d931a..c3136cccc559e86f90f978d9bb922ae305c5d140 100644 (file)
@@ -1288,9 +1288,9 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
        struct atiixp_modem *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "ATIIXP-MODEM");
        strcpy(card->shortname, "ATI IXP Modem");
index a36d4d1fd419f098e3dabdfa598914d49d92b378..9ec122383eefbab4492fe9d180e6737f7b4f9ed0 100644 (file)
@@ -250,9 +250,9 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
        // (2)
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        // (3)
        if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
index 649849e540d3893484e61b3c6aa6c6dcb50a22e9..f4aa8ff6f5f9d7d5f33935749b6c3100f7f48463 100644 (file)
@@ -462,9 +462,10 @@ static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
 /* Reset Single A3D source. */
 static void a3dsrc_ZeroState(a3dsrc_t * a)
 {
-
-       //printk("vortex: ZeroState slice: %d, source %d\n", a->slice, a->source);
-
+       /*
+       printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n",
+              a->slice, a->source);
+       */
        a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
        a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);
        a3dsrc_SetItdDline(a, A3dItdDlineZeros);
index b070e57145143e6cb0703f338d9bf5db7dd3cffc..3906f5afe27a3a9b27c9f0bf90e36108664d4925 100644 (file)
@@ -1135,7 +1135,10 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
                        snd_pcm_sgbuf_get_addr(dma->substream, 0));
                break;
        }
-       //printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
+       /*
+       printk(KERN_DEBUG "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
+              dma->cfg0, dma->cfg1);
+       */
        hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
        hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG1 + (adbdma << 3), dma->cfg1);
 
@@ -1959,7 +1962,7 @@ vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[])
                                          ADB_CODECOUT(0 + 4));
                vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
                                          ADB_CODECOUT(1 + 4));
-               //printk("SDAC detected ");
+               /* printk(KERN_DEBUG "SDAC detected "); */
        }
 #else
        // Use plain direct output to codec.
@@ -2013,7 +2016,11 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
                                        resmap[restype] |= (1 << i);
                                else
                                        vortex->dma_adb[i].resources[restype] |= (1 << i);
-                               //printk("vortex: ResManager: type %d out %d\n", restype, i);
+                               /*
+                               printk(KERN_DEBUG
+                                      "vortex: ResManager: type %d out %d\n",
+                                      restype, i);
+                               */
                                return i;
                        }
                }
@@ -2024,7 +2031,11 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
                for (i = 0; i < qty; i++) {
                        if (resmap[restype] & (1 << i)) {
                                resmap[restype] &= ~(1 << i);
-                               //printk("vortex: ResManager: type %d in %d\n",restype, i);
+                               /*
+                               printk(KERN_DEBUG
+                                      "vortex: ResManager: type %d in %d\n",
+                                      restype, i);
+                               */
                                return i;
                        }
                }
@@ -2789,7 +2800,7 @@ vortex_translateformat(vortex_t * vortex, char bits, char nch, int encod)
 {
        int a, this_194;
 
-       if ((bits != 8) || (bits != 16))
+       if ((bits != 8) && (bits != 16))
                return -1;
 
        switch (encod) {
index 978b856f5621aafd04b39f1d51880af44dce1a90..2805e34bd41d715a44c3ba645165a71295260095 100644 (file)
@@ -213,38 +213,59 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
        switch (reg) {
                /* Voice specific parameters */
        case 0:         /* running */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_RUN(wt), (int)val);
+               */
                hwwrite(vortex->mmio, WT_RUN(wt), val);
                return 0xc;
                break;
        case 1:         /* param 0 */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_PARM(wt,0), (int)val);
+               */
                hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
                return 0xc;
                break;
        case 2:         /* param 1 */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_PARM(wt,1), (int)val);
+               */
                hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
                return 0xc;
                break;
        case 3:         /* param 2 */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_PARM(wt,2), (int)val);
+               */
                hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
                return 0xc;
                break;
        case 4:         /* param 3 */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_PARM(wt,3), (int)val);
+               */
                hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
                return 0xc;
                break;
        case 6:         /* mute */
-               //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val);
+               /*
+               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                      WT_MUTE(wt), (int)val);
+               */
                hwwrite(vortex->mmio, WT_MUTE(wt), val);
                return 0xc;
                break;
        case 0xb:
                {               /* delay */
-                       //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val);
+                       /*
+                       printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+                              WT_DELAY(wt,0), (int)val);
+                       */
                        hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
                        hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
                        hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
@@ -272,7 +293,9 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
                return 0;
                break;
        }
-       //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+       /*
+       printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+       */
        hwwrite(vortex->mmio, ecx, val);
        return 1;
 }
index c7c54e7748e9ac6fdbf09f1d4bb11f7106d1bfc3..8eea29fc42fe8b7d56769ba9d40de84f38fc400f 100644 (file)
@@ -368,9 +368,9 @@ static int __devinit snd_aw2_probe(struct pci_dev *pci,
        }
 
        /* (2) Create card instance */
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        /* (3) Create main component */
        err = snd_aw2_create(card, pci, &chip);
index 333007c523a1f876b2deca492a71c59f93de86e4..e9e9b5821d41f1c4287b96a1115a11a928b534e4 100644 (file)
@@ -211,25 +211,25 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 #endif
 
 #if DEBUG_MIXER
-#define snd_azf3328_dbgmixer(format, args...) printk(format, ##args)
+#define snd_azf3328_dbgmixer(format, args...) printk(KERN_DEBUG format, ##args)
 #else
 #define snd_azf3328_dbgmixer(format, args...)
 #endif
 
 #if DEBUG_PLAY_REC
-#define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args)
 #else
 #define snd_azf3328_dbgplay(format, args...)
 #endif
 
 #if DEBUG_MISC
-#define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbgtimer(format, args...) printk(KERN_DEBUG format, ##args)
 #else
 #define snd_azf3328_dbgtimer(format, args...)
 #endif
 
 #if DEBUG_GAME
-#define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbggame(format, args...) printk(KERN_DEBUG format, ##args)
 #else
 #define snd_azf3328_dbggame(format, args...)
 #endif
@@ -2216,9 +2216,9 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "AZF3328");
        strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
index 1aa1c04025407f2243d11a277f26b2a29da6c740..a299340519dfab53f07e3991124ca18223753c32 100644 (file)
@@ -888,9 +888,9 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_bt87x_create(card, pci, &chip);
        if (err < 0)
index 0e62205d4081d3da96606c9b48f7b568d221f7ca..df757575798a8db40d80fc982cd380dd89eff4e1 100644 (file)
@@ -255,6 +255,14 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .gpio_type = 2,
           .i2c_adc = 1,
           .spi_dac = 1 } ,
+       /* Giga-byte GA-G1975X mobo
+        * Novell bnc#395807
+        */
+       /* FIXME: the GPIO and I2C setting aren't tested well */
+       { .serial = 0x1458a006,
+         .name = "Giga-byte GA-G1975X",
+         .gpio_type = 1,
+         .i2c_adc = 1 },
         /* Shuttle XPC SD31P which has an onboard Creative Labs
          * Sound Blaster Live! 24-bit EAX
          * high-definition 7.1 audio processor".
@@ -404,7 +412,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
        }
 
        tmp = reg << 25 | value << 16;
-       // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+       /*
+       snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+       */
        /* Not sure what this I2C channel controls. */
        /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
 
@@ -422,7 +432,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
                /* Wait till the transaction ends */
                while (1) {
                        status = snd_ca0106_ptr_read(emu, I2C_A, 0);
-                       //snd_printk("I2C:status=0x%x\n", status);
+                       /*snd_printk(KERN_DEBUG "I2C:status=0x%x\n", status);*/
                        timeout++;
                        if ((status & I2C_A_ADC_START) == 0)
                                break;
@@ -521,7 +531,10 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
         channel->number = channel_id;
 
        channel->use = 1;
-        //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+       /*
+       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+              channel_id, chip, channel);
+       */
         //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
        channel->epcm = epcm;
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -614,7 +627,10 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
         channel->number = channel_id;
 
        channel->use = 1;
-        //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+       /*
+        printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+              channel_id, chip, channel);
+       */
         //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
         channel->epcm = epcm;
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -705,9 +721,20 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
        u32 reg71;
        int i;
        
-        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
-        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
-       //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#if 0 /* debug */
+       snd_printk(KERN_DEBUG
+                  "prepare:channel_number=%d, rate=%d, format=0x%x, "
+                  "channels=%d, buffer_size=%ld, period_size=%ld, "
+                  "periods=%u, frames_to_bytes=%d\n",
+                  channel, runtime->rate, runtime->format,
+                  runtime->channels, runtime->buffer_size,
+                  runtime->period_size, runtime->periods,
+                  frames_to_bytes(runtime, 1));
+       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+                  runtime->dma_addr, runtime->dma_area, table_base);
+       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+                  emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#endif /* debug */
        /* Rate can be set per channel. */
        /* reg40 control host to fifo */
        /* reg71 controls DAC rate. */
@@ -799,9 +826,20 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
        u32 reg71_set = 0;
        u32 reg71;
        
-        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
-        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
-       //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#if 0 /* debug */
+       snd_printk(KERN_DEBUG
+                  "prepare:channel_number=%d, rate=%d, format=0x%x, "
+                  "channels=%d, buffer_size=%ld, period_size=%ld, "
+                  "periods=%u, frames_to_bytes=%d\n",
+                  channel, runtime->rate, runtime->format,
+                  runtime->channels, runtime->buffer_size,
+                  runtime->period_size, runtime->periods,
+                  frames_to_bytes(runtime, 1));
+        snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+                  runtime->dma_addr, runtime->dma_area, table_base);
+       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+                  emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#endif /* debug */
        /* reg71 controls ADC rate. */
        switch (runtime->rate) {
        case 44100:
@@ -846,7 +884,14 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
        }
 
 
-        //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size,  frames_to_bytes(runtime, 1));
+       /*
+       printk(KERN_DEBUG
+              "prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, "
+              "buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",
+              channel, runtime->rate, runtime->format, runtime->channels,
+              runtime->buffer_size, runtime->period_size,
+              frames_to_bytes(runtime, 1));
+       */
        snd_ca0106_ptr_write(emu, 0x13, channel, 0);
        snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
        snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
@@ -888,13 +933,13 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream,
                runtime = s->runtime;
                epcm = runtime->private_data;
                channel = epcm->channel_id;
-               /* snd_printk("channel=%d\n",channel); */
+               /* snd_printk(KERN_DEBUG "channel=%d\n", channel); */
                epcm->running = running;
                basic |= (0x1 << channel);
                extended |= (0x10 << channel);
                 snd_pcm_trigger_done(s, substream);
         }
-       /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */
+       /* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x\n",basic, extended); */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -972,8 +1017,13 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
        ptr=ptr2;
         if (ptr >= runtime->buffer_size)
                ptr -= runtime->buffer_size;
-       //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
-
+       /*
+       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
+              ptr1, ptr2, ptr, (int)runtime->buffer_size,
+              (int)runtime->period_size, (int)runtime->frame_bits,
+              (int)runtime->rate);
+       */
        return ptr;
 }
 
@@ -995,8 +1045,13 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
        ptr=ptr2;
         if (ptr >= runtime->buffer_size)
                ptr -= runtime->buffer_size;
-       //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
-
+       /*
+       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
+              ptr1, ptr2, ptr, (int)runtime->buffer_size,
+              (int)runtime->period_size, (int)runtime->frame_bits,
+              (int)runtime->rate);
+       */
        return ptr;
 }
 
@@ -1181,8 +1236,12 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
 
         stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);
-       //snd_printk("interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76);
-       //snd_printk("ptr=0x%08x\n",snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
+       /*
+       snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x\n",
+                  status, stat76);
+       snd_printk(KERN_DEBUG "ptr=0x%08x\n",
+                  snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
+       */
         mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */
        for(i = 0; i < 4; i++) {
                pchannel = &(chip->playback_channels[i]);
@@ -1470,7 +1529,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                int size, n;
 
                size = ARRAY_SIZE(i2c_adc_init);
-               /* snd_printk("I2C:array size=0x%x\n", size); */
+               /* snd_printk(KERN_DEBUG "I2C:array size=0x%x\n", size); */
                for (n = 0; n < size; n++)
                        snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
                                             i2c_adc_init[n][1]);
@@ -1707,9 +1766,9 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_ca0106_create(dev, card, pci, &chip);
        if (err < 0)
index 1a74ca62c31484a8b8923f324771c43fcd1491a3..c7899c32aba19d08b945da3e4c4e510d46fa6a8f 100644 (file)
@@ -3272,9 +3272,9 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        
        switch (pci->device) {
        case PCI_DEVICE_ID_CMEDIA_CM8738:
index 192e7842e181e4cbbe8c3f0be43c7cccb4213964..f6286f84a2213c1b08314de7b74f2bcd6a2469fb 100644 (file)
@@ -834,7 +834,11 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream)
        struct cs4281_dma *dma = runtime->private_data;
        struct cs4281 *chip = snd_pcm_substream_chip(substream);
 
-       // printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies);
+       /*
+       printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+              snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+              jiffies);
+       */
        return runtime->buffer_size -
               snd_cs4281_peekBA0(chip, dma->regDCC) - 1;
 }
@@ -1925,9 +1929,9 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) {
                snd_card_free(card);
index e876b3263e462a9060b071e7974f1b0dcb90c583..c9b3e3d48cbcbf819e16e5d0a8535e8029310596 100644 (file)
@@ -88,9 +88,9 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_cs46xx_create(card, pci,
                                     external_amp[dev], thinkpad[dev],
                                     &chip)) < 0) {
index 8ab07aa63652b010c9337c7a83c66a8e2a1c5218..1be96ead42448d08be408f3f05993a9d76a14a82 100644 (file)
@@ -194,7 +194,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
         *  ACSDA = Status Data Register = 474h
         */
 #if 0
-       printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
+       printk(KERN_DEBUG "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
                        snd_cs46xx_peekBA0(chip, BA0_ACSDA),
                        snd_cs46xx_peekBA0(chip, BA0_ACCAD));
 #endif
@@ -428,8 +428,8 @@ static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout)
        }
   
        if(status & SERBST_WBSY) {
-               snd_printk( KERN_ERR "cs46xx: failure waiting for FIFO command to complete\n");
-
+               snd_printk(KERN_ERR "cs46xx: failure waiting for "
+                          "FIFO command to complete\n");
                return -EINVAL;
        }
 
index 018a7de5601706d9c11ff38a2317af65a208873f..4eb55aa336125bb05ce6ccdf91ae589a5a752e6a 100644 (file)
@@ -62,7 +62,11 @@ static inline void snd_cs46xx_poke(struct snd_cs46xx *chip, unsigned long reg, u
        unsigned int bank = reg >> 16;
        unsigned int offset = reg & 0xffff;
 
-       /*if (bank == 0) printk("snd_cs46xx_poke: %04X - %08X\n",reg >> 2,val); */
+       /*
+       if (bank == 0)
+               printk(KERN_DEBUG "snd_cs46xx_poke: %04X - %08X\n",
+                      reg >> 2,val);
+       */
        writel(val, chip->region.idx[bank+1].remap_addr + offset);
 }
 
index 6dea5b5cc77419814334addf8b22c06c5bee142c..dc464321d0f3ebda294e8e45de1db429122f4bc7 100644 (file)
@@ -258,10 +258,10 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
 
-       if (card == NULL)
-               return -ENOMEM;
+       if (err < 0)
+               return err;
 
        err = snd_cs5530_create(card, pci, &chip);
        if (err < 0) {
index 826e6dec2e97cf1e834d08b4c380469cb4717c8a..c89ed1f5bc2bd5e6f29f357944de60aca751bae0 100644 (file)
@@ -312,7 +312,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_cs5535audio_interrupt,
                        IRQF_SHARED, "CS5535 Audio", cs5535au)) {
-               snd_printk("unable to grab IRQ %d\n", pci->irq);
+               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto sndfail;
        }
@@ -353,9 +353,9 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0)
                goto probefail_out;
index 7b576aeb3f8d20a3d1d4083c503bf0c5c09441c6..1361de77e0cd2edd61574776e85da80e03208f53 100644 (file)
@@ -15,6 +15,8 @@ snd-echo3g-objs := echo3g.o
 snd-indigo-objs := indigo.o
 snd-indigoio-objs := indigoio.o
 snd-indigodj-objs := indigodj.o
+snd-indigoiox-objs := indigoiox.o
+snd-indigodjx-objs := indigodjx.o
 
 obj-$(CONFIG_SND_DARLA20) += snd-darla20.o
 obj-$(CONFIG_SND_GINA20) += snd-gina20.o
@@ -28,3 +30,5 @@ obj-$(CONFIG_SND_ECHO3G) += snd-echo3g.o
 obj-$(CONFIG_SND_INDIGO) += snd-indigo.o
 obj-$(CONFIG_SND_INDIGOIO) += snd-indigoio.o
 obj-$(CONFIG_SND_INDIGODJ) += snd-indigodj.o
+obj-$(CONFIG_SND_INDIGOIOX) += snd-indigoiox.o
+obj-$(CONFIG_SND_INDIGODJX) += snd-indigodjx.o
index 417e25add82bccdb120724b837b5d32f52b2f62c..57967e580571ffaf6634d5a8d5e265c4c9101d83 100644 (file)
@@ -56,7 +56,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        }
 
        chip->comm_page->e3g_frq_register =
-               __constant_cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
+               cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
        chip->device_id = device_id;
        chip->subdevice_id = subdevice_id;
        chip->bad_board = TRUE;
index 8dbc5c4ba421a03dd128050dbd271616efdee3ae..da2065cd2c0d5c3ffd5783b98c90ebfbc4ee244c 100644 (file)
@@ -950,6 +950,8 @@ static int __devinit snd_echo_new_pcm(struct echoaudio *chip)
        Control interface
 ******************************************************************************/
 
+#ifndef ECHOCARD_HAS_VMIXER
+
 /******************* PCM output volume *******************/
 static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
@@ -1001,18 +1003,6 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
        return changed;
 }
 
-#ifdef ECHOCARD_HAS_VMIXER
-/* On Vmixer cards this one controls the line-out volume */
-static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
-       .name = "Line Playback Volume",
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-       .info = snd_echo_output_gain_info,
-       .get = snd_echo_output_gain_get,
-       .put = snd_echo_output_gain_put,
-       .tlv = {.p = db_scale_output_gain},
-};
-#else
 static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
        .name = "PCM Playback Volume",
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1022,6 +1012,7 @@ static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
        .put = snd_echo_output_gain_put,
        .tlv = {.p = db_scale_output_gain},
 };
+
 #endif
 
 
@@ -1997,9 +1988,9 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
 
        DE_INIT(("Echoaudio driver starting...\n"));
        i = 0;
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        snd_card_set_dev(card, &pci->dev);
 
@@ -2037,8 +2028,6 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
 
 #ifdef ECHOCARD_HAS_VMIXER
        snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
-       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_output_gain, chip))) < 0)
-               goto ctl_error;
        if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
                goto ctl_error;
 #else
index 1c88e051abf2a5c33e809e54c47a3479d114cbb0..f9490ae36c2e6eeefafcd3d995b06d7db0bbc529 100644 (file)
 #define INDIGO                 0x0090
 #define INDIGO_IO              0x00a0
 #define INDIGO_DJ              0x00b0
+#define DC8                    0x00c0
+#define INDIGO_IOX             0x00d0
+#define INDIGO_DJX             0x00e0
 #define ECHO3G                 0x0100
 
 
index c3736bbd819e31da81312ccf942ff687bfa787d7..e32a748979210098c6282bfb9879d4d8cf89d504 100644 (file)
@@ -40,8 +40,7 @@ static int check_asic_status(struct echoaudio *chip)
        if (wait_handshake(chip))
                return -EIO;
 
-       chip->comm_page->ext_box_status =
-               __constant_cpu_to_le32(E3G_ASIC_NOT_LOADED);
+       chip->comm_page->ext_box_status = cpu_to_le32(E3G_ASIC_NOT_LOADED);
        chip->asic_loaded = FALSE;
        clear_handshake(chip);
        send_vector(chip, DSP_VC_TEST_ASIC);
index be0e18192de3ffca06502cbbc23e872df3d0cecb..4df51ef5e09533231100d94aa1bc35404e992df3 100644 (file)
@@ -926,11 +926,11 @@ static int init_dsp_comm_page(struct echoaudio *chip)
 
        /* Init the comm page */
        chip->comm_page->comm_size =
-               __constant_cpu_to_le32(sizeof(struct comm_page));
+               cpu_to_le32(sizeof(struct comm_page));
        chip->comm_page->handshake = 0xffffffff;
        chip->comm_page->midi_out_free_count =
-               __constant_cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
-       chip->comm_page->sample_rate = __constant_cpu_to_le32(44100);
+               cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
+       chip->comm_page->sample_rate = cpu_to_le32(44100);
        chip->sample_rate = 44100;
 
        /* Set line levels so we don't blast any inputs on startup */
index e352f3ae292c3bd495b127581d29b868dcc6268e..cb7d75a0a50349eeb745d3f97f2f497cac24a149 100644 (file)
@@ -576,8 +576,13 @@ SET_LAYLA24_FREQUENCY_REG command.
 #define E3G_ASIC_NOT_LOADED            0xffff
 #define E3G_BOX_TYPE_MASK              0xf0
 
-#define EXT_3GBOX_NC                   0x01
-#define EXT_3GBOX_NOT_SET              0x02
+/* Indigo express control register values */
+#define INDIGO_EXPRESS_32000           0x02
+#define INDIGO_EXPRESS_44100           0x01
+#define INDIGO_EXPRESS_48000           0x00
+#define INDIGO_EXPRESS_DOUBLE_SPEED    0x10
+#define INDIGO_EXPRESS_QUAD_SPEED      0x04
+#define INDIGO_EXPRESS_CLOCK_MASK      0x17
 
 
 /*
index db6c952e9d7f12e77a799d0e8edaabd12c8af5a8..3f1e7475faea916203d6c3af085ce5bb6fd1300e 100644 (file)
@@ -208,10 +208,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
        DE_ACT(("set_professional_spdif %d\n", prof));
        if (prof)
                chip->comm_page->flags |=
-                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        else
                chip->comm_page->flags &=
-                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        chip->professional_spdif = prof;
        return update_flags(chip);
 }
index f05e39f7aad943c2e5591cda8aac4b4336d524de..0b2cd9c8627750f0b2addbc5c8005756d9edb1aa 100644 (file)
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
 
-       /* Default routing of the virtual channels: all vchannels are routed
-       to the stereo output */
-       set_vmixer_gain(chip, 0, 0, 0);
-       set_vmixer_gain(chip, 1, 1, 0);
-       set_vmixer_gain(chip, 0, 2, 0);
-       set_vmixer_gain(chip, 1, 3, 0);
-       set_vmixer_gain(chip, 0, 4, 0);
-       set_vmixer_gain(chip, 1, 5, 0);
-       set_vmixer_gain(chip, 0, 6, 0);
-       set_vmixer_gain(chip, 1, 7, 0);
-       err = update_vmixer_level(chip);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c
new file mode 100644 (file)
index 0000000..9ab625e
--- /dev/null
@@ -0,0 +1,119 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 clock, control_reg, old_control_reg;
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       old_control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg = old_control_reg & ~INDIGO_EXPRESS_CLOCK_MASK;
+
+       switch (rate) {
+       case 32000:
+               clock = INDIGO_EXPRESS_32000;
+               break;
+       case 44100:
+               clock = INDIGO_EXPRESS_44100;
+               break;
+       case 48000:
+               clock = INDIGO_EXPRESS_48000;
+               break;
+       case 64000:
+               clock = INDIGO_EXPRESS_32000|INDIGO_EXPRESS_DOUBLE_SPEED;
+               break;
+       case 88200:
+               clock = INDIGO_EXPRESS_44100|INDIGO_EXPRESS_DOUBLE_SPEED;
+               break;
+       case 96000:
+               clock = INDIGO_EXPRESS_48000|INDIGO_EXPRESS_DOUBLE_SPEED;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       control_reg |= clock;
+       if (control_reg != old_control_reg) {
+               chip->comm_page->control_register = cpu_to_le32(control_reg);
+               chip->sample_rate = rate;
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+       }
+       return 0;
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain)
+{
+       int index;
+
+       if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+                      output >= num_busses_out(chip)))
+               return -EINVAL;
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->vmixer_gain[output][pipe] = gain;
+       index = output * num_pipes_out(chip) + pipe;
+       chip->comm_page->vmixer[index] = gain;
+
+       DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+       return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The IndigoIO has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
index 90730a5ecb422b880c8e36aff0d21adf2d8198aa..08392916691e365d53422f660cb5ac54e7c36b58 100644 (file)
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
 
-       /* Default routing of the virtual channels: vchannels 0-3 and
-       vchannels 4-7 are routed to real channels 0-4 */
-       set_vmixer_gain(chip, 0, 0, 0);
-       set_vmixer_gain(chip, 1, 1, 0);
-       set_vmixer_gain(chip, 2, 2, 0);
-       set_vmixer_gain(chip, 3, 3, 0);
-       set_vmixer_gain(chip, 0, 4, 0);
-       set_vmixer_gain(chip, 1, 5, 0);
-       set_vmixer_gain(chip, 2, 6, 0);
-       set_vmixer_gain(chip, 3, 7, 0);
-       err = update_vmixer_level(chip);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c
new file mode 100644 (file)
index 0000000..3482ef6
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2009 Giuliano Pochini <pochini@shiny.it>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_DJX
+#define ECHOCARD_NAME "Indigo DJx"
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 0 */
+#define PX_DIGITAL_IN  8       /* 0 */
+#define PX_NUM         8
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 4 */
+#define BX_DIGITAL_OUT 4       /* 0 */
+#define BX_ANALOG_IN   4       /* 0 */
+#define BX_DIGITAL_IN  4       /* 0 */
+#define BX_NUM         4
+
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+MODULE_FIRMWARE("ea/loader_dsp.fw");
+MODULE_FIRMWARE("ea/indigo_djx_dsp.fw");
+
+#define FW_361_LOADER          0
+#define FW_INDIGO_DJX_DSP      1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "indigo_djx_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0},      /* Indigo DJx*/
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 32000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 4,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "indigodjx_dsp.c"
+#include "indigo_express_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c
new file mode 100644 (file)
index 0000000..f591fc2
--- /dev/null
@@ -0,0 +1,68 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int update_vmixer_level(struct echoaudio *chip);
+static int set_vmixer_gain(struct echoaudio *chip, u16 output,
+                          u16 pipe, int gain);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Indigo DJx\n"));
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX))
+               return -ENODEV;
+
+       err = init_dsp_comm_page(chip);
+       if (err < 0) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       err = load_firmware(chip);
+       if (err < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       err = init_line_levels(chip);
+       if (err < 0)
+               return err;
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
index a7e09ec2107908f395319ca8b9cb0ab491b646f9..0604c8a85223bc7b0ceacfc6f60b3171193b65aa 100644 (file)
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)) < 0)
                return err;
 
-       /* Default routing of the virtual channels: all vchannels are routed
-       to the stereo output */
-       set_vmixer_gain(chip, 0, 0, 0);
-       set_vmixer_gain(chip, 1, 1, 0);
-       set_vmixer_gain(chip, 0, 2, 0);
-       set_vmixer_gain(chip, 1, 3, 0);
-       set_vmixer_gain(chip, 0, 4, 0);
-       set_vmixer_gain(chip, 1, 5, 0);
-       set_vmixer_gain(chip, 0, 6, 0);
-       set_vmixer_gain(chip, 1, 7, 0);
-       err = update_vmixer_level(chip);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c
new file mode 100644 (file)
index 0000000..aebee27
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2009 Giuliano Pochini <pochini@shiny.it>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_IOX
+#define ECHOCARD_NAME "Indigo IOx"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 2 */
+#define PX_DIGITAL_IN  10      /* 0 */
+#define PX_NUM         10
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 2 */
+#define BX_DIGITAL_OUT 2       /* 0 */
+#define BX_ANALOG_IN   2       /* 2 */
+#define BX_DIGITAL_IN  4       /* 0 */
+#define BX_NUM         4
+
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+MODULE_FIRMWARE("ea/loader_dsp.fw");
+MODULE_FIRMWARE("ea/indigo_iox_dsp.fw");
+
+#define FW_361_LOADER          0
+#define FW_INDIGO_IOX_DSP      1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "indigo_iox_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0},      /* Indigo IOx */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 32000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "indigoiox_dsp.c"
+#include "indigo_express_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c
new file mode 100644 (file)
index 0000000..f357521
--- /dev/null
@@ -0,0 +1,68 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int update_vmixer_level(struct echoaudio *chip);
+static int set_vmixer_gain(struct echoaudio *chip, u16 output,
+                          u16 pipe, int gain);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Indigo IOx\n"));
+       if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX))
+               return -ENODEV;
+
+       err = init_dsp_comm_page(chip);
+       if (err < 0) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       err = load_firmware(chip);
+       if (err < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       err = init_line_levels(chip);
+       if (err < 0)
+               return err;
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
index ede75c6ca0fb7520fb8ec8b93049da396618f946..83750e9fd7b4a3cc0290498ac1a267ee5c5da30f 100644 (file)
@@ -284,10 +284,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
        DE_ACT(("set_professional_spdif %d\n", prof));
        if (prof)
                chip->comm_page->flags |=
-                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        else
                chip->comm_page->flags &=
-                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        chip->professional_spdif = prof;
        return update_flags(chip);
 }
index 227386602f9b6a86064f8c92c94acbb980a953f3..551405114cbc67a33f04f0bf3fa37038ce1b32b7 100644 (file)
@@ -69,18 +69,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
        if ((err = init_line_levels(chip)))
                return err;
 
-       /* Default routing of the virtual channels: vchannels 0-3 go to analog
-       outputs and vchannels 4-7 go to S/PDIF outputs */
-       set_vmixer_gain(chip, 0, 0, 0);
-       set_vmixer_gain(chip, 1, 1, 0);
-       set_vmixer_gain(chip, 0, 2, 0);
-       set_vmixer_gain(chip, 1, 3, 0);
-       set_vmixer_gain(chip, 2, 4, 0);
-       set_vmixer_gain(chip, 3, 5, 0);
-       set_vmixer_gain(chip, 2, 6, 0);
-       set_vmixer_gain(chip, 3, 7, 0);
-       err = update_vmixer_level(chip);
-
        DE_INIT(("init_hw done\n"));
        return err;
 }
@@ -222,10 +210,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
        DE_ACT(("set_professional_spdif %d\n", prof));
        if (prof)
                chip->comm_page->flags |=
-                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        else
                chip->comm_page->flags &=
-                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+                       ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
        chip->professional_spdif = prof;
        return update_flags(chip);
 }
index 77bf2a83d9970751c3e26a449c7dfa1d882f89d8..a953d142cb4b41144090cf6f0d66b3ddf382fc67 100644 (file)
@@ -44,10 +44,10 @@ static int enable_midi_input(struct echoaudio *chip, char enable)
        if (enable) {
                chip->mtc_state = MIDI_IN_STATE_NORMAL;
                chip->comm_page->flags |=
-                       __constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+                       cpu_to_le32(DSP_FLAG_MIDI_INPUT);
        } else
                chip->comm_page->flags &=
-                       ~__constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+                       ~cpu_to_le32(DSP_FLAG_MIDI_INPUT);
 
        clear_handshake(chip);
        return send_vector(chip, DSP_VC_UPDATE_FLAGS);
index 8354c1a833129c7300b765ef918462a3852537f6..c7f3b994101cef1f335fde62e09a5d53616e4152 100644 (file)
@@ -114,9 +114,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        if (max_buffer_size[dev] < 32)
                max_buffer_size[dev] = 32;
        else if (max_buffer_size[dev] > 1024)
index 0e649dcdbf64bef54d800e8ad7b3384124ca0efe..7ef949d99a50a551d2e81b85175e01d96fa18728 100644 (file)
@@ -103,7 +103,10 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
                        int ch;
                        vp = &emu->voices[best[i].voice];
                        if ((ch = vp->ch) < 0) {
-                               //printk("synth_get_voice: ch < 0 (%d) ??", i);
+                               /*
+                               printk(KERN_WARNING
+                                      "synth_get_voice: ch < 0 (%d) ??", i);
+                               */
                                continue;
                        }
                        vp->emu->num_voices--;
@@ -335,7 +338,7 @@ start_voice(struct snd_emux_voice *vp)
                return -EINVAL;
        emem->map_locked++;
        if (snd_emu10k1_memblk_map(hw, emem) < 0) {
-               // printk("emu: cannot map!\n");
+               /* printk(KERN_ERR "emu: cannot map!\n"); */
                return -ENOMEM;
        }
        mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1;
index 101a1c13a20dd0b4cdd106d89dd5867187b2b2f9..f18bd6207c5066e0a38b2386feacd06a74039b57 100644 (file)
@@ -711,8 +711,7 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena
 static int emu1010_firmware_thread(void *data)
 {
        struct snd_emu10k1 *emu = data;
-       int tmp, tmp2;
-       int reg;
+       u32 tmp, tmp2, reg;
        int err;
 
        for (;;) {
@@ -758,7 +757,8 @@ static int emu1010_firmware_thread(void *data)
                        snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
                        snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
                        snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
-                       snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2);
+                       snd_printk(KERN_INFO "Audio Dock ver: %u.%u\n",
+                                  tmp, tmp2);
                        /* Sync clocking between 1010 and Dock */
                        /* Allow DLL to settle */
                        msleep(10);
@@ -804,8 +804,7 @@ static int emu1010_firmware_thread(void *data)
 static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 {
        unsigned int i;
-       int tmp, tmp2;
-       int reg;
+       u32 tmp, tmp2, reg;
        int err;
        const char *filename = NULL;
 
@@ -887,7 +886,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
        snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
        snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
        snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
-       snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2);
+       snd_printk(KERN_INFO "emu1010: Hana version: %u.%u\n", tmp, tmp2);
        /* Enable 48Volt power to Audio Dock */
        snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
 
index 5ff4dbb62dad1412e3f7ca987052427086912944..31542adc6b7e34a34d2ef6dca5758cb1992ad8af 100644 (file)
@@ -1544,9 +1544,9 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) {
                snd_card_free(card);
index 7dba08f0ab8e2c9d9e166fd12f3ed9934ed3cd34..191e1cd9997db53e8318ec4866efe327f9c012e4 100644 (file)
@@ -1519,7 +1519,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
        /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
        if (emu->card_capabilities->emu_model) {
                /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
-               snd_printk("EMU outputs on\n");
+               snd_printk(KERN_INFO "EMU outputs on\n");
                for (z = 0; z < 8; z++) {
                        if (emu->card_capabilities->ca0108_chip) {
                                A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
@@ -1567,7 +1567,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        if (emu->card_capabilities->emu_model) {
                if (emu->card_capabilities->ca0108_chip) {
-                       snd_printk("EMU2 inputs on\n");
+                       snd_printk(KERN_INFO "EMU2 inputs on\n");
                        for (z = 0; z < 0x10; z++) {
                                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, 
                                                                        bit_shifter16,
@@ -1575,10 +1575,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                                                                        A_FXBUS2(z*2) );
                        }
                } else {
-                       snd_printk("EMU inputs on\n");
+                       snd_printk(KERN_INFO "EMU inputs on\n");
                        /* Capture 16 (originally 8) channels of S32_LE sound */
 
-                       /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
+                       /*
+                       printk(KERN_DEBUG "emufx.c: gpr=0x%x, tmp=0x%x\n",
+                              gpr, tmp);
+                       */
                        /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
                        /* A_P16VIN(0) is delayed by one sample,
                         * so all other A_P16VIN channels will need to also be delayed
index cf9276ddad42dba9d3c91965f788124cd2d48990..78f62fd404c29613c802d4c812fb3d639c28e107 100644 (file)
@@ -44,7 +44,7 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu,
        if (epcm->substream == NULL)
                return;
 #if 0
-       printk("IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+       printk(KERN_DEBUG "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
                        epcm->substream->runtime->hw->pointer(emu, epcm->substream),
                        snd_pcm_lib_period_bytes(epcm->substream),
                        snd_pcm_lib_buffer_bytes(epcm->substream));
@@ -146,7 +146,11 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
                                              1,
                                              &epcm->extra);
                if (err < 0) {
-                       /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */
+                       /*
+                       printk(KERN_DEBUG "pcm_channel_alloc: "
+                              "failed extra: voices=%d, frame=%d\n",
+                              voices, frame);
+                       */
                        for (i = 0; i < voices; i++) {
                                snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
                                epcm->voices[i] = NULL;
@@ -737,7 +741,10 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
        struct snd_emu10k1_pcm_mixer *mix;
        int result = 0;
 
-       /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */
+       /*
+       printk(KERN_DEBUG "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
+              (int)emu, cmd, substream->ops->pointer(substream))
+       */
        spin_lock(&emu->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -786,7 +793,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
                /* hmm this should cause full and half full interrupt to be raised? */
                outl(epcm->capture_ipr, emu->port + IPR);
                snd_emu10k1_intr_enable(emu, epcm->capture_inte);
-               /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */
+               /*
+               printk(KERN_DEBUG "adccr = 0x%x, adcbs = 0x%x\n",
+                      epcm->adccr, epcm->adcbs);
+               */
                switch (epcm->type) {
                case CAPTURE_AC97ADC:
                        snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
@@ -857,7 +867,11 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
                        ptr -= runtime->buffer_size;
        }
 #endif
-       /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */
+       /*
+       printk(KERN_DEBUG
+              "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n",
+              ptr, runtime->buffer_size, runtime->period_size);
+       */
        return ptr;
 }
 
@@ -1546,7 +1560,11 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
                                                   unsigned int count,
                                                   unsigned int tram_shift)
 {
-       /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */
+       /*
+       printk(KERN_DEBUG "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
+              "src = 0x%p, count = 0x%x\n",
+              dst_left, dst_right, src, count);
+       */
        if ((tram_shift & 1) == 0) {
                while (count--) {
                        *dst_left-- = *src++;
@@ -1623,7 +1641,12 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
        struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
        unsigned int i;
        
-       /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */
+       /*
+       printk(KERN_DEBUG "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
+              "buffer_size = 0x%x (0x%x)\n",
+              emu->fx8010.etram_pages, runtime->dma_area,
+              runtime->buffer_size, runtime->buffer_size << 2);
+       */
        memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
        pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
        pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
index b5a802bdeb7c1b21f76573e72bbd16fd2af74898..4bfc31d1b281bd6847e1eb6abfe75c9d8eb6ee9b 100644 (file)
@@ -226,7 +226,9 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
                                break;
 
                        if (timeout > 1000) {
-                               snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
+                               snd_printk(KERN_WARNING
+                                          "emu10k1:I2C:timeout status=0x%x\n",
+                                          status);
                                break;
                        }
                }
index 749a21b6bd06bf9b49efed57c071560a13347ada..e617acaf10e3300679b7ca0614183877bc654db9 100644 (file)
@@ -168,7 +168,7 @@ static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
        struct snd_emu10k1_pcm *epcm = runtime->private_data;
   
        if (epcm) {
-               //snd_printk("epcm free: %p\n", epcm);
+               /* snd_printk(KERN_DEBUG "epcm free: %p\n", epcm); */
                kfree(epcm);
        }
 }
@@ -183,14 +183,16 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
        int err;
 
        epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
-        //snd_printk("epcm kcalloc: %p\n", epcm);
+        /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
 
        if (epcm == NULL)
                return -ENOMEM;
        epcm->emu = emu;
        epcm->substream = substream;
-        //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
-  
+       /*
+       snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+                  substream->pcm->device, channel_id);
+       */
        runtime->private_data = epcm;
        runtime->private_free = snd_p16v_pcm_free_substream;
   
@@ -200,10 +202,15 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
         channel->number = channel_id;
 
         channel->use=1;
-       //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
-        //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
-        //channel->interrupt = snd_p16v_pcm_channel_interrupt;
-        channel->epcm=epcm;
+#if 0 /* debug */
+       snd_printk(KERN_DEBUG
+                  "p16v: open channel_id=%d, channel=%p, use=0x%x\n",
+                  channel_id, channel, channel->use);
+       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+              channel_id, chip, channel);
+#endif /* debug */
+       /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
+       channel->epcm = epcm;
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                 return err;
 
@@ -224,14 +231,16 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
        int err;
 
        epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
-       //snd_printk("epcm kcalloc: %p\n", epcm);
+       /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
 
        if (epcm == NULL)
                return -ENOMEM;
        epcm->emu = emu;
        epcm->substream = substream;
-       //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
-
+       /*
+       snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+                  substream->pcm->device, channel_id);
+       */
        runtime->private_data = epcm;
        runtime->private_free = snd_p16v_pcm_free_substream;
   
@@ -241,10 +250,15 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
        channel->number = channel_id;
 
        channel->use=1;
-       //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
-       //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
-       //channel->interrupt = snd_p16v_pcm_channel_interrupt;
-       channel->epcm=epcm;
+#if 0 /* debug */
+       snd_printk(KERN_DEBUG
+                  "p16v: open channel_id=%d, channel=%p, use=0x%x\n",
+                  channel_id, channel, channel->use);
+       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+              channel_id, chip, channel);
+#endif /* debug */
+       /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
+       channel->epcm = epcm;
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                return err;
 
@@ -334,9 +348,19 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
        int i;
        u32 tmp;
        
-        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
-        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
-       //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes);
+#if 0 /* debug */
+       snd_printk(KERN_DEBUG "prepare:channel_number=%d, rate=%d, "
+                  "format=0x%x, channels=%d, buffer_size=%ld, "
+                  "period_size=%ld, periods=%u, frames_to_bytes=%d\n",
+                  channel, runtime->rate, runtime->format, runtime->channels,
+                  runtime->buffer_size, runtime->period_size,
+                  runtime->periods, frames_to_bytes(runtime, 1));
+       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+                  runtime->dma_addr, runtime->dma_area, table_base);
+       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+                  emu->p16v_buffer.addr, emu->p16v_buffer.area,
+                  emu->p16v_buffer.bytes);
+#endif /* debug */
        tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
         switch (runtime->rate) {
        case 44100:
@@ -379,7 +403,15 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        int channel = substream->pcm->device - emu->p16v_device_offset;
        u32 tmp;
-       //printk("prepare capture:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size,  frames_to_bytes(runtime, 1));
+
+       /*
+       printk(KERN_DEBUG "prepare capture:channel_number=%d, rate=%d, "
+              "format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, "
+              "frames_to_bytes=%d\n",
+              channel, runtime->rate, runtime->format, runtime->channels,
+              runtime->buffer_size, runtime->period_size,
+              frames_to_bytes(runtime, 1));
+       */
        tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
         switch (runtime->rate) {
        case 44100:
@@ -459,13 +491,13 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
                runtime = s->runtime;
                epcm = runtime->private_data;
                channel = substream->pcm->device-emu->p16v_device_offset;
-               //snd_printk("p16v channel=%d\n",channel);
+               /* snd_printk(KERN_DEBUG "p16v channel=%d\n", channel); */
                epcm->running = running;
                basic |= (0x1<<channel);
                inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);
                 snd_pcm_trigger_done(s, substream);
         }
-       //snd_printk("basic=0x%x, inte=0x%x\n",basic, inte);
+       /* snd_printk(KERN_DEBUG "basic=0x%x, inte=0x%x\n", basic, inte); */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -558,8 +590,13 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)
                ptr -= runtime->buffer_size;
                printk(KERN_WARNING "buffer capture limited!\n");
        }
-       //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
-
+       /*
+       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
+              ptr1, ptr2, ptr, (int)runtime->buffer_size,
+              (int)runtime->period_size, (int)runtime->frame_bits,
+              (int)runtime->rate);
+       */
        return ptr;
 }
 
@@ -592,7 +629,10 @@ int snd_p16v_free(struct snd_emu10k1 *chip)
        // release the data
        if (chip->p16v_buffer.area) {
                snd_dma_free_pages(&chip->p16v_buffer);
-               //snd_printk("period lables free: %p\n", &chip->p16v_buffer);
+               /*
+               snd_printk(KERN_DEBUG "period lables free: %p\n",
+                          &chip->p16v_buffer);
+               */
        }
        return 0;
 }
@@ -604,7 +644,7 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm *
        int err;
         int capture=1;
   
-       //snd_printk("snd_p16v_pcm called. device=%d\n", device);
+       /* snd_printk("KERN_DEBUG snd_p16v_pcm called. device=%d\n", device); */
        emu->p16v_device_offset = device;
        if (rpcm)
                *rpcm = NULL;
@@ -631,7 +671,10 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm *
                                                         snd_dma_pci_data(emu->pci), 
                                                         ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) 
                        return err;
-               //snd_printk("preallocate playback substream: err=%d\n", err);
+               /*
+               snd_printk(KERN_DEBUG
+                          "preallocate playback substream: err=%d\n", err);
+               */
        }
 
        for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 
@@ -642,7 +685,10 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm *
                                                   snd_dma_pci_data(emu->pci), 
                                                   65536 - 64, 65536 - 64)) < 0)
                        return err;
-               //snd_printk("preallocate capture substream: err=%d\n", err);
+               /*
+               snd_printk(KERN_DEBUG
+                          "preallocate capture substream: err=%d\n", err);
+               */
        }
   
        if (rpcm)
index d7300a1aa262b64cc54a9ca060242167b4b90ba5..20b8da250bd087190717e0f9774f9e8939e20a79 100644 (file)
@@ -53,7 +53,10 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        *rvoice = NULL;
        first_voice = last_voice = 0;
        for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
-               // printk("i %d j %d next free %d!\n", i, j, emu->next_free_voice);
+               /*
+               printk(KERN_DEBUG "i %d j %d next free %d!\n",
+                      i, j, emu->next_free_voice);
+               */
                i %= NUM_G;
 
                /* stereo voices must be even/odd */
@@ -71,7 +74,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
                        }
                }
                if (!skip) {
-                       // printk("allocated voice %d\n", i);
+                       /* printk(KERN_DEBUG "allocated voice %d\n", i); */
                        first_voice = i;
                        last_voice = (i + number) % NUM_G;
                        emu->next_free_voice = last_voice;
@@ -84,7 +87,10 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        
        for (i = 0; i < number; i++) {
                voice = &emu->voices[(first_voice + i) % NUM_G];
-               // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
+               /*
+               printk(kERN_DEBUG "voice alloc - %i, %i of %i\n",
+                      voice->number, idx-first_voice+1, number);
+               */
                voice->use = 1;
                switch (type) {
                case EMU10K1_PCM:
index 9bf95367c882b4fbe80558f254aa2b45456f9646..18f4d1e98c46945c63c0a2c80c64e1fcc198bde8 100644 (file)
@@ -584,7 +584,8 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
        unsigned long end_time = jiffies + HZ / 10;
 
 #if 0
-       printk("CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
+       printk(KERN_DEBUG
+              "CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
               reg, val, ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC));
 #endif
        do {
@@ -2409,9 +2410,9 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_ensoniq_create(card, pci, &ensoniq)) < 0) {
                snd_card_free(card);
index 4cd9a1faaecc186732b1ad911ebfd74e3c59e77e..dd63b132fb8efc0a3070976a2eca838e4812e550 100644 (file)
@@ -1673,18 +1673,22 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
 
        status = inb(SLIO_REG(chip, IRQCONTROL));
 #if 0
-       printk("Es1938debug - interrupt status: =0x%x\n", status);
+       printk(KERN_DEBUG "Es1938debug - interrupt status: =0x%x\n", status);
 #endif
        
        /* AUDIO 1 */
        if (status & 0x10) {
 #if 0
-                printk("Es1938debug - AUDIO channel 1 interrupt\n");
-               printk("Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
+                printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 1 interrupt\n");
+               printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
                       inw(SLDM_REG(chip, DMACOUNT)));
-               printk("Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
+               printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
                       inl(SLDM_REG(chip, DMAADDR)));
-               printk("Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
+               printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
                       inl(SLDM_REG(chip, DMASTATUS)));
 #endif
                /* clear irq */
@@ -1699,10 +1703,13 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
        /* AUDIO 2 */
        if (status & 0x20) {
 #if 0
-                printk("Es1938debug - AUDIO channel 2 interrupt\n");
-               printk("Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
+                printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 2 interrupt\n");
+               printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
                       inw(SLIO_REG(chip, AUDIO2DMACOUNT)));
-               printk("Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
+               printk(KERN_DEBUG
+                      "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
                       inl(SLIO_REG(chip, AUDIO2DMAADDR)));
 
 #endif
@@ -1799,9 +1806,9 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        for (idx = 0; idx < 5; idx++) {
                if (pci_resource_start(pci, idx) == 0 ||
                    !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) {
index e9c3794bbcb8a409751cc26ab466764d37fd1698..dc97e8116141645d9d399cf8eee503979c267784 100644 (file)
@@ -2645,9 +2645,9 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
                 
        if (total_bufsize[dev] < 128)
                total_bufsize[dev] = 128;
index c129f9e2072cb6970a1d5e83ad7b7f3950a4160b..60cdb9e0b68d23d112745c3dbe73354c124c1137 100644 (file)
@@ -1468,9 +1468,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) {
                snd_card_free(card);
                return err;
index 960fd79703848e153cb44fcff27ed58f97ad3337..4de5bacd392924d94482a45b8885182e966780ab 100644 (file)
@@ -138,6 +138,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 
                input_unregister_device(beep->dev);
                kfree(beep);
+               codec->beep = NULL;
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
index b9679f081cae9006a3a81b784f5e1e4927f567f5..51bf6a5daf39bd32bf9f1be6c6f94631426878fa 100644 (file)
@@ -39,7 +39,7 @@ struct hda_beep {
 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
 void snd_hda_detach_beep_device(struct hda_codec *codec);
 #else
-#define snd_hda_attach_beep_device(...)
+#define snd_hda_attach_beep_device(...)                0
 #define snd_hda_detach_beep_device(...)
 #endif
 #endif
index d03f99298be95eb64856288f71f957e4c63d2e8e..a4e5e59521157d8598553bc989b5e40e84b19a86 100644 (file)
@@ -647,9 +647,9 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
 
        total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
        for (i = 0; i < total_nodes; i++, nid++) {
-               unsigned int func;
-               func = snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE);
-               switch (func & 0xff) {
+               codec->function_id = snd_hda_param_read(codec, nid,
+                                               AC_PAR_FUNCTION_TYPE) & 0xff;
+               switch (codec->function_id) {
                case AC_GRP_AUDIO_FUNCTION:
                        codec->afg = nid;
                        break;
@@ -682,11 +682,140 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
        return 0;
 }
 
+/* read all pin default configurations and save codec->init_pins */
+static int read_pin_defaults(struct hda_codec *codec)
+{
+       int i;
+       hda_nid_t nid = codec->start_nid;
+
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               struct hda_pincfg *pin;
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
+                               AC_WCAP_TYPE_SHIFT;
+               if (wid_type != AC_WID_PIN)
+                       continue;
+               pin = snd_array_new(&codec->init_pins);
+               if (!pin)
+                       return -ENOMEM;
+               pin->nid = nid;
+               pin->cfg = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+       }
+       return 0;
+}
+
+/* look up the given pin config list and return the item matching with NID */
+static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec,
+                                        struct snd_array *array,
+                                        hda_nid_t nid)
+{
+       int i;
+       for (i = 0; i < array->used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(array, i);
+               if (pin->nid == nid)
+                       return pin;
+       }
+       return NULL;
+}
+
+/* write a config value for the given NID */
+static void set_pincfg(struct hda_codec *codec, hda_nid_t nid,
+                      unsigned int cfg)
+{
+       int i;
+       for (i = 0; i < 4; i++) {
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
+                                   cfg & 0xff);
+               cfg >>= 8;
+       }
+}
+
+/* set the current pin config value for the given NID.
+ * the value is cached, and read via snd_hda_codec_get_pincfg()
+ */
+int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
+                      hda_nid_t nid, unsigned int cfg)
+{
+       struct hda_pincfg *pin;
+       unsigned int oldcfg;
+
+       oldcfg = snd_hda_codec_get_pincfg(codec, nid);
+       pin = look_up_pincfg(codec, list, nid);
+       if (!pin) {
+               pin = snd_array_new(list);
+               if (!pin)
+                       return -ENOMEM;
+               pin->nid = nid;
+       }
+       pin->cfg = cfg;
+
+       /* change only when needed; e.g. if the pincfg is already present
+        * in user_pins[], don't write it
+        */
+       cfg = snd_hda_codec_get_pincfg(codec, nid);
+       if (oldcfg != cfg)
+               set_pincfg(codec, nid, cfg);
+       return 0;
+}
+
+int snd_hda_codec_set_pincfg(struct hda_codec *codec,
+                            hda_nid_t nid, unsigned int cfg)
+{
+       return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg);
+
+/* get the current pin config value of the given pin NID */
+unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_pincfg *pin;
+
+#ifdef CONFIG_SND_HDA_HWDEP
+       pin = look_up_pincfg(codec, &codec->user_pins, nid);
+       if (pin)
+               return pin->cfg;
+#endif
+       pin = look_up_pincfg(codec, &codec->driver_pins, nid);
+       if (pin)
+               return pin->cfg;
+       pin = look_up_pincfg(codec, &codec->init_pins, nid);
+       if (pin)
+               return pin->cfg;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
+
+/* restore all current pin configs */
+static void restore_pincfgs(struct hda_codec *codec)
+{
+       int i;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               set_pincfg(codec, pin->nid,
+                          snd_hda_codec_get_pincfg(codec, pin->nid));
+       }
+}
 
 static void init_hda_cache(struct hda_cache_rec *cache,
                           unsigned int record_size);
 static void free_hda_cache(struct hda_cache_rec *cache);
 
+/* restore the initial pin cfgs and release all pincfg lists */
+static void restore_init_pincfgs(struct hda_codec *codec)
+{
+       /* first free driver_pins and user_pins, then call restore_pincfg
+        * so that only the values in init_pins are restored
+        */
+       snd_array_free(&codec->driver_pins);
+#ifdef CONFIG_SND_HDA_HWDEP
+       snd_array_free(&codec->user_pins);
+#endif
+       restore_pincfgs(codec);
+       snd_array_free(&codec->init_pins);
+}
+
 /*
  * codec destructor
  */
@@ -694,6 +823,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 {
        if (!codec)
                return;
+       restore_init_pincfgs(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        cancel_delayed_work(&codec->power_work);
        flush_workqueue(codec->bus->workq);
@@ -712,6 +842,9 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        kfree(codec);
 }
 
+static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state);
+
 /**
  * snd_hda_codec_new - create a HDA codec
  * @bus: the bus to assign
@@ -751,6 +884,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
+       snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
+       snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        if (codec->bus->modelname) {
                codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
                if (!codec->modelname) {
@@ -787,15 +922,18 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        setup_fg_nodes(codec);
        if (!codec->afg && !codec->mfg) {
                snd_printdd("hda_codec: no AFG or MFG node found\n");
-               snd_hda_codec_free(codec);
-               return -ENODEV;
+               err = -ENODEV;
+               goto error;
        }
 
-       if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) {
+       err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
+       if (err < 0) {
                snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
-               snd_hda_codec_free(codec);
-               return -ENOMEM;
+               goto error;
        }
+       err = read_pin_defaults(codec);
+       if (err < 0)
+               goto error;
 
        if (!codec->subsystem_id) {
                hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
@@ -806,12 +944,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        if (bus->modelname)
                codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);
 
+       /* power-up all before initialization */
+       hda_set_power_state(codec,
+                           codec->afg ? codec->afg : codec->mfg,
+                           AC_PWRST_D0);
+
        if (do_init) {
                err = snd_hda_codec_configure(codec);
-               if (err < 0) {
-                       snd_hda_codec_free(codec);
-                       return err;
-               }
+               if (err < 0)
+                       goto error;
        }
        snd_hda_codec_proc_new(codec);
 
@@ -824,6 +965,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
        if (codecp)
                *codecp = codec;
        return 0;
+
+ error:
+       snd_hda_codec_free(codec);
+       return err;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_new);
 
@@ -907,6 +1052,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_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
 #define INFO_AMP_CAPS  (1<<0)
 #define INFO_AMP_VOL(ch)       (1 << (1 + (ch)))
 
@@ -997,6 +1143,21 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_amp_info *info;
+
+       info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+       if (!info)
+               return 0;
+       if (!info->head.val) {
+               info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+               info->head.val |= INFO_AMP_CAPS;
+       }
+       return info->amp_caps;
+}
+EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
+
 /*
  * read the current volume to info
  * if the cache exists, read the cache value.
@@ -1120,6 +1281,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
        u16 nid = get_amp_nid(kcontrol);
        u8 chs = get_amp_channels(kcontrol);
        int dir = get_amp_direction(kcontrol);
+       unsigned int ofs = get_amp_offset(kcontrol);
        u32 caps;
 
        caps = query_amp_caps(codec, nid, dir);
@@ -1131,6 +1293,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                       kcontrol->id.name);
                return -EINVAL;
        }
+       if (ofs < caps)
+               caps -= ofs;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = chs == 3 ? 2 : 1;
        uinfo->value.integer.min = 0;
@@ -1139,6 +1303,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
 
+
+static inline unsigned int
+read_amp_value(struct hda_codec *codec, hda_nid_t nid,
+              int ch, int dir, int idx, unsigned int ofs)
+{
+       unsigned int val;
+       val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
+       val &= HDA_AMP_VOLMASK;
+       if (val >= ofs)
+               val -= ofs;
+       else
+               val = 0;
+       return val;
+}
+
+static inline int
+update_amp_value(struct hda_codec *codec, hda_nid_t nid,
+                int ch, int dir, int idx, unsigned int ofs,
+                unsigned int val)
+{
+       if (val > 0)
+               val += ofs;
+       return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
+                                       HDA_AMP_VOLMASK, val);
+}
+
 int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
@@ -1147,14 +1337,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
        int chs = get_amp_channels(kcontrol);
        int dir = get_amp_direction(kcontrol);
        int idx = get_amp_index(kcontrol);
+       unsigned int ofs = get_amp_offset(kcontrol);
        long *valp = ucontrol->value.integer.value;
 
        if (chs & 1)
-               *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx)
-                       & HDA_AMP_VOLMASK;
+               *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
        if (chs & 2)
-               *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx)
-                       & HDA_AMP_VOLMASK;
+               *valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
@@ -1167,18 +1356,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
        int chs = get_amp_channels(kcontrol);
        int dir = get_amp_direction(kcontrol);
        int idx = get_amp_index(kcontrol);
+       unsigned int ofs = get_amp_offset(kcontrol);
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
        snd_hda_power_up(codec);
        if (chs & 1) {
-               change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
-                                                 0x7f, *valp);
+               change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
                valp++;
        }
        if (chs & 2)
-               change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  0x7f, *valp);
+               change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
        snd_hda_power_down(codec);
        return change;
 }
@@ -1190,6 +1378,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = get_amp_nid(kcontrol);
        int dir = get_amp_direction(kcontrol);
+       unsigned int ofs = get_amp_offset(kcontrol);
        u32 caps, val1, val2;
 
        if (size < 4 * sizeof(unsigned int))
@@ -1198,6 +1387,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
        val2 = (val2 + 1) * 25;
        val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
+       val1 += ofs;
        val1 = ((int)val1) * ((int)val2);
        if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
                return -EFAULT;
@@ -1268,7 +1458,6 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
 }
 EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
 
-#ifdef CONFIG_SND_HDA_RECONFIG
 /* Clear all controls assigned to the given codec */
 void snd_hda_ctls_clear(struct hda_codec *codec)
 {
@@ -1279,9 +1468,52 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
        snd_array_free(&codec->mixers);
 }
 
-void snd_hda_codec_reset(struct hda_codec *codec)
+/* pseudo device locking
+ * toggle card->shutdown to allow/disallow the device access (as a hack)
+ */
+static int hda_lock_devices(struct snd_card *card)
 {
-       int i;
+       spin_lock(&card->files_lock);
+       if (card->shutdown) {
+               spin_unlock(&card->files_lock);
+               return -EINVAL;
+       }
+       card->shutdown = 1;
+       spin_unlock(&card->files_lock);
+       return 0;
+}
+
+static void hda_unlock_devices(struct snd_card *card)
+{
+       spin_lock(&card->files_lock);
+       card->shutdown = 0;
+       spin_unlock(&card->files_lock);
+}
+
+int snd_hda_codec_reset(struct hda_codec *codec)
+{
+       struct snd_card *card = codec->bus->card;
+       int i, pcm;
+
+       if (hda_lock_devices(card) < 0)
+               return -EBUSY;
+       /* check whether the codec isn't used by any mixer or PCM streams */
+       if (!list_empty(&card->ctl_files)) {
+               hda_unlock_devices(card);
+               return -EBUSY;
+       }
+       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+               struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+               if (!cpcm->pcm)
+                       continue;
+               if (cpcm->pcm->streams[0].substream_opened ||
+                   cpcm->pcm->streams[1].substream_opened) {
+                       hda_unlock_devices(card);
+                       return -EBUSY;
+               }
+       }
+
+       /* OK, let it free */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        cancel_delayed_work(&codec->power_work);
@@ -1291,8 +1523,7 @@ void snd_hda_codec_reset(struct hda_codec *codec)
        /* relase PCMs */
        for (i = 0; i < codec->num_pcms; i++) {
                if (codec->pcm_info[i].pcm) {
-                       snd_device_free(codec->bus->card,
-                                       codec->pcm_info[i].pcm);
+                       snd_device_free(card, codec->pcm_info[i].pcm);
                        clear_bit(codec->pcm_info[i].device,
                                  codec->bus->pcm_dev_bits);
                }
@@ -1305,13 +1536,22 @@ void snd_hda_codec_reset(struct hda_codec *codec)
        free_hda_cache(&codec->cmd_cache);
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+       /* free only driver_pins so that init_pins + user_pins are restored */
+       snd_array_free(&codec->driver_pins);
+       restore_pincfgs(codec);
        codec->num_pcms = 0;
        codec->pcm_info = NULL;
        codec->preset = NULL;
+       memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
+       codec->slave_dig_outs = NULL;
+       codec->spdif_status_reset = 0;
        module_put(codec->owner);
        codec->owner = NULL;
+
+       /* allow device access again */
+       hda_unlock_devices(card);
+       return 0;
 }
-#endif /* CONFIG_SND_HDA_RECONFIG */
 
 /* create a virtual master control and add slaves */
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
@@ -1336,15 +1576,20 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        
        for (s = slaves; *s; s++) {
                struct snd_kcontrol *sctl;
-
-               sctl = snd_hda_find_mixer_ctl(codec, *s);
-               if (!sctl) {
-                       snd_printdd("Cannot find slave %s, skipped\n", *s);
-                       continue;
+               int i = 0;
+               for (;;) {
+                       sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
+                       if (!sctl) {
+                               if (!i)
+                                       snd_printdd("Cannot find slave %s, "
+                                                   "skipped\n", *s);
+                               break;
+                       }
+                       err = snd_ctl_add_slave(kctl, sctl);
+                       if (err < 0)
+                               return err;
+                       i++;
                }
-               err = snd_ctl_add_slave(kctl, sctl);
-               if (err < 0)
-                       return err;
        }
        return 0;
 }
@@ -1955,6 +2200,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
        }
        for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
                kctl = snd_ctl_new1(dig_mix, codec);
+               if (!kctl)
+                       return -ENOMEM;
                kctl->private_value = nid;
                err = snd_hda_ctl_add(codec, kctl);
                if (err < 0)
@@ -2074,8 +2321,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
                                 * don't power down the widget if it controls
                                 * eapd and EAPD_BTLENABLE is set.
                                 */
-                               pincap = snd_hda_param_read(codec, nid,
-                                                           AC_PAR_PIN_CAP);
+                               pincap = snd_hda_query_pin_caps(codec, nid);
                                if (pincap & AC_PINCAP_EAPD) {
                                        int eapd = snd_hda_codec_read(codec,
                                                nid, 0,
@@ -2144,6 +2390,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
        hda_set_power_state(codec,
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D0);
+       restore_pincfgs(codec); /* restore all current pin configs */
        hda_exec_init_verbs(codec);
        if (codec->patch_ops.resume)
                codec->patch_ops.resume(codec);
@@ -2171,8 +2418,16 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
 
        list_for_each_entry(codec, &bus->codec_list, list) {
                int err = snd_hda_codec_build_controls(codec);
-               if (err < 0)
-                       return err;
+               if (err < 0) {
+                       printk(KERN_ERR "hda_codec: cannot build controls"
+                              "for #%d (error %d)\n", codec->addr, err); 
+                       err = snd_hda_codec_reset(codec);
+                       if (err < 0) {
+                               printk(KERN_ERR
+                                      "hda_codec: cannot revert codec\n");
+                               return err;
+                       }
+               }
        }
        return 0;
 }
@@ -2181,19 +2436,12 @@ EXPORT_SYMBOL_HDA(snd_hda_build_controls);
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
        int err = 0;
-       /* fake as if already powered-on */
-       hda_keep_power_on(codec);
-       /* then fire up */
-       hda_set_power_state(codec,
-                           codec->afg ? codec->afg : codec->mfg,
-                           AC_PWRST_D0);
        hda_exec_init_verbs(codec);
        /* continue to initialize... */
        if (codec->patch_ops.init)
                err = codec->patch_ops.init(codec);
        if (!err && codec->patch_ops.build_controls)
                err = codec->patch_ops.build_controls(codec);
-       snd_hda_power_down(codec);
        if (err < 0)
                return err;
        return 0;
@@ -2306,12 +2554,11 @@ EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                                u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
 {
-       int i;
-       unsigned int val, streams;
+       unsigned int i, val, wcaps;
 
        val = 0;
-       if (nid != codec->afg &&
-           (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
+       wcaps = get_wcaps(codec, nid);
+       if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
                val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
                if (val == -1)
                        return -EIO;
@@ -2325,15 +2572,20 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                        if (val & (1 << i))
                                rates |= rate_bits[i].alsa_bits;
                }
+               if (rates == 0) {
+                       snd_printk(KERN_ERR "hda_codec: rates == 0 "
+                                  "(nid=0x%x, val=0x%x, ovrd=%i)\n",
+                                       nid, val,
+                                       (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
+                       return -EIO;
+               }
                *ratesp = rates;
        }
 
        if (formatsp || bpsp) {
                u64 formats = 0;
-               unsigned int bps;
-               unsigned int wcaps;
+               unsigned int streams, bps;
 
-               wcaps = get_wcaps(codec, nid);
                streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
                if (streams == -1)
                        return -EIO;
@@ -2386,6 +2638,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                        formats |= SNDRV_PCM_FMTBIT_U8;
                        bps = 8;
                }
+               if (formats == 0) {
+                       snd_printk(KERN_ERR "hda_codec: formats == 0 "
+                                  "(nid=0x%x, val=0x%x, ovrd=%i, "
+                                  "streams=0x%x)\n",
+                                       nid, val,
+                                       (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
+                                       streams);
+                       return -EIO;
+               }
                if (formatsp)
                        *formatsp = formats;
                if (bpsp)
@@ -2501,12 +2762,16 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
 static int set_pcm_default_values(struct hda_codec *codec,
                                  struct hda_pcm_stream *info)
 {
+       int err;
+
        /* query support PCM information from the given NID */
        if (info->nid && (!info->rates || !info->formats)) {
-               snd_hda_query_supported_pcm(codec, info->nid,
+               err = snd_hda_query_supported_pcm(codec, info->nid,
                                info->rates ? NULL : &info->rates,
                                info->formats ? NULL : &info->formats,
                                info->maxbps ? NULL : &info->maxbps);
+               if (err < 0)
+                       return err;
        }
        if (info->ops.open == NULL)
                info->ops.open = hda_pcm_default_open_close;
@@ -2549,13 +2814,10 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
                        dev = audio_idx[i];
                        if (!test_bit(dev, bus->pcm_dev_bits))
-                               break;
-               }
-               if (i >= ARRAY_SIZE(audio_idx)) {
-                       snd_printk(KERN_WARNING "Too many audio devices\n");
-                       return -EAGAIN;
+                               goto ok;
                }
-               break;
+               snd_printk(KERN_WARNING "Too many audio devices\n");
+               return -EAGAIN;
        case HDA_PCM_TYPE_SPDIF:
        case HDA_PCM_TYPE_HDMI:
        case HDA_PCM_TYPE_MODEM:
@@ -2570,6 +2832,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
                return -EINVAL;
        }
+ ok:
        set_bit(dev, bus->pcm_dev_bits);
        return dev;
 }
@@ -2606,24 +2869,36 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
                if (!codec->patch_ops.build_pcms)
                        return 0;
                err = codec->patch_ops.build_pcms(codec);
-               if (err < 0)
-                       return err;
+               if (err < 0) {
+                       printk(KERN_ERR "hda_codec: cannot build PCMs"
+                              "for #%d (error %d)\n", codec->addr, err); 
+                       err = snd_hda_codec_reset(codec);
+                       if (err < 0) {
+                               printk(KERN_ERR
+                                      "hda_codec: cannot revert codec\n");
+                               return err;
+                       }
+               }
        }
        for (pcm = 0; pcm < codec->num_pcms; pcm++) {
                struct hda_pcm *cpcm = &codec->pcm_info[pcm];
                int dev;
 
                if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
-                       return 0; /* no substreams assigned */
+                       continue; /* no substreams assigned */
 
                if (!cpcm->pcm) {
                        dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
                        if (dev < 0)
-                               return 0;
+                               continue; /* no fatal error */
                        cpcm->device = dev;
                        err = snd_hda_attach_pcm(codec, cpcm);
-                       if (err < 0)
-                               return err;
+                       if (err < 0) {
+                               printk(KERN_ERR "hda_codec: cannot attach "
+                                      "PCM stream %d for codec #%d\n",
+                                      dev, codec->addr);
+                               continue; /* no fatal error */
+                       }
                }
        }
        return 0;
@@ -3324,8 +3599,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                if (ignore_nids && is_in_nid_list(nid, ignore_nids))
                        continue;
 
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
                if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
                        continue;
                loc = get_defcfg_location(def_conf);
@@ -3401,10 +3675,22 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        cfg->input_pins[AUTO_PIN_AUX] = nid;
                        break;
                case AC_JACK_SPDIF_OUT:
-                       cfg->dig_out_pin = nid;
+               case AC_JACK_DIG_OTHER_OUT:
+                       if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+                               continue;
+                       cfg->dig_out_pins[cfg->dig_outs] = nid;
+                       cfg->dig_out_type[cfg->dig_outs] =
+                               (loc == AC_JACK_LOC_HDMI) ?
+                               HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
+                       cfg->dig_outs++;
                        break;
                case AC_JACK_SPDIF_IN:
+               case AC_JACK_DIG_OTHER_IN:
                        cfg->dig_in_pin = nid;
+                       if (loc == AC_JACK_LOC_HDMI)
+                               cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
+                       else
+                               cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
                        break;
                }
        }
@@ -3510,6 +3796,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                   cfg->hp_pins[1], cfg->hp_pins[2],
                   cfg->hp_pins[3], cfg->hp_pins[4]);
        snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
+       if (cfg->dig_outs)
+               snd_printd("   dig-out=0x%x/0x%x\n",
+                          cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
        snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
                   " cd=0x%x, aux=0x%x\n",
                   cfg->input_pins[AUTO_PIN_MIC],
@@ -3518,6 +3807,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                   cfg->input_pins[AUTO_PIN_FRONT_LINE],
                   cfg->input_pins[AUTO_PIN_CD],
                   cfg->input_pins[AUTO_PIN_AUX]);
+       if (cfg->dig_in_pin)
+               snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
        return 0;
 }
index 09a332ada0c68dd8a840de095846fe4f9328abcc..2fdecf4b0eb631b89ef15f47ef1f37c3ac2e13ed 100644 (file)
@@ -739,6 +739,7 @@ struct hda_codec {
        hda_nid_t mfg;  /* MFG node id */
 
        /* ids */
+       u32 function_id;
        u32 vendor_id;
        u32 subsystem_id;
        u32 revision_id;
@@ -778,11 +779,14 @@ struct hda_codec {
        unsigned short spdif_ctls;      /* SPDIF control bits */
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
        hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
+       struct snd_array init_pins;     /* initial (BIOS) pin configurations */
+       struct snd_array driver_pins;   /* pin configs set by codec parser */
 
 #ifdef CONFIG_SND_HDA_HWDEP
        struct snd_hwdep *hwdep;        /* assigned hwdep device */
        struct snd_array init_verbs;    /* additional init verbs */
        struct snd_array hints;         /* additional hints */
+       struct snd_array user_pins;     /* default pin configs to override */
 #endif
 
        /* misc flags */
@@ -790,6 +794,9 @@ struct hda_codec {
                                             * status change
                                             * (e.g. Realtek codecs)
                                             */
+       unsigned int pin_amp_workaround:1; /* pin out-amp takes index
+                                           * (e.g. Conexant codecs)
+                                           */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        unsigned int power_on :1;       /* current (global) power-state */
        unsigned int power_transition :1; /* power-state in transition */
@@ -855,6 +862,18 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
 #define snd_hda_sequence_write_cache   snd_hda_sequence_write
 #endif
 
+/* the struct for codec->pin_configs */
+struct hda_pincfg {
+       hda_nid_t nid;
+       unsigned int cfg;
+};
+
+unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
+                            unsigned int cfg);
+int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
+                      hda_nid_t nid, unsigned int cfg); /* for hwdep */
+
 /*
  * Mixer
  */
index 65745e96dc701d91cb5bcbf31b883e80f53791e9..1d5797a966821aa197460ee1836d99452493c595 100644 (file)
@@ -144,9 +144,9 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
        node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 
        if (node->type == AC_WID_PIN) {
-               node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP);
+               node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
                node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+               node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid);
        }
 
        if (node->wid_caps & AC_WCAP_OUT_AMP) {
index 4ae51dcb81af861450e37d2219c76b6027746764..1c57505c2874d152ca4e76e3fbdefae5ecd81383 100644 (file)
 #include <sound/hda_hwdep.h>
 #include <sound/minors.h>
 
+/* hint string pair */
+struct hda_hint {
+       const char *key;
+       const char *val;        /* contained in the same alloc as key */
+};
+
 /*
  * write/read an out-of-bound verb
  */
@@ -99,16 +105,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
 
 static void clear_hwdep_elements(struct hda_codec *codec)
 {
-       char **head;
        int i;
 
        /* clear init verbs */
        snd_array_free(&codec->init_verbs);
        /* clear hints */
-       head = codec->hints.list;
-       for (i = 0; i < codec->hints.used; i++, head++)
-               kfree(*head);
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               kfree(hint->key); /* we don't need to free hint->val */
+       }
        snd_array_free(&codec->hints);
+       snd_array_free(&codec->user_pins);
 }
 
 static void hwdep_free(struct snd_hwdep *hwdep)
@@ -140,7 +147,8 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
 #endif
 
        snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
-       snd_array_init(&codec->hints, sizeof(char *), 32);
+       snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
+       snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
 
        return 0;
 }
@@ -153,7 +161,13 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
 
 static int clear_codec(struct hda_codec *codec)
 {
-       snd_hda_codec_reset(codec);
+       int err;
+
+       err = snd_hda_codec_reset(codec);
+       if (err < 0) {
+               snd_printk(KERN_ERR "The codec is being used, can't free.\n");
+               return err;
+       }
        clear_hwdep_elements(codec);
        return 0;
 }
@@ -162,20 +176,29 @@ static int reconfig_codec(struct hda_codec *codec)
 {
        int err;
 
+       snd_hda_power_up(codec);
        snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
-       snd_hda_codec_reset(codec);
+       err = snd_hda_codec_reset(codec);
+       if (err < 0) {
+               snd_printk(KERN_ERR
+                          "The codec is being used, can't reconfigure.\n");
+               goto error;
+       }
        err = snd_hda_codec_configure(codec);
        if (err < 0)
-               return err;
+               goto error;
        /* rebuild PCMs */
        err = snd_hda_codec_build_pcms(codec);
        if (err < 0)
-               return err;
+               goto error;
        /* rebuild mixers */
        err = snd_hda_codec_build_controls(codec);
        if (err < 0)
-               return err;
-       return snd_card_register(codec->bus->card);
+               goto error;
+       err = snd_card_register(codec->bus->card);
+ error:
+       snd_hda_power_down(codec);
+       return err;
 }
 
 /*
@@ -271,6 +294,22 @@ static ssize_t type##_store(struct device *dev,                    \
 CODEC_ACTION_STORE(reconfig);
 CODEC_ACTION_STORE(clear);
 
+static ssize_t init_verbs_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       int i, len = 0;
+       for (i = 0; i < codec->init_verbs.used; i++) {
+               struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "0x%02x 0x%03x 0x%04x\n",
+                               v->nid, v->verb, v->param);
+       }
+       return len;
+}
+
 static ssize_t init_verbs_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
@@ -293,26 +332,157 @@ static ssize_t init_verbs_store(struct device *dev,
        return count;
 }
 
+static ssize_t hints_show(struct device *dev,
+                         struct device_attribute *attr,
+                         char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       int i, len = 0;
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "%s = %s\n", hint->key, hint->val);
+       }
+       return len;
+}
+
+static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
+{
+       int i;
+
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               if (!strcmp(hint->key, key))
+                       return hint;
+       }
+       return NULL;
+}
+
+static void remove_trail_spaces(char *str)
+{
+       char *p;
+       if (!*str)
+               return;
+       p = str + strlen(str) - 1;
+       for (; isspace(*p); p--) {
+               *p = 0;
+               if (p == str)
+                       return;
+       }
+}
+
+#define MAX_HINTS      1024
+
 static ssize_t hints_store(struct device *dev,
                           struct device_attribute *attr,
                           const char *buf, size_t count)
 {
        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
        struct hda_codec *codec = hwdep->private_data;
-       char *p;
-       char **hint;
+       char *key, *val;
+       struct hda_hint *hint;
 
-       if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
+       while (isspace(*buf))
+               buf++;
+       if (!*buf || *buf == '#' || *buf == '\n')
                return count;
-       p = kstrndup_noeol(buf, 1024);
-       if (!p)
+       if (*buf == '=')
+               return -EINVAL;
+       key = kstrndup_noeol(buf, 1024);
+       if (!key)
                return -ENOMEM;
-       hint = snd_array_new(&codec->hints);
+       /* extract key and val */
+       val = strchr(key, '=');
+       if (!val) {
+               kfree(key);
+               return -EINVAL;
+       }
+       *val++ = 0;
+       while (isspace(*val))
+               val++;
+       remove_trail_spaces(key);
+       remove_trail_spaces(val);
+       hint = get_hint(codec, key);
+       if (hint) {
+               /* replace */
+               kfree(hint->key);
+               hint->key = key;
+               hint->val = val;
+               return count;
+       }
+       /* allocate a new hint entry */
+       if (codec->hints.used >= MAX_HINTS)
+               hint = NULL;
+       else
+               hint = snd_array_new(&codec->hints);
        if (!hint) {
-               kfree(p);
+               kfree(key);
                return -ENOMEM;
        }
-       *hint = p;
+       hint->key = key;
+       hint->val = val;
+       return count;
+}
+
+static ssize_t pin_configs_show(struct hda_codec *codec,
+                               struct snd_array *list,
+                               char *buf)
+{
+       int i, len = 0;
+       for (i = 0; i < list->used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(list, i);
+               len += sprintf(buf + len, "0x%02x 0x%08x\n",
+                              pin->nid, pin->cfg);
+       }
+       return len;
+}
+
+static ssize_t init_pin_configs_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       return pin_configs_show(codec, &codec->init_pins, buf);
+}
+
+static ssize_t user_pin_configs_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       return pin_configs_show(codec, &codec->user_pins, buf);
+}
+
+static ssize_t driver_pin_configs_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       return pin_configs_show(codec, &codec->driver_pins, buf);
+}
+
+#define MAX_PIN_CONFIGS                32
+
+static ssize_t user_pin_configs_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       int nid, cfg;
+       int err;
+
+       if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
+               return -EINVAL;
+       if (!nid)
+               return -EINVAL;
+       err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
+       if (err < 0)
+               return err;
        return count;
 }
 
@@ -331,8 +501,11 @@ static struct device_attribute codec_attrs[] = {
        CODEC_ATTR_RO(mfg),
        CODEC_ATTR_RW(name),
        CODEC_ATTR_RW(modelname),
-       CODEC_ATTR_WO(init_verbs),
-       CODEC_ATTR_WO(hints),
+       CODEC_ATTR_RW(init_verbs),
+       CODEC_ATTR_RW(hints),
+       CODEC_ATTR_RO(init_pin_configs),
+       CODEC_ATTR_RW(user_pin_configs),
+       CODEC_ATTR_RO(driver_pin_configs),
        CODEC_ATTR_WO(reconfig),
        CODEC_ATTR_WO(clear),
 };
@@ -351,4 +524,29 @@ int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * Look for hint string
+ */
+const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
+{
+       struct hda_hint *hint = get_hint(codec, key);
+       return hint ? hint->val : NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_hint);
+
+int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
+{
+       const char *p = snd_hda_get_hint(codec, key);
+       if (!p || !*p)
+               return -ENOENT;
+       switch (toupper(*p)) {
+       case 'T': /* true */
+       case 'Y': /* yes */
+       case '1':
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
+
 #endif /* CONFIG_SND_HDA_RECONFIG */
index f3b5723c285953201abe089d2830c48facda7613..30829ee920c3a8366ea841dbdb985787719b521e 100644 (file)
@@ -381,6 +381,7 @@ struct azx {
 
        /* HD codec */
        unsigned short codec_mask;
+       int  codec_probe_mask; /* copied from probe_mask option */
        struct hda_bus *bus;
 
        /* CORB/RIRB */
@@ -858,13 +859,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
                      SD_CTL_DMA_START | SD_INT_MASK);
 }
 
-/* stop a stream */
-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+/* stop DMA */
+static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
 {
-       /* stop DMA */
        azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
                      ~(SD_CTL_DMA_START | SD_INT_MASK));
        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+}
+
+/* stop a stream */
+static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+{
+       azx_stream_clear(chip, azx_dev);
        /* disable SIE */
        azx_writeb(chip, INTCTL,
                   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
@@ -1075,8 +1081,7 @@ static int azx_setup_periods(struct azx *chip,
        azx_sd_writel(azx_dev, SD_BDLPL, 0);
        azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
-       period_bytes = snd_pcm_lib_period_bytes(substream);
-       azx_dev->period_bytes = period_bytes;
+       period_bytes = azx_dev->period_bytes;
        periods = azx_dev->bufsize / period_bytes;
 
        /* program the initial BDL entries */
@@ -1123,24 +1128,17 @@ static int azx_setup_periods(struct azx *chip,
  error:
        snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
                   azx_dev->bufsize, period_bytes);
-       /* reset */
-       azx_sd_writel(azx_dev, SD_BDLPL, 0);
-       azx_sd_writel(azx_dev, SD_BDLPU, 0);
        return -EINVAL;
 }
 
-/*
- * set up the SD for streaming
- */
-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+/* reset stream */
+static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
 {
        unsigned char val;
        int timeout;
 
-       /* make sure the run bit is zero for SD */
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
-                     ~SD_CTL_DMA_START);
-       /* reset stream */
+       azx_stream_clear(chip, azx_dev);
+
        azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
                      SD_CTL_STREAM_RESET);
        udelay(3);
@@ -1157,7 +1155,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
               --timeout)
                ;
+}
 
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+{
+       /* make sure the run bit is zero for SD */
+       azx_stream_clear(chip, azx_dev);
        /* program the stream_tag */
        azx_sd_writel(azx_dev, SD_CTL,
                      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
@@ -1228,7 +1234,6 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
 };
 
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
-                                     unsigned int codec_probe_mask,
                                      int no_init)
 {
        struct hda_bus_template bus_temp;
@@ -1261,7 +1266,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
 
        /* First try to probe all given codec slots */
        for (c = 0; c < max_slots; c++) {
-               if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
+               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
                        if (probe_codec(chip, c) < 0) {
                                /* Some BIOSen give you wrong codec addresses
                                 * that don't exist
@@ -1285,7 +1290,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
 
        /* Then create codec instances */
        for (c = 0; c < max_slots; c++) {
-               if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
+               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
                        struct hda_codec *codec;
                        err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
                        if (err < 0)
@@ -1403,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        runtime->private_data = azx_dev;
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
+
+       azx_stream_reset(chip, azx_dev);
        return 0;
 }
 
@@ -1429,6 +1436,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
 static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *hw_params)
 {
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+
+       azx_dev->bufsize = 0;
+       azx_dev->period_bytes = 0;
+       azx_dev->format_val = 0;
        return snd_pcm_lib_malloc_pages(substream,
                                        params_buffer_bytes(hw_params));
 }
@@ -1443,6 +1455,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
        azx_sd_writel(azx_dev, SD_BDLPL, 0);
        azx_sd_writel(azx_dev, SD_BDLPU, 0);
        azx_sd_writel(azx_dev, SD_CTL, 0);
+       azx_dev->bufsize = 0;
+       azx_dev->period_bytes = 0;
+       azx_dev->format_val = 0;
 
        hinfo->ops.cleanup(hinfo, apcm->codec, substream);
 
@@ -1456,23 +1471,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
        struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int bufsize, period_bytes, format_val;
+       int err;
 
-       azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
-       azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
-                                                        runtime->channels,
-                                                        runtime->format,
-                                                        hinfo->maxbps);
-       if (!azx_dev->format_val) {
+       format_val = snd_hda_calc_stream_format(runtime->rate,
+                                               runtime->channels,
+                                               runtime->format,
+                                               hinfo->maxbps);
+       if (!format_val) {
                snd_printk(KERN_ERR SFX
                           "invalid format_val, rate=%d, ch=%d, format=%d\n",
                           runtime->rate, runtime->channels, runtime->format);
                return -EINVAL;
        }
 
+       bufsize = snd_pcm_lib_buffer_bytes(substream);
+       period_bytes = snd_pcm_lib_period_bytes(substream);
+
        snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
-                   azx_dev->bufsize, azx_dev->format_val);
-       if (azx_setup_periods(chip, substream, azx_dev) < 0)
-               return -EINVAL;
+                   bufsize, format_val);
+
+       if (bufsize != azx_dev->bufsize ||
+           period_bytes != azx_dev->period_bytes ||
+           format_val != azx_dev->format_val) {
+               azx_dev->bufsize = bufsize;
+               azx_dev->period_bytes = period_bytes;
+               azx_dev->format_val = format_val;
+               err = azx_setup_periods(chip, substream, azx_dev);
+               if (err < 0)
+                       return err;
+       }
+
        azx_setup_controller(chip, azx_dev);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -2100,25 +2129,36 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
        /* including bogus ALC268 in slot#2 that conflicts with ALC888 */
        SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
-       /* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */
-       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03),
+       /* forced codec slots */
+       SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
        {}
 };
 
+#define AZX_FORCE_CODEC_MASK   0x100
+
 static void __devinit check_probe_mask(struct azx *chip, int dev)
 {
        const struct snd_pci_quirk *q;
 
-       if (probe_mask[dev] == -1) {
+       chip->codec_probe_mask = probe_mask[dev];
+       if (chip->codec_probe_mask == -1) {
                q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
                if (q) {
                        printk(KERN_INFO
                               "hda_intel: probe_mask set to 0x%x "
                               "for device %04x:%04x\n",
                               q->value, q->subvendor, q->subdevice);
-                       probe_mask[dev] = q->value;
+                       chip->codec_probe_mask = q->value;
                }
        }
+
+       /* check forced option */
+       if (chip->codec_probe_mask != -1 &&
+           (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
+               chip->codec_mask = chip->codec_probe_mask & 0xff;
+               printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n",
+                      chip->codec_mask);
+       }
 }
 
 
@@ -2347,10 +2387,10 @@ static int __devinit azx_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (!card) {
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printk(KERN_ERR SFX "Error creating card!\n");
-               return -ENOMEM;
+               return err;
        }
 
        err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
@@ -2359,8 +2399,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        card->private_data = chip;
 
        /* create codec instances */
-       err = azx_codec_create(chip, model[dev], probe_mask[dev],
-                              probe_only[dev]);
+       err = azx_codec_create(chip, model[dev], probe_only[dev]);
        if (err < 0)
                goto out_free;
 
@@ -2457,10 +2496,10 @@ static struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
        { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
        { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
-       { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
        /* Teradici */
        { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
        /* AMD Generic, PCI class code and Vendor ID for HD Audio */
index 44f189cb97aee1f8d40f166a5a998ae0ddca61b1..83349013b4df1bcd5e8d5ea762153a1e3049920c 100644 (file)
 /*
  * for mixer controls
  */
+#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)           \
+       ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
 #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
-       ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
+       HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
 /* mono volume with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
@@ -96,7 +98,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
                                            const char *name);
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                        unsigned int *tlv, const char **slaves);
-void snd_hda_codec_reset(struct hda_codec *codec);
+int snd_hda_codec_reset(struct hda_codec *codec);
 int snd_hda_codec_configure(struct hda_codec *codec);
 
 /* amp value bits */
@@ -134,7 +136,7 @@ extern struct hda_ctl_ops snd_hda_bind_sw;  /* for bind-switch */
 
 struct hda_bind_ctls {
        struct hda_ctl_ops *ops;
-       long values[];
+       unsigned long values[];
 };
 
 int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
@@ -227,6 +229,7 @@ struct hda_multi_out {
        hda_nid_t hp_nid;       /* optional DAC for HP, 0 when not exists */
        hda_nid_t extra_out_nid[3];     /* optional DACs, 0 when not exists */
        hda_nid_t dig_out_nid;  /* digital out audio widget */
+       hda_nid_t *slave_dig_outs;
        int max_channels;       /* currently supported analog channels */
        int dig_out_used;       /* current usage of digital out (HDA_DIG_XXX) */
        int no_share_stream;    /* don't share a stream with multiple pins */
@@ -354,9 +357,12 @@ struct auto_pin_cfg {
        int line_out_type;      /* AUTO_PIN_XXX_OUT */
        hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
        hda_nid_t input_pins[AUTO_PIN_LAST];
-       hda_nid_t dig_out_pin;
+       int dig_outs;
+       hda_nid_t dig_out_pins[2];
        hda_nid_t dig_in_pin;
        hda_nid_t mono_out_pin;
+       int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
+       int dig_in_type; /* HDA_PCM_TYPE_XXX */
 };
 
 #define get_defcfg_connect(cfg) \
@@ -405,6 +411,7 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 
 int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
 void snd_hda_ctls_clear(struct hda_codec *codec);
@@ -427,6 +434,23 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
 }
 #endif
 
+#ifdef CONFIG_SND_HDA_RECONFIG
+const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
+int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
+#else
+static inline
+const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
+{
+       return NULL;
+}
+
+static inline
+int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
+{
+       return -ENOENT;
+}
+#endif
+
 /*
  * power-management
  */
@@ -458,6 +482,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
 #define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
+#define get_amp_offset(kc)     (((kc)->private_value >> 23) & 0x3f)
 
 /*
  * CEA Short Audio Descriptor data
index 144b85276d5a9431de945d75f4eda4309c4e39d7..93d7499350c6609f3e4a5a9af6396bf0ac6c8447 100644 (file)
@@ -399,8 +399,10 @@ static void print_conn_list(struct snd_info_buffer *buffer,
 {
        int c, curr = -1;
 
-       if (conn_len > 1 && wid_type != AC_WID_AUD_MIX &&
-           wid_type != AC_WID_VOL_KNB)
+       if (conn_len > 1 &&
+           wid_type != AC_WID_AUD_MIX &&
+           wid_type != AC_WID_VOL_KNB &&
+           wid_type != AC_WID_POWER)
                curr = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_CONNECT_SEL, 0);
        snd_iprintf(buffer, "  Connection: %d\n", conn_len);
@@ -467,8 +469,9 @@ static void print_codec_info(struct snd_info_entry *entry,
        snd_iprintf(buffer, "Codec: %s\n",
                    codec->name ? codec->name : "Not Set");
        snd_iprintf(buffer, "Address: %d\n", codec->addr);
-       snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
-       snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
+       snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
+       snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
+       snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
        snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
 
        if (codec->mfg)
@@ -554,8 +557,14 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "  Amp-Out caps: ");
                        print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
                        snd_iprintf(buffer, "  Amp-Out vals: ");
-                       print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                      wid_caps & AC_WCAP_STEREO, 1);
+                       if (wid_type == AC_WID_PIN &&
+                           codec->pin_amp_workaround)
+                               print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+                                              wid_caps & AC_WCAP_STEREO,
+                                              conn_len);
+                       else
+                               print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+                                              wid_caps & AC_WCAP_STEREO, 1);
                }
 
                switch (wid_type) {
index e48612323aa0f11facf58c1d9df107bca5fa3692..5bb48ee8b6c63eebfd05047c36ce7942d61e60c6 100644 (file)
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_beep.h"
 
 struct ad198x_spec {
        struct snd_kcontrol_new *mixers[5];
        int num_mixers;
-
+       unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
        const struct hda_verb *init_verbs[5];   /* initialization verbs
                                                 * don't forget NULL termination!
                                                 */
@@ -154,6 +155,16 @@ static const char *ad_slave_sws[] = {
 
 static void ad198x_free_kctls(struct hda_codec *codec);
 
+/* additional beep mixers; the actual parameters are overwritten at build */
+static struct snd_kcontrol_new ad_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT),
+       { } /* end */
+};
+
+#define set_beep_amp(spec, nid, idx, dir) \
+       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
+
 static int ad198x_build_controls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -181,6 +192,21 @@ static int ad198x_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       /* create beep controls if needed */
+       if (spec->beep_amp) {
+               struct snd_kcontrol_new *knew;
+               for (knew = ad_beep_mixer; knew->name; knew++) {
+                       struct snd_kcontrol *kctl;
+                       kctl = snd_ctl_new1(knew, codec);
+                       if (!kctl)
+                               return -ENOMEM;
+                       kctl->private_value = spec->beep_amp;
+                       err = snd_hda_ctl_add(codec, kctl);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
        /* if we have no master control, let's create it */
        if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
                unsigned int vmaster_tlv[4];
@@ -406,7 +432,8 @@ static void ad198x_free(struct hda_codec *codec)
                return;
 
        ad198x_free_kctls(codec);
-       kfree(codec->spec);
+       kfree(spec);
+       snd_hda_detach_beep_device(codec);
 }
 
 static struct hda_codec_ops ad198x_patch_ops = {
@@ -545,8 +572,6 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
@@ -610,8 +635,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+       /* 
           HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
           HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
@@ -809,8 +833,6 @@ static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
        {
@@ -1002,10 +1024,8 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
-       SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
-       SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
        SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
        SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
        SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
@@ -1027,15 +1047,14 @@ static struct hda_amp_list ad1986a_loopbacks[] = {
 
 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
 {
-       unsigned int conf = snd_hda_codec_read(codec, nid, 0,
-                                              AC_VERB_GET_CONFIG_DEFAULT, 0);
+       unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
        return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
 }
 
 static int patch_ad1986a(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
-       int board_config;
+       int err, board_config;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -1043,6 +1062,13 @@ static int patch_ad1986a(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x19);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 6;
        spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
        spec->multiout.dac_nids = ad1986a_dac_nids;
@@ -1222,8 +1248,6 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -1294,6 +1318,7 @@ static struct hda_amp_list ad1983_loopbacks[] = {
 static int patch_ad1983(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
+       int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -1301,6 +1326,13 @@ static int patch_ad1983(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
        spec->multiout.dac_nids = ad1983_dac_nids;
@@ -1370,8 +1402,6 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
@@ -1416,8 +1446,8 @@ static struct hda_verb ad1981_init_verbs[] = {
        {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
        {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
        /* Mic boost: 0dB */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Record selector: Front mic */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1682,10 +1712,10 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
        SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
        /* All HP models */
-       SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
        /* Lenovo Thinkpad T60/X60/Z6xx */
-       SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
        /* HP nx6320 (reversed SSID, H/W bug) */
        SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
        {}
@@ -1694,7 +1724,7 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = {
 static int patch_ad1981(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
-       int board_config;
+       int err, board_config;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -1702,6 +1732,13 @@ static int patch_ad1981(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
        spec->multiout.dac_nids = ad1981_dac_nids;
@@ -1988,9 +2025,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
@@ -2034,9 +2068,6 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
@@ -2066,9 +2097,6 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
@@ -2297,10 +2325,6 @@ static struct hda_verb ad1988_capture_init_verbs[] = {
        {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* ADCs; muted */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
        { }
 };
@@ -2408,10 +2432,6 @@ static struct hda_verb ad1988_3stack_init_verbs[] = {
        {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* ADCs; muted */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* Analog Mix output amp */
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
        { }
@@ -2483,10 +2503,6 @@ static struct hda_verb ad1988_laptop_init_verbs[] = {
        {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* ADCs; muted */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* Analog Mix output amp */
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
        { }
@@ -2890,7 +2906,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = AD1988_SPDIF_IN;
@@ -2940,7 +2956,7 @@ static struct snd_pci_quirk ad1988_cfg_tbl[] = {
 static int patch_ad1988(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
-       int board_config;
+       int err, board_config;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -2960,7 +2976,7 @@ static int patch_ad1988(struct hda_codec *codec)
 
        if (board_config == AD1988_AUTO) {
                /* automatic parse from the BIOS config */
-               int err = ad1988_parse_auto_config(codec);
+               err = ad1988_parse_auto_config(codec);
                if (err < 0) {
                        ad198x_free(codec);
                        return err;
@@ -2970,6 +2986,13 @@ static int patch_ad1988(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
        switch (board_config) {
        case AD1988_6STACK:
        case AD1988_6STACK_DIG:
@@ -3126,12 +3149,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       /*
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-       */
        HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3204,10 +3221,10 @@ static struct hda_verb ad1884_init_verbs[] = {
        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
        /* Port-B (front mic) pin */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Port-C (rear mic) pin */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Analog mixer; mute as default */
        {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -3240,7 +3257,7 @@ static const char *ad1884_slave_vols[] = {
        "CD Playback Volume",
        "Internal Mic Playback Volume",
        "Docking Mic Playback Volume"
-       "Beep Playback Volume",
+       /* "Beep Playback Volume", */
        "IEC958 Playback Volume",
        NULL
 };
@@ -3248,6 +3265,7 @@ static const char *ad1884_slave_vols[] = {
 static int patch_ad1884(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
+       int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -3255,6 +3273,13 @@ static int patch_ad1884(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
        spec->multiout.dac_nids = ad1884_dac_nids;
@@ -3321,8 +3346,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
        HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3358,7 +3381,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* docking mic boost */
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        /* Analog mixer - docking mic; mute as default */
        {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        /* enable EAPD bit */
@@ -3379,10 +3402,6 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
        HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
-       /*
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
-       */
        HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3468,7 +3487,7 @@ static const char *ad1984_models[AD1984_MODELS] = {
 
 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
        /* Lenovo Thinkpad T61/X61 */
-       SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
        SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
        {}
 };
@@ -3561,8 +3580,6 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
@@ -3622,10 +3639,10 @@ static struct hda_verb ad1884a_init_verbs[] = {
        {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* Port-B (front mic) pin */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Port-C (rear line-in) pin */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* Port-E (rear mic) pin */
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
@@ -3695,8 +3712,6 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
@@ -3724,8 +3739,6 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3836,8 +3849,6 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3911,9 +3922,9 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
        SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
+       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
        {}
 };
@@ -3921,7 +3932,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
 static int patch_ad1884a(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
-       int board_config;
+       int err, board_config;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -3929,6 +3940,13 @@ static int patch_ad1884a(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
        spec->multiout.dac_nids = ad1884a_dac_nids;
@@ -3966,6 +3984,14 @@ static int patch_ad1884a(struct hda_codec *codec)
                spec->multiout.dig_out_nid = 0;
                codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
                codec->patch_ops.init = ad1884a_hp_init;
+               /* set the upper-limit for mixer amp to 0dB for avoiding the
+                * possible damage by overloading
+                */
+               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
+                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (1 << AC_AMPCAP_MUTE_SHIFT));
                break;
        case AD1884A_THINKPAD:
                spec->mixers[0] = ad1984a_thinkpad_mixers;
@@ -4083,8 +4109,6 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
        { } /* end */
 };
 
@@ -4097,8 +4121,6 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
        HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -4257,7 +4279,7 @@ static const char *ad1882_models[AD1986A_MODELS] = {
 static int patch_ad1882(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
-       int board_config;
+       int err, board_config;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4265,6 +4287,13 @@ static int patch_ad1882(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       err = snd_hda_attach_beep_device(codec, 0x10);
+       if (err < 0) {
+               ad198x_free(codec);
+               return err;
+       }
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
        spec->multiout.max_channels = 6;
        spec->multiout.num_dacs = 3;
        spec->multiout.dac_nids = ad1882_dac_nids;
index f3ebe837f2d5ef46b42c1b81a8b104daffb147ed..c921264bbd719c2364e2b073d7c7db562cb8488f 100644 (file)
@@ -680,13 +680,13 @@ static int patch_cmi9880(struct hda_codec *codec)
                struct auto_pin_cfg cfg;
 
                /* collect pin default configuration */
-               port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
-               port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+               port_e = snd_hda_codec_get_pincfg(codec, 0x0f);
+               port_f = snd_hda_codec_get_pincfg(codec, 0x10);
                spec->front_panel = 1;
                if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE ||
                    get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) {
-                       port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
-                       port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       port_g = snd_hda_codec_get_pincfg(codec, 0x1f);
+                       port_h = snd_hda_codec_get_pincfg(codec, 0x20);
                        spec->channel_modes = cmi9880_channel_modes;
                        /* no front panel */
                        if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE ||
@@ -703,8 +703,8 @@ static int patch_cmi9880(struct hda_codec *codec)
                        spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
                } else {
                        spec->input_mux = &cmi9880_basic_mux;
-                       port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
-                       port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13);
+                       port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12);
                        if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE)
                                spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
                        if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE)
index 0177ef8f4c9e9f2af8206a21c307d6795e3dbbd3..1f2ad76ca94b1d077f1bd7550eae9c789a23802e 100644 (file)
@@ -58,6 +58,7 @@ struct conexant_spec {
 
        struct snd_kcontrol_new *mixers[5];
        int num_mixers;
+       hda_nid_t vmaster_nid;
 
        const struct hda_verb *init_verbs[5];   /* initialization verbs
                                                 * don't forget NULL
@@ -72,6 +73,7 @@ struct conexant_spec {
                                         */
        unsigned int cur_eapd;
        unsigned int hp_present;
+       unsigned int no_auto_mic;
        unsigned int need_dac_fix;
 
        /* capture */
@@ -461,6 +463,29 @@ static void conexant_free(struct hda_codec *codec)
        kfree(codec->spec);
 }
 
+static struct snd_kcontrol_new cxt_capture_mixers[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Source",
+               .info = conexant_mux_enum_info,
+               .get = conexant_mux_enum_get,
+               .put = conexant_mux_enum_put
+       },
+       {}
+};
+
+static const char *slave_vols[] = {
+       "Headphone Playback Volume",
+       "Speaker Playback Volume",
+       NULL
+};
+
+static const char *slave_sws[] = {
+       "Headphone Playback Switch",
+       "Speaker Playback Switch",
+       NULL
+};
+
 static int conexant_build_controls(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -488,6 +513,32 @@ static int conexant_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* if we have no master control, let's create it */
+       if (spec->vmaster_nid &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               unsigned int vmaster_tlv[4];
+               snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+                                       HDA_OUTPUT, vmaster_tlv);
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         vmaster_tlv, slave_vols);
+               if (err < 0)
+                       return err;
+       }
+       if (spec->vmaster_nid &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                         NULL, slave_sws);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->input_mux) {
+               err = snd_hda_add_new_ctls(codec, cxt_capture_mixers);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -719,13 +770,6 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
 }
 
 static struct snd_kcontrol_new cxt5045_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = conexant_mux_enum_info,
-               .get = conexant_mux_enum_get,
-               .put = conexant_mux_enum_put
-       },
        HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
@@ -759,13 +803,6 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 };
 
 static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = conexant_mux_enum_info,
-               .get = conexant_mux_enum_get,
-               .put = conexant_mux_enum_put
-       },
        HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
@@ -1002,15 +1039,9 @@ static const char *cxt5045_models[CXT5045_MODELS] = {
 };
 
 static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
-       SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
        SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
-       SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
+                          CXT5045_LAPTOP_HPSENSE),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
@@ -1020,8 +1051,8 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
-       SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
-       SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell",
+                          CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE),
        {}
 };
@@ -1035,6 +1066,7 @@ static int patch_cxt5045(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       codec->pin_amp_workaround = 1;
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
@@ -1134,7 +1166,7 @@ static int patch_cxt5045(struct hda_codec *codec)
 /* Conexant 5047 specific */
 #define CXT5047_SPDIF_OUT      0x11
 
-static hda_nid_t cxt5047_dac_nids[2] = { 0x10, 0x1c };
+static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
 static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
 static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
 
@@ -1142,20 +1174,6 @@ static struct hda_channel_mode cxt5047_modes[1] = {
        { 2, NULL },
 };
 
-static struct hda_input_mux cxt5047_capture_source = {
-       .num_items = 1,
-       .items = {
-               { "Mic", 0x2 },
-       }
-};
-
-static struct hda_input_mux cxt5047_hp_capture_source = {
-       .num_items = 1,
-       .items = {
-               { "ExtMic", 0x2 },
-       }
-};
-
 static struct hda_input_mux cxt5047_toshiba_capture_source = {
        .num_items = 2,
        .items = {
@@ -1179,7 +1197,11 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
         * the headphone jack
         */
        bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE;
-       snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
+       /* NOTE: Conexat codec needs the index for *OUTPUT* amp of
+        * pin widgets unlike other codecs.  In this case, we need to
+        * set index 0x01 for the volume from the mixer amp 0x19.
+        */
+       snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
                                 HDA_AMP_MUTE, bits);
        bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE;
        snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
@@ -1187,16 +1209,6 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-/* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */
-static struct hda_bind_ctls cxt5047_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
 /* mute internal speaker if HP is plugged */
 static void cxt5047_hp_automute(struct hda_codec *codec)
 {
@@ -1207,27 +1219,8 @@ static void cxt5047_hp_automute(struct hda_codec *codec)
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 
        bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       /* Mute/Unmute PCM 2 for good measure - some systems need this */
-       snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
-
-/* mute internal speaker if HP is plugged */
-static void cxt5047_hp2_automute(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       unsigned int bits;
-
-       spec->hp_present = snd_hda_codec_read(codec, 0x13, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-
-       bits = spec->hp_present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       /* Mute/Unmute PCM 2 for good measure - some systems need this */
-       snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0,
+       /* See the note in cxt5047_hp_master_sw_put */
+       snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
                                 HDA_AMP_MUTE, bits);
 }
 
@@ -1268,55 +1261,14 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
        }
 }
 
-/* unsolicited event for HP jack sensing - non-EAPD systems */
-static void cxt5047_hp2_unsol_event(struct hda_codec *codec,
-                                 unsigned int res)
-{
-       res >>= 26;
-       switch (res) {
-       case CONEXANT_HP_EVENT:
-               cxt5047_hp2_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
-               cxt5047_hp_automic(codec);
-               break;
-       }
-}
-
-static struct snd_kcontrol_new cxt5047_mixers[] = {
-       HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Gain Volume", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Gain Switch", 0x1a, 0x0, HDA_OUTPUT),
+static struct snd_kcontrol_new cxt5047_base_mixers[] = {
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
        HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x13, 0x00, HDA_OUTPUT),
-
-       {}
-};
-
-static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = conexant_mux_enum_info,
-               .get = conexant_mux_enum_get,
-               .put = conexant_mux_enum_put
-       },
-       HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
-       HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
@@ -1329,29 +1281,15 @@ static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = {
        {}
 };
 
-static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = conexant_mux_enum_info,
-               .get = conexant_mux_enum_get,
-               .put = conexant_mux_enum_put
-       },
-       HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
+       /* See the note in cxt5047_hp_master_sw_put */
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+       {}
+};
+
+static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = cxt_eapd_info,
-               .get = cxt_eapd_get,
-               .put = cxt5047_hp_master_sw_put,
-               .private_value = 0x13,
-       },
        { } /* end */
 };
 
@@ -1362,8 +1300,8 @@ static struct hda_verb cxt5047_init_verbs[] = {
        {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
        /* HP, Speaker  */
        {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       {0x13, AC_VERB_SET_CONNECT_SEL,0x1},
-       {0x1d, AC_VERB_SET_CONNECT_SEL,0x0},
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */
        /* Record selector: Mic */
        {0x12, AC_VERB_SET_CONNECT_SEL,0x03},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -1383,30 +1321,7 @@ static struct hda_verb cxt5047_init_verbs[] = {
 
 /* configuration for Toshiba Laptops */
 static struct hda_verb cxt5047_toshiba_init_verbs[] = {
-       {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
-       /* pin sensing on HP and Mic jacks */
-       {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
-       /* Speaker routing */
-       {0x1d, AC_VERB_SET_CONNECT_SEL,0x1},
-       {}
-};
-
-/* configuration for HP Laptops */
-static struct hda_verb cxt5047_hp_init_verbs[] = {
-       /* pin sensing on HP jack */
-       {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
-       /* 0x13 is actually shared by both HP and speaker;
-        * setting the connection to 0 (=0x19) makes the master volume control
-        * working mysteriouslly...
-        */
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Record selector: Ext Mic */
-       {0x12, AC_VERB_SET_CONNECT_SEL,0x03},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE,
-        AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
-       /* Speaker routing */
-       {0x1d, AC_VERB_SET_CONNECT_SEL,0x1},
+       {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
        {}
 };
 
@@ -1571,11 +1486,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = {
 };
 
 static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
-       SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
+                          CXT5047_LAPTOP),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
        {}
 };
@@ -1589,6 +1502,7 @@ static int patch_cxt5047(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       codec->pin_amp_workaround = 1;
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
@@ -1597,9 +1511,8 @@ static int patch_cxt5047(struct hda_codec *codec)
        spec->num_adc_nids = 1;
        spec->adc_nids = cxt5047_adc_nids;
        spec->capsrc_nids = cxt5047_capsrc_nids;
-       spec->input_mux = &cxt5047_capture_source;
        spec->num_mixers = 1;
-       spec->mixers[0] = cxt5047_mixers;
+       spec->mixers[0] = cxt5047_base_mixers;
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = cxt5047_init_verbs;
        spec->spdif_route = 0;
@@ -1613,21 +1526,22 @@ static int patch_cxt5047(struct hda_codec *codec)
                                                  cxt5047_cfg_tbl);
        switch (board_config) {
        case CXT5047_LAPTOP:
-               codec->patch_ops.unsol_event = cxt5047_hp2_unsol_event;
+               spec->num_mixers = 2;
+               spec->mixers[1] = cxt5047_hp_spk_mixers;
+               codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
                break;
        case CXT5047_LAPTOP_HP:
-               spec->input_mux = &cxt5047_hp_capture_source;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = cxt5047_hp_init_verbs;
-               spec->mixers[0] = cxt5047_hp_mixers;
+               spec->num_mixers = 2;
+               spec->mixers[1] = cxt5047_hp_only_mixers;
                codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
                codec->patch_ops.init = cxt5047_hp_init;
                break;
        case CXT5047_LAPTOP_EAPD:
                spec->input_mux = &cxt5047_toshiba_capture_source;
+               spec->num_mixers = 2;
+               spec->mixers[1] = cxt5047_hp_spk_mixers;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
-               spec->mixers[0] = cxt5047_toshiba_mixers;
                codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
                break;
 #ifdef CONFIG_SND_DEBUG
@@ -1638,6 +1552,7 @@ static int patch_cxt5047(struct hda_codec *codec)
                codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
 #endif 
        }
+       spec->vmaster_nid = 0x13;
        return 0;
 }
 
@@ -1673,8 +1588,11 @@ static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 /* toggle input of built-in and mic jack appropriately */
 static void cxt5051_portb_automic(struct hda_codec *codec)
 {
+       struct conexant_spec *spec = codec->spec;
        unsigned int present;
 
+       if (spec->no_auto_mic)
+               return;
        present = snd_hda_codec_read(codec, 0x17, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) &
                AC_PINSENSE_PRESENCE;
@@ -1690,6 +1608,8 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
        unsigned int present;
        hda_nid_t new_adc;
 
+       if (spec->no_auto_mic)
+               return;
        present = snd_hda_codec_read(codec, 0x18, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) &
                AC_PINSENSE_PRESENCE;
@@ -1776,6 +1696,22 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
        {}
 };
 
+static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
+       HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = cxt_eapd_info,
+               .get = cxt_eapd_get,
+               .put = cxt5051_hp_master_sw_put,
+               .private_value = 0x1a,
+       },
+
+       {}
+};
+
 static struct hda_verb cxt5051_init_verbs[] = {
        /* Line in, Mic */
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
@@ -1806,6 +1742,66 @@ static struct hda_verb cxt5051_init_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
+       /* Line in, Mic */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
+       /* SPK  */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP, Amp  */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Record selector: Int mic */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* SPDIF route: PCM */
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* EAPD */
+       {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
+       { } /* end */
+};
+
+static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
+       /* Line in, Mic */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       /* SPK  */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP, Amp  */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Docking HP */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Record selector: Int mic */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+       /* SPDIF route: PCM */
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* EAPD */
+       {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+       { } /* end */
+};
+
 /* initialize jack-sensing, too */
 static int cxt5051_init(struct hda_codec *codec)
 {
@@ -1823,18 +1819,24 @@ static int cxt5051_init(struct hda_codec *codec)
 enum {
        CXT5051_LAPTOP,  /* Laptops w/ EAPD support */
        CXT5051_HP,     /* no docking */
+       CXT5051_HP_DV6736,      /* HP without mic switch */
+       CXT5051_LENOVO_X200,    /* Lenovo X200 laptop */
        CXT5051_MODELS
 };
 
 static const char *cxt5051_models[CXT5051_MODELS] = {
        [CXT5051_LAPTOP]        = "laptop",
        [CXT5051_HP]            = "hp",
+       [CXT5051_HP_DV6736]     = "hp-dv6736",
+       [CXT5051_LENOVO_X200]   = "lenovo-x200",
 };
 
 static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
        SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
                      CXT5051_LAPTOP),
        SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
+       SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
        {}
 };
 
@@ -1847,6 +1849,7 @@ static int patch_cxt5051(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       codec->pin_amp_workaround = 1;
 
        codec->patch_ops = conexant_patch_ops;
        codec->patch_ops.init = cxt5051_init;
@@ -1867,17 +1870,22 @@ static int patch_cxt5051(struct hda_codec *codec)
        spec->cur_adc = 0;
        spec->cur_adc_idx = 0;
 
+       codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+
        board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
                                                  cxt5051_models,
                                                  cxt5051_cfg_tbl);
        switch (board_config) {
        case CXT5051_HP:
-               codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
                spec->mixers[0] = cxt5051_hp_mixers;
                break;
-       default:
-       case CXT5051_LAPTOP:
-               codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+       case CXT5051_HP_DV6736:
+               spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
+               spec->mixers[0] = cxt5051_hp_dv6736_mixers;
+               spec->no_auto_mic = 1;
+               break;
+       case CXT5051_LENOVO_X200:
+               spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
                break;
        }
 
index 6c26afcb82622d7b0e994f69c334cec8ef90bf33..82097790f6f322a62e83b757e53451a0684b96f7 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_beep.h"
 
 #define ALC880_FRONT_EVENT             0x01
 #define ALC880_DCVOL_EVENT             0x02
@@ -77,6 +78,7 @@ enum {
        ALC260_ACER,
        ALC260_WILL,
        ALC260_REPLACER_672V,
+       ALC260_FAVORIT100,
 #ifdef CONFIG_SND_DEBUG
        ALC260_TEST,
 #endif
@@ -103,6 +105,7 @@ enum {
        ALC262_NEC,
        ALC262_TOSHIBA_S06,
        ALC262_TOSHIBA_RX1,
+       ALC262_TYAN,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -238,6 +241,13 @@ enum {
        ALC883_MODEL_LAST,
 };
 
+/* styles of capture selection */
+enum {
+       CAPT_MUX = 0,   /* only mux based */
+       CAPT_MIX,       /* only mixer based */
+       CAPT_1MUX_MIX,  /* first mux and other mixers */
+};
+
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -246,6 +256,7 @@ struct alc_spec {
        struct snd_kcontrol_new *mixers[5];     /* mixer arrays */
        unsigned int num_mixers;
        struct snd_kcontrol_new *cap_mixer;     /* capture mixer */
+       unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
 
        const struct hda_verb *init_verbs[5];   /* initialization verbs
                                                 * don't forget NULL
@@ -269,13 +280,15 @@ struct alc_spec {
                                         * dig_out_nid and hp_nid are optional
                                         */
        hda_nid_t alt_dac_nid;
+       hda_nid_t slave_dig_outs[3];    /* optional - for auto-parsing */
+       int dig_out_type;
 
        /* capture */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
        hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-       unsigned char is_mix_capture;   /* matrix-style capture (non-mux) */
+       int capture_style;              /* capture style (CAPT_*) */
 
        /* capture source */
        unsigned int num_mux_defs;
@@ -293,7 +306,7 @@ struct alc_spec {
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct snd_array kctls;
-       struct hda_input_mux private_imux;
+       struct hda_input_mux private_imux[3];
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        /* hooks */
@@ -305,6 +318,9 @@ struct alc_spec {
        unsigned int jack_present: 1;
        unsigned int master_sw: 1;
 
+       /* other flags */
+       unsigned int no_analog :1; /* digital I/O only */
+
        /* for virtual master */
        hda_nid_t vmaster_nid;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -314,13 +330,6 @@ struct alc_spec {
        /* for PLL fix */
        hda_nid_t pll_nid;
        unsigned int pll_coef_idx, pll_coef_bit;
-
-#ifdef SND_HDA_NEEDS_RESUME
-#define ALC_MAX_PINS   16
-       unsigned int num_pins;
-       hda_nid_t pin_nids[ALC_MAX_PINS];
-       unsigned int pin_cfgs[ALC_MAX_PINS];
-#endif
 };
 
 /*
@@ -336,6 +345,7 @@ struct alc_config_preset {
        hda_nid_t *dac_nids;
        hda_nid_t dig_out_nid;          /* optional */
        hda_nid_t hp_nid;               /* optional */
+       hda_nid_t *slave_dig_outs;
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
        hda_nid_t *capsrc_nids;
@@ -392,7 +402,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
 
-       if (spec->is_mix_capture) {
+       if (spec->capture_style &&
+           !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
                /* Matrix-mixer style (e.g. ALC882) */
                unsigned int *cur_val = &spec->cur_mux[adc_idx];
                unsigned int i, idx;
@@ -749,6 +760,24 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
          .private_value = nid | (mask<<16) }
 #endif   /* CONFIG_SND_DEBUG */
 
+/*
+ * set up the input pin config (depending on the given auto-pin type)
+ */
+static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
+                             int auto_pin_type)
+{
+       unsigned int val = PIN_IN;
+
+       if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+               unsigned int pincap;
+               pincap = snd_hda_query_pin_caps(codec, nid);
+               pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+               if (pincap & AC_PINCAP_VREF_80)
+                       val = PIN_VREF80;
+       }
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+}
+
 /*
  */
 static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
@@ -810,6 +839,7 @@ static void setup_preset(struct alc_spec *spec,
        spec->multiout.num_dacs = preset->num_dacs;
        spec->multiout.dac_nids = preset->dac_nids;
        spec->multiout.dig_out_nid = preset->dig_out_nid;
+       spec->multiout.slave_dig_outs = preset->slave_dig_outs;
        spec->multiout.hp_nid = preset->hp_nid;
 
        spec->num_mux_defs = preset->num_mux_defs;
@@ -921,7 +951,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                         HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 #else
-#define alc_mic_automute(codec) /* NOP */
+#define alc_mic_automute(codec) do {} while(0) /* NOP */
 #endif /* disabled */
 
 /* unsolicited event for HP jack sensing */
@@ -952,7 +982,7 @@ static void alc888_coef_init(struct hda_codec *codec)
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
        tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       if ((tmp & 0xf0) == 2)
+       if ((tmp & 0xf0) == 0x20)
                /* alc888S-VC */
                snd_hda_codec_read(codec, 0x20, 0,
                                   AC_VERB_SET_PROC_COEF, 0x830);
@@ -991,8 +1021,7 @@ static void alc_subsystem_id(struct hda_codec *codec,
        nid = 0x1d;
        if (codec->vendor_id == 0x10ec0260)
                nid = 0x17;
-       ass = snd_hda_codec_read(codec, nid, 0,
-                                AC_VERB_GET_CONFIG_DEFAULT, 0);
+       ass = snd_hda_codec_get_pincfg(codec, nid);
        if (!(ass & 1) && !(ass & 0x100000))
                return;
        if ((ass >> 30) != 1)   /* no physical connection */
@@ -1166,16 +1195,8 @@ static void alc_fix_pincfg(struct hda_codec *codec,
                return;
 
        cfg = pinfix[quirk->value];
-       for (; cfg->nid; cfg++) {
-               int i;
-               u32 val = cfg->val;
-               for (i = 0; i < 4; i++) {
-                       snd_hda_codec_write(codec, cfg->nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
-                                   val & 0xff);
-                       val >>= 8;
-               }
-       }
+       for (; cfg->nid; cfg++)
+               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
 }
 
 /*
@@ -1375,8 +1396,6 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -1483,8 +1502,6 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1578,8 +1595,7 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
                                     snd_hda_mixer_amp_switch_put);
 }
 
-#define DEFINE_CAPMIX(num) \
-static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+#define _DEFINE_CAPMIX(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name = "Capture Switch", \
@@ -1600,7 +1616,9 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .get = alc_cap_vol_get, \
                .put = alc_cap_vol_put, \
                .tlv = { .c = alc_cap_vol_tlv }, \
-       }, \
+       }
+
+#define _DEFINE_CAPSRC(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                /* .name = "Capture Source", */ \
@@ -1609,15 +1627,28 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .info = alc_mux_enum_info, \
                .get = alc_mux_enum_get, \
                .put = alc_mux_enum_put, \
-       }, \
-       { } /* end */ \
+       }
+
+#define DEFINE_CAPMIX(num) \
+static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+       _DEFINE_CAPMIX(num),                                  \
+       _DEFINE_CAPSRC(num),                                  \
+       { } /* end */                                         \
+}
+
+#define DEFINE_CAPMIX_NOSRC(num) \
+static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+       _DEFINE_CAPMIX(num),                                        \
+       { } /* end */                                               \
 }
 
 /* up to three ADCs */
 DEFINE_CAPMIX(1);
 DEFINE_CAPMIX(2);
 DEFINE_CAPMIX(3);
-
+DEFINE_CAPMIX_NOSRC(1);
+DEFINE_CAPMIX_NOSRC(2);
+DEFINE_CAPMIX_NOSRC(3);
 
 /*
  * ALC880 5-stack model
@@ -1706,8 +1737,6 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Channel Mode",
@@ -1884,13 +1913,6 @@ static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
        { } /* end */
 };
 
-/* additional mixers to alc880_asus_mixer */
-static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-       { } /* end */
-};
-
 /* TCL S700 */
 static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -1923,8 +1945,6 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Channel Mode",
@@ -1999,6 +2019,13 @@ static const char *alc_slave_sws[] = {
 
 static void alc_free_kctls(struct hda_codec *codec);
 
+/* additional beep mixers; the actual parameters are overwritten at build */
+static struct snd_kcontrol_new alc_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
+       { } /* end */
+};
+
 static int alc_build_controls(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -2020,11 +2047,13 @@ static int alc_build_controls(struct hda_codec *codec)
                                                    spec->multiout.dig_out_nid);
                if (err < 0)
                        return err;
-               err = snd_hda_create_spdif_share_sw(codec,
-                                                   &spec->multiout);
-               if (err < 0)
-                       return err;
-               spec->multiout.share_spdif = 1;
+               if (!spec->no_analog) {
+                       err = snd_hda_create_spdif_share_sw(codec,
+                                                           &spec->multiout);
+                       if (err < 0)
+                               return err;
+                       spec->multiout.share_spdif = 1;
+               }
        }
        if (spec->dig_in_nid) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -2032,8 +2061,24 @@ static int alc_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       /* create beep controls if needed */
+       if (spec->beep_amp) {
+               struct snd_kcontrol_new *knew;
+               for (knew = alc_beep_mixer; knew->name; knew++) {
+                       struct snd_kcontrol *kctl;
+                       kctl = snd_ctl_new1(knew, codec);
+                       if (!kctl)
+                               return -ENOMEM;
+                       kctl->private_value = spec->beep_amp;
+                       err = snd_hda_ctl_add(codec, kctl);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
        /* if we have no master control, let's create it */
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+       if (!spec->no_analog &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
                unsigned int vmaster_tlv[4];
                snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
                                        HDA_OUTPUT, vmaster_tlv);
@@ -2042,7 +2087,8 @@ static int alc_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+       if (!spec->no_analog &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
                err = snd_hda_add_vmaster(codec, "Master Playback Switch",
                                          NULL, alc_slave_sws);
                if (err < 0)
@@ -2951,6 +2997,14 @@ static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                             stream_tag, format, substream);
 }
 
+static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
 static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
                                         struct hda_codec *codec,
                                         struct snd_pcm_substream *substream)
@@ -3034,7 +3088,8 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = {
        .ops = {
                .open = alc880_dig_playback_pcm_open,
                .close = alc880_dig_playback_pcm_close,
-               .prepare = alc880_dig_playback_pcm_prepare
+               .prepare = alc880_dig_playback_pcm_prepare,
+               .cleanup = alc880_dig_playback_pcm_cleanup
        },
 };
 
@@ -3061,6 +3116,9 @@ static int alc_build_pcms(struct hda_codec *codec)
        codec->num_pcms = 1;
        codec->pcm_info = info;
 
+       if (spec->no_analog)
+               goto skip_analog;
+
        info->name = spec->stream_name_analog;
        if (spec->stream_analog_playback) {
                if (snd_BUG_ON(!spec->multiout.dac_nids))
@@ -3084,12 +3142,17 @@ static int alc_build_pcms(struct hda_codec *codec)
                }
        }
 
+ skip_analog:
        /* SPDIF for stream index #1 */
        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
                codec->num_pcms = 2;
+               codec->slave_dig_outs = spec->multiout.slave_dig_outs;
                info = spec->pcm_rec + 1;
                info->name = spec->stream_name_digital;
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               if (spec->dig_out_type)
+                       info->pcm_type = spec->dig_out_type;
+               else
+                       info->pcm_type = HDA_PCM_TYPE_SPDIF;
                if (spec->multiout.dig_out_nid &&
                    spec->stream_digital_playback) {
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
@@ -3104,6 +3167,9 @@ static int alc_build_pcms(struct hda_codec *codec)
                codec->spdif_status_reset = 1;
        }
 
+       if (spec->no_analog)
+               return 0;
+
        /* If the use of more than one ADC is requested for the current
         * model, configure a second analog capture-only PCM.
         */
@@ -3162,65 +3228,17 @@ static void alc_free(struct hda_codec *codec)
 
        alc_free_kctls(codec);
        kfree(spec);
-       codec->spec = NULL; /* to be sure */
+       snd_hda_detach_beep_device(codec);
 }
 
 #ifdef SND_HDA_NEEDS_RESUME
-static void store_pin_configs(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid, end_nid;
-
-       end_nid = codec->start_nid + codec->num_nodes;
-       for (nid = codec->start_nid; nid < end_nid; nid++) {
-               unsigned int wid_caps = get_wcaps(codec, nid);
-               unsigned int wid_type =
-                       (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-               if (wid_type != AC_WID_PIN)
-                       continue;
-               if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
-                       break;
-               spec->pin_nids[spec->num_pins] = nid;
-               spec->pin_cfgs[spec->num_pins] =
-                       snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_GET_CONFIG_DEFAULT, 0);
-               spec->num_pins++;
-       }
-}
-
-static void resume_pin_configs(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               hda_nid_t pin_nid = spec->pin_nids[i];
-               unsigned int pin_config = spec->pin_cfgs[i];
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                                   pin_config & 0x000000ff);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                                   (pin_config & 0x0000ff00) >> 8);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                                   (pin_config & 0x00ff0000) >> 16);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                   pin_config >> 24);
-       }
-}
-
 static int alc_resume(struct hda_codec *codec)
 {
-       resume_pin_configs(codec);
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        return 0;
 }
-#else
-#define store_pin_configs(codec)
 #endif
 
 /*
@@ -3559,7 +3577,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
        SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
        SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-       SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
        SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
        SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
        SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
@@ -3602,7 +3620,8 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
+       /* default Intel */
+       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
        SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
        {}
@@ -3782,7 +3801,7 @@ static struct alc_config_preset alc880_presets[] = {
                .input_mux = &alc880_capture_source,
        },
        [ALC880_UNIWILL_DIG] = {
-               .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
+               .mixers = { alc880_asus_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_pin_asus_init_verbs },
                .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
@@ -3820,8 +3839,7 @@ static struct alc_config_preset alc880_presets[] = {
                .init_hook = alc880_uniwill_p53_hp_automute,
        },
        [ALC880_FUJITSU] = {
-               .mixers = { alc880_fujitsu_mixer,
-                           alc880_pcbeep_mixer, },
+               .mixers = { alc880_fujitsu_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_uniwill_p53_init_verbs,
                                alc880_beep_init_verbs },
@@ -4114,7 +4132,7 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
 static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -4202,11 +4220,9 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc880_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-                       if (nid != ALC880_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC880_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -4221,7 +4237,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
 static int alc880_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
+       int i, err;
        static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -4252,8 +4268,23 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
-               spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+       /* check multiple SPDIF-out (for recent codecs) */
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t dig_nid;
+               err = snd_hda_get_connections(codec,
+                                             spec->autocfg.dig_out_pins[i],
+                                             &dig_nid, 1);
+               if (err < 0)
+                       continue;
+               if (!i)
+                       spec->multiout.dig_out_nid = dig_nid;
+               else {
+                       spec->multiout.slave_dig_outs = spec->slave_dig_outs;
+                       spec->slave_dig_outs[i - 1] = dig_nid;
+                       if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
+                               break;
+               }
+       }
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = ALC880_DIGIN_NID;
 
@@ -4263,9 +4294,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc880_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -4280,21 +4310,33 @@ static void alc880_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
-/*
- * OK, here we have finally the patch for ALC880
- */
-
 static void set_capture_mixer(struct alc_spec *spec)
 {
-       static struct snd_kcontrol_new *caps[3] = {
-               alc_capture_mixer1,
-               alc_capture_mixer2,
-               alc_capture_mixer3,
+       static struct snd_kcontrol_new *caps[2][3] = {
+               { alc_capture_mixer_nosrc1,
+                 alc_capture_mixer_nosrc2,
+                 alc_capture_mixer_nosrc3 },
+               { alc_capture_mixer1,
+                 alc_capture_mixer2,
+                 alc_capture_mixer3 },
        };
-       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
-               spec->cap_mixer = caps[spec->num_adc_nids - 1];
+       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
+               int mux;
+               if (spec->input_mux && spec->input_mux->num_items > 1)
+                       mux = 1;
+               else
+                       mux = 0;
+               spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
+       }
 }
 
+#define set_beep_amp(spec, nid, idx, dir) \
+       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+/*
+ * OK, here we have finally the patch for ALC880
+ */
+
 static int patch_alc880(struct hda_codec *codec)
 {
        struct alc_spec *spec;
@@ -4330,6 +4372,12 @@ static int patch_alc880(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC880_AUTO)
                setup_preset(spec, &alc880_presets[board_config]);
 
@@ -4356,6 +4404,7 @@ static int patch_alc880(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -4463,6 +4512,26 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = {
                },
        },
 };
+
+/* Maxdata Favorit 100XS */
+static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
+       {
+               .num_items = 2,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+               },
+       },
+       {
+               .num_items = 3,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+                       { "Mixer", 0x5 },
+               },
+       },
+};
+
 /*
  * This is just place-holder, so there's something for alc_build_pcms to look
  * at when it calculates the maximum number of channels. ALC260 has no mixer
@@ -4505,12 +4574,6 @@ static struct snd_kcontrol_new alc260_input_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
-       { } /* end */
-};
-
 /* update HP, line and mono out pins according to the master switch */
 static void alc260_hp_master_update(struct hda_codec *codec,
                                    hda_nid_t hp, hda_nid_t line,
@@ -4702,8 +4765,6 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
        HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
        ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
        { } /* end */
@@ -4748,8 +4809,18 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
        ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
+       { } /* end */
+};
+
+/* Maxdata Favorit 100XS: one output and one input (0x12) jack
+ */
+static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+       ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
        { } /* end */
 };
 
@@ -4767,8 +4838,6 @@ static struct snd_kcontrol_new alc260_will_mixer[] = {
        ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -5126,6 +5195,89 @@ static struct hda_verb alc260_acer_init_verbs[] = {
        { }
 };
 
+/* Initialisation sequence for Maxdata Favorit 100XS
+ * (adapted from Acer init verbs).
+ */
+static struct hda_verb alc260_favorit100_init_verbs[] = {
+       /* GPIO 0 enables the output jack.
+        * Turn this on and rely on the standard mute
+        * methods whenever the user wants to turn these outputs off.
+        */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+       /* Line/Mic input jack is connected to Mic1 pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       /* Ensure all other unused pins are disabled and muted. */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Disable digital (SPDIF) pins */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
+        * bus when acting as outputs.
+        */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute Line-out pin widget amp left and right
+        * (no equiv mixer ctrl)
+        */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
+        * inputs. If the pin mode is changed by the user the pin mode control
+        * will take care of enabling the pin's input/output buffers as needed.
+        * Therefore there's no need to enable the input buffer at this
+        * stage.
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting - mic
+        * (on mic1 pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do similar with the second ADC: mute capture input amp and
+        * set ADC connection to mic to match ALSA's default state.
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+
 static struct hda_verb alc260_will_verbs[] = {
        {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -5272,8 +5424,6 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
        HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
@@ -5471,7 +5621,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -5546,11 +5696,9 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (nid >= 0x12) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-                       if (nid != ALC260_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC260_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -5623,7 +5771,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
@@ -5631,9 +5779,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc260_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -5670,6 +5817,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
        [ALC260_ACER]           = "acer",
        [ALC260_WILL]           = "will",
        [ALC260_REPLACER_672V]  = "replacer",
+       [ALC260_FAVORIT100]     = "favorit100",
 #ifdef CONFIG_SND_DEBUG
        [ALC260_TEST]           = "test",
 #endif
@@ -5679,6 +5827,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
 static struct snd_pci_quirk alc260_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
        SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
+       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
        SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
@@ -5701,8 +5850,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
 static struct alc_config_preset alc260_presets[] = {
        [ALC260_BASIC] = {
                .mixers = { alc260_base_output_mixer,
-                           alc260_input_mixer,
-                           alc260_pc_beep_mixer },
+                           alc260_input_mixer },
                .init_verbs = { alc260_init_verbs },
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
@@ -5781,6 +5929,18 @@ static struct alc_config_preset alc260_presets[] = {
                .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
                .input_mux = alc260_acer_capture_sources,
        },
+       [ALC260_FAVORIT100] = {
+               .mixers = { alc260_favorit100_mixer },
+               .init_verbs = { alc260_favorit100_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
+               .input_mux = alc260_favorit100_capture_sources,
+       },
        [ALC260_WILL] = {
                .mixers = { alc260_will_mixer },
                .init_verbs = { alc260_init_verbs, alc260_will_verbs },
@@ -5857,6 +6017,12 @@ static int patch_alc260(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC260_AUTO)
                setup_preset(spec, &alc260_presets[board_config]);
 
@@ -5882,6 +6048,7 @@ static int patch_alc260(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x08;
 
@@ -6053,8 +6220,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6081,8 +6246,6 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6134,8 +6297,6 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6244,8 +6405,10 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       /* FIXME: this looks suspicious...
        HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       */
        { } /* end */
 };
 
@@ -6877,19 +7040,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               unsigned int vref;
                if (!nid)
                        continue;
-               vref = PIN_IN;
-               if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
-                       unsigned int pincap;
-                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-                       if ((pincap >> AC_PINCAP_VREF_SHIFT) &
-                           AC_PINCAP_VREF_80)
-                               vref = PIN_VREF80;
-               }
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
+               alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -6900,18 +7053,21 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
 static void alc882_auto_init_input_src(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
        int c;
 
        for (c = 0; c < spec->num_adc_nids; c++) {
                hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
                hda_nid_t nid = spec->capsrc_nids[c];
+               unsigned int mux_idx;
+               const struct hda_input_mux *imux;
                int conns, mute, idx, item;
 
                conns = snd_hda_get_connections(codec, nid, conn_list,
                                                ARRAY_SIZE(conn_list));
                if (conns < 0)
                        continue;
+               mux_idx = c >= spec->num_mux_defs ? 0 : c;
+               imux = &spec->input_mux[mux_idx];
                for (idx = 0; idx < conns; idx++) {
                        /* if the current connection is the selected one,
                         * unmute it as default - otherwise mute it
@@ -6924,8 +7080,20 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
                                        break;
                                }
                        }
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE, mute);
+                       /* check if we have a selector or mixer
+                        * we could check for the widget type instead, but
+                        * just check for Amp-In presence (in case of mixer
+                        * without amp-in there is something wrong, this
+                        * function shouldn't be used or capsrc nid is wrong)
+                        */
+                       if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                                   mute);
+                       else if (mute != AMP_IN_MUTE(idx))
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_CONNECT_SEL,
+                                                   idx);
                }
        }
 }
@@ -7054,6 +7222,12 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
@@ -7074,7 +7248,7 @@ static int patch_alc882(struct hda_codec *codec)
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
        spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
-       spec->is_mix_capture = 1; /* matrix-style capture */
+       spec->capture_style = CAPT_MIX; /* matrix-style capture */
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -7091,6 +7265,7 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -7142,10 +7317,14 @@ static hda_nid_t alc883_adc_nids_rev[2] = {
        0x09, 0x08
 };
 
+#define alc889_adc_nids                alc880_adc_nids
+
 static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
 
 static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
 
+#define alc889_capsrc_nids     alc882_capsrc_nids
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -7363,8 +7542,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7427,8 +7604,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7452,8 +7627,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7478,8 +7651,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7503,8 +7674,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7912,36 +8081,83 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_6st_dell_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static void alc888_3st_hp_front_automute(struct hda_codec *codec)
+{
+       unsigned int present, bits;
+
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
+                                     unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc888_3st_hp_front_automute(codec);
+               break;
+       }
+}
+
 static struct hda_verb alc888_3st_hp_verbs[] = {
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
        {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
-       { }
-};
-
-static struct hda_verb alc888_6st_dell_verbs[] = {
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
+       { } /* end */
 };
 
+/*
+ * 2ch mode
+ */
 static struct hda_verb alc888_3st_hp_2ch_init[] = {
        { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
        { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
        { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { }
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc888_3st_hp_4ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
 };
 
+/*
+ * 6ch mode
+ */
 static struct hda_verb alc888_3st_hp_6ch_init[] = {
        { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
        { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { }
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
 };
 
-static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+static struct hda_channel_mode alc888_3st_hp_modes[3] = {
        { 2, alc888_3st_hp_2ch_init },
+       { 4, alc888_3st_hp_4ch_init },
        { 6, alc888_3st_hp_6ch_init },
 };
 
@@ -8202,7 +8418,7 @@ static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
 {
        switch (res >> 26) {
        case ALC880_HP_EVENT:
-               printk("hp_event\n");
+               /* printk(KERN_DEBUG "hp_event\n"); */
                alc888_6st_dell_front_automute(codec);
                break;
        }
@@ -8461,6 +8677,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
@@ -8468,17 +8685,21 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
                ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
+       SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
+       /* default Acer */
+       SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
        SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
@@ -8518,7 +8739,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
        SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
        SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
@@ -8543,6 +8764,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        {}
 };
 
+static hda_nid_t alc1200_slave_dig_outs[] = {
+       ALC883_DIGOUT_NID, 0,
+};
+
 static struct alc_config_preset alc883_presets[] = {
        [ALC883_3ST_2ch_DIG] = {
                .mixers = { alc883_3ST_2ch_mixer },
@@ -8778,6 +9003,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
+               .unsol_event = alc888_3st_hp_unsol_event,
+               .init_hook = alc888_3st_hp_front_automute,
        },
        [ALC888_6ST_DELL] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -8883,6 +9110,7 @@ static struct alc_config_preset alc883_presets[] = {
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC1200_DIGOUT_NID,
                .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc1200_slave_dig_outs,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
@@ -8950,11 +9178,9 @@ static void alc883_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc883_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           (i <= AUTO_PIN_FRONT_MIC ?
-                                            PIN_VREF80 : PIN_IN));
-                       if (nid != ALC883_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC883_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -8969,6 +9195,8 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        int err = alc880_parse_auto_config(codec);
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
 
        if (err < 0)
                return err;
@@ -8982,6 +9210,26 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
        /* hack - override the init verbs */
        spec->init_verbs[0] = alc883_auto_init_verbs;
 
+       /* setup input_mux for ALC889 */
+       if (codec->vendor_id == 0x10ec0889) {
+               /* digital-mic input pin is excluded in alc880_auto_create..()
+                * because it's under 0x18
+                */
+               if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+                   cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+                       struct hda_input_mux *imux = &spec->private_imux[0];
+                       for (i = 1; i < 3; i++)
+                               memcpy(&spec->private_imux[i],
+                                      &spec->private_imux[0],
+                                      sizeof(spec->private_imux[0]));
+                       imux->items[imux->num_items].label = "Int DMic";
+                       imux->items[imux->num_items].index = 0x0b;
+                       imux->num_items++;
+                       spec->num_mux_defs = 3;
+                       spec->input_mux = spec->private_imux;
+               }
+       }
+
        return 1; /* config found */
 }
 
@@ -9033,6 +9281,12 @@ static int patch_alc883(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC883_AUTO)
                setup_preset(spec, &alc883_presets[board_config]);
 
@@ -9045,14 +9299,36 @@ static int patch_alc883(struct hda_codec *codec)
                        spec->stream_name_analog = "ALC888 Analog";
                        spec->stream_name_digital = "ALC888 Digital";
                }
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+                       spec->adc_nids = alc883_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc883_capsrc_nids;
+               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        case 0x10ec0889:
                spec->stream_name_analog = "ALC889 Analog";
                spec->stream_name_digital = "ALC889 Digital";
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
+                       spec->adc_nids = alc889_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc889_capsrc_nids;
+               spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
+                                                       capture */
                break;
        default:
                spec->stream_name_analog = "ALC883 Analog";
                spec->stream_name_digital = "ALC883 Digital";
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+                       spec->adc_nids = alc883_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc883_capsrc_nids;
+               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        }
 
@@ -9063,15 +9339,9 @@ static int patch_alc883(struct hda_codec *codec)
        spec->stream_digital_playback = &alc883_pcm_digital_playback;
        spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
-       if (!spec->num_adc_nids) {
-               spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-               spec->adc_nids = alc883_adc_nids;
-       }
-       if (!spec->capsrc_nids)
-               spec->capsrc_nids = alc883_capsrc_nids;
-       spec->is_mix_capture = 1; /* matrix-style capture */
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -9124,8 +9394,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-          HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
@@ -9146,8 +9414,6 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-          HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
        /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        { } /* end */
@@ -9256,8 +9522,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
        { } /* end */
@@ -9286,8 +9550,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -9435,6 +9697,67 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc262_tyan_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_tyan_verbs[] = {
+       /* Headphone automute */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* P11 AUX_IN, white 4-pin connector */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
+
+       {}
+};
+
+/* unsolicited event for HP jack sensing */
+static void alc262_tyan_automute(struct hda_codec *codec)
+{
+       unsigned int mute;
+       unsigned int present;
+
+       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       present = (present & 0x80000000) != 0;
+       if (present) {
+               /* mute line output on ATX panel */
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute line output if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+static void alc262_tyan_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_tyan_automute(codec);
+}
+
 #define alc262_capture_mixer           alc882_capture_mixer
 #define alc262_capture_alt_mixer       alc882_capture_alt_mixer
 
@@ -9901,8 +10224,6 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
@@ -10474,8 +10795,14 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
                                           alc262_ignore);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
+       }
        err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -10485,8 +10812,11 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+ dig_only:
+       if (spec->autocfg.dig_outs) {
                spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
+               spec->dig_out_type = spec->autocfg.dig_out_type[0];
+       }
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = ALC262_DIGIN_NID;
 
@@ -10495,13 +10825,12 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 
        add_verb(spec, alc262_volume_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -10543,21 +10872,19 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_ULTRA]          = "ultra",
        [ALC262_LENOVO_3000]    = "lenovo-3000",
        [ALC262_NEC]            = "nec",
+       [ALC262_TYAN]           = "tyan",
        [ALC262_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
        SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
-       SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
+                          ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
        SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -10575,17 +10902,17 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
        SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN",
-                     ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
+       SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
+                          ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
                      ALC262_TOSHIBA_RX1),
        SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
-       SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
+       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
+                          ALC262_ULTRA),
        SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
        SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
@@ -10802,6 +11129,19 @@ static struct alc_config_preset alc262_presets[] = {
                .unsol_event = alc262_hippo_unsol_event,
                .init_hook = alc262_hippo_automute,
        },
+       [ALC262_TYAN] = {
+               .mixers = { alc262_tyan_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x02,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_tyan_unsol_event,
+               .init_hook = alc262_tyan_automute,
+       },
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -10854,6 +11194,14 @@ static int patch_alc262(struct hda_codec *codec)
                }
        }
 
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+       }
+
        if (board_config != ALC262_AUTO)
                setup_preset(spec, &alc262_presets[board_config]);
 
@@ -10865,7 +11213,7 @@ static int patch_alc262(struct hda_codec *codec)
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
-       spec->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -10882,8 +11230,10 @@ static int patch_alc262(struct hda_codec *codec)
                        spec->capsrc_nids = alc262_capsrc_nids;
                }
        }
-       if (!spec->cap_mixer)
+       if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
+       if (!spec->no_analog)
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -11263,19 +11613,13 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
 static struct hda_verb alc268_base_init_verbs[] = {
        /* Unmute DAC0-1 and set vol = 0 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
        /*
         * Set up output mixers (0x0c - 0x0e)
         */
        /* set vol=0 to output mixers */
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
         {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
 
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11294,9 +11638,7 @@ static struct hda_verb alc268_base_init_verbs[] = {
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
        /* set PCBEEP vol = 0, mute connections */
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11318,10 +11660,8 @@ static struct hda_verb alc268_base_init_verbs[] = {
  */
 static struct hda_verb alc268_volume_init_verbs[] = {
        /* set output DAC */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
@@ -11329,16 +11669,12 @@ static struct hda_verb alc268_volume_init_verbs[] = {
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
        {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
 
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
        /* set PCBEEP vol = 0, mute connections */
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11537,7 +11873,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, idx1;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -11631,9 +11967,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
                                           alc268_ignore);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
-
+       }
        err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -11643,25 +11984,26 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = 2;
 
+ dig_only:
        /* digital only support output */
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs) {
                spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
-
+               spec->dig_out_type = spec->autocfg.dig_out_type[0];
+       }
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       if (spec->autocfg.speaker_pins[0] != 0x1d)
+       if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
                add_mixer(spec, alc268_beep_mixer);
 
        add_verb(spec, alc268_volume_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -11723,7 +12065,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
 
 static struct alc_config_preset alc268_presets[] = {
        [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer },
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc267_quanta_il1_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -11805,7 +12147,8 @@ static struct alc_config_preset alc268_presets[] = {
        },
        [ALC268_ACER_ASPIRE_ONE] = {
                .mixers = { alc268_acer_aspire_one_mixer,
-                               alc268_capture_alt_mixer },
+                           alc268_beep_mixer,
+                           alc268_capture_alt_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_aspire_one_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -11874,7 +12217,7 @@ static int patch_alc268(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
-       int err;
+       int i, has_beep, err;
 
        spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -11923,15 +12266,30 @@ static int patch_alc268(struct hda_codec *codec)
 
        spec->stream_digital_playback = &alc268_pcm_digital_playback;
 
-       if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
-               /* override the amp caps for beep generator */
-               snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+       has_beep = 0;
+       for (i = 0; i < spec->num_mixers; i++) {
+               if (spec->mixers[i] == alc268_beep_mixer) {
+                       has_beep = 1;
+                       break;
+               }
+       }
+
+       if (has_beep) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+                       /* override the amp caps for beep generator */
+                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
                                          (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
                                          (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
                                          (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
                                          (0 << AC_AMPCAP_MUTE_SHIFT));
+       }
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
                int i;
@@ -12012,8 +12370,6 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
@@ -12040,8 +12396,6 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
        { }
 };
 
@@ -12065,8 +12419,6 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
        { }
 };
 
@@ -12103,13 +12455,6 @@ static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
        { } /* end */
 };
 
-/* beep control */
-static struct snd_kcontrol_new alc269_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
-       { } /* end */
-};
-
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -12509,7 +12854,7 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
         */
        if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
            cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux;
+               struct hda_input_mux *imux = &spec->private_imux[0];
                imux->items[imux->num_items].label = "Int Mic";
                imux->items[imux->num_items].index = 0x05;
                imux->num_items++;
@@ -12527,13 +12872,34 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
 #define alc269_pcm_digital_playback    alc880_pcm_digital_playback
 #define alc269_pcm_digital_capture     alc880_pcm_digital_capture
 
+static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc880_playback_pcm_open,
+               .prepare = alc880_playback_pcm_prepare,
+               .cleanup = alc880_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+};
+
 /*
  * BIOS auto configuration
  */
 static int alc269_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int i, err;
+       int err;
        static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -12550,22 +12916,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
 
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       /* create a beep mixer control if the pin 0x1d isn't assigned */
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
-               if (spec->autocfg.input_pins[i] == 0x1d)
-                       break;
-       if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
-               add_mixer(spec, alc269_beep_mixer);
-
        add_verb(spec, alc269_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
        /* set default input source */
        snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
                                  0, AC_VERB_SET_CONNECT_SEL,
@@ -12575,10 +12934,9 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       if (!spec->cap_mixer)
+       if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -12675,7 +13033,7 @@ static struct alc_config_preset alc269_presets[] = {
                .init_hook = alc269_eeepc_dmic_inithook,
        },
        [ALC269_FUJITSU] = {
-               .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
+               .mixers = { alc269_fujitsu_mixer },
                .cap_mixer = alc269_epc_capture_mixer,
                .init_verbs = { alc269_init_verbs,
                                alc269_eeepc_dmic_init_verbs },
@@ -12740,13 +13098,26 @@ static int patch_alc269(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC269_AUTO)
                setup_preset(spec, &alc269_presets[board_config]);
 
        spec->stream_name_analog = "ALC269 Analog";
-       spec->stream_analog_playback = &alc269_pcm_analog_playback;
-       spec->stream_analog_capture = &alc269_pcm_analog_capture;
-
+       if (codec->subsystem_id == 0x17aa3bf8) {
+               /* Due to a hardware problem on Lenovo Ideadpad, we need to
+                * fix the sample rate of analog I/O to 44.1kHz
+                */
+               spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+       } else {
+               spec->stream_analog_playback = &alc269_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_pcm_analog_capture;
+       }
        spec->stream_name_digital = "ALC269 Digital";
        spec->stream_digital_playback = &alc269_pcm_digital_playback;
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
@@ -12756,6 +13127,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->capsrc_nids = alc269_capsrc_nids;
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC269_AUTO)
@@ -13006,8 +13378,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = {
 static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
        { }
 };
 
@@ -13481,7 +13851,7 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
 static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx, idx1;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -13568,12 +13938,8 @@ static void alc861_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (nid >= 0x0c && nid <= 0x11) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-               }
+               if (nid >= 0x0c && nid <= 0x11)
+                       alc_set_input_pin(codec, nid, i);
        }
 }
 
@@ -13609,7 +13975,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
 
        if (spec->kctls.list)
@@ -13618,13 +13984,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc861_auto_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        spec->adc_nids = alc861_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
        set_capture_mixer(spec);
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -13833,6 +14198,12 @@ static int patch_alc861(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x23);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC861_AUTO)
                setup_preset(spec, &alc861_presets[board_config]);
 
@@ -13844,6 +14215,8 @@ static int patch_alc861(struct hda_codec *codec)
        spec->stream_digital_playback = &alc861_pcm_digital_playback;
        spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
+       set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+
        spec->vmaster_nid = 0x03;
 
        codec->patch_ops = alc_patch_ops;
@@ -14000,9 +14373,6 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-
        { } /* end */
 };
 
@@ -14026,9 +14396,6 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-
        { } /* end */
 };
 
@@ -14067,8 +14434,6 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
        HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -14379,9 +14744,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
        SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
        {}
 };
@@ -14543,11 +14906,9 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc861vd_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                       i <= AUTO_PIN_FRONT_MIC ?
-                                                       PIN_VREF80 : PIN_IN);
-                       if (nid != ALC861VD_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC861VD_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                AC_VERB_SET_AMP_GAIN_MUTE,
                                                AMP_OUT_MUTE);
@@ -14713,7 +15074,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
 
        if (spec->kctls.list)
@@ -14722,13 +15083,12 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc861vd_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -14779,6 +15139,12 @@ static int patch_alc861vd(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x23);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC861VD_AUTO)
                setup_preset(spec, &alc861vd_presets[board_config]);
 
@@ -14801,9 +15167,10 @@ static int patch_alc861vd(struct hda_codec *codec)
        spec->adc_nids = alc861vd_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
        spec->capsrc_nids = alc861vd_capsrc_nids;
-       spec->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
 
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x02;
 
@@ -14992,8 +15359,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -15015,8 +15380,6 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -15992,56 +16355,55 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
-       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
-       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
-       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
-       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
        SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
+       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
+       /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
        SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
+       /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
-       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
-       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
+       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
                      ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
-       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
-       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
        SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
                                        ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
+       SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
+                          ALC663_ASUS_H13),
        {}
 };
 
@@ -16361,7 +16723,7 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 
        if (alc880_is_fixed_pin(pin)) {
                nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-                /* printk("DAC nid=%x\n",nid); */
+               /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
                /* specify the DAC as the extra output */
                if (!spec->multiout.hp_nid)
                        spec->multiout.hp_nid = nid;
@@ -16391,26 +16753,58 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
        return 0;
 }
 
+/* return the index of the src widget from the connection list of the nid.
+ * return -1 if not found
+ */
+static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
+                               hda_nid_t src)
+{
+       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int i, conns;
+
+       conns = snd_hda_get_connections(codec, nid, conn_list,
+                                       ARRAY_SIZE(conn_list));
+       if (conns < 0)
+               return -1;
+       for (i = 0; i < conns; i++)
+               if (conn_list[i] == src)
+                       return i;
+       return -1;
+}
+
+static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
+}
+
 /* create playback/capture controls for input pins */
-static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (alc880_is_input_pin(cfg->input_pins[i])) {
-                       idx = alc880_input_pin_idx(cfg->input_pins[i]);
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i],
-                                              idx, 0x0b);
-                       if (err < 0)
-                               return err;
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index =
-                               alc880_input_pin_idx(cfg->input_pins[i]);
-                       imux->num_items++;
+               if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
+                       idx = alc662_input_pin_idx(codec, 0x0b,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               err = new_analog_input(spec, cfg->input_pins[i],
+                                                      auto_pin_cfg_labels[i],
+                                                      idx, 0x0b);
+                               if (err < 0)
+                                       return err;
+                       }
+                       idx = alc662_input_pin_idx(codec, 0x22,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               imux->items[imux->num_items].label =
+                                       auto_pin_cfg_labels[i];
+                               imux->items[imux->num_items].index = idx;
+                               imux->num_items++;
+                       }
                }
        }
        return 0;
@@ -16460,7 +16854,6 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
                alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
-#define alc662_is_input_pin(nid)       alc880_is_input_pin(nid)
 #define ALC662_PIN_CD_NID              ALC880_PIN_CD_NID
 
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
@@ -16470,12 +16863,10 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc662_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           (i <= AUTO_PIN_FRONT_MIC ?
-                                            PIN_VREF80 : PIN_IN));
-                       if (nid != ALC662_PIN_CD_NID)
+               if (alc662_is_input_pin(codec, nid)) {
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC662_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -16513,20 +16904,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
                                           "Headphone");
        if (err < 0)
                return err;
-       err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
 
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        add_verb(spec, alc662_auto_init_verbs);
        if (codec->vendor_id == 0x10ec0663)
@@ -16536,7 +16927,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -16588,6 +16978,12 @@ static int patch_alc662(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC662_AUTO)
                setup_preset(spec, &alc662_presets[board_config]);
 
@@ -16611,10 +17007,14 @@ static int patch_alc662(struct hda_codec *codec)
        spec->adc_nids = alc662_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
        spec->capsrc_nids = alc662_capsrc_nids;
-       spec->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
 
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       if (codec->vendor_id == 0x10ec0662)
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       else
+               set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        spec->vmaster_nid = 0x02;
 
index 6094344fb223312bb668ad92b1cab3bcc626c068..b5e108aa8f635b56df364d240d3fc33187cbe7ac 100644 (file)
@@ -43,6 +43,7 @@ enum {
 };
 
 enum {
+       STAC_AUTO,
        STAC_REF,
        STAC_9200_OQO,
        STAC_9200_DELL_D21,
@@ -62,14 +63,17 @@ enum {
 };
 
 enum {
+       STAC_9205_AUTO,
        STAC_9205_REF,
        STAC_9205_DELL_M42,
        STAC_9205_DELL_M43,
        STAC_9205_DELL_M44,
+       STAC_9205_EAPD,
        STAC_9205_MODELS
 };
 
 enum {
+       STAC_92HD73XX_AUTO,
        STAC_92HD73XX_NO_JD, /* no jack-detection */
        STAC_92HD73XX_REF,
        STAC_DELL_M6_AMIC,
@@ -80,22 +84,27 @@ enum {
 };
 
 enum {
+       STAC_92HD83XXX_AUTO,
        STAC_92HD83XXX_REF,
        STAC_92HD83XXX_PWR_REF,
+       STAC_DELL_S14,
        STAC_92HD83XXX_MODELS
 };
 
 enum {
+       STAC_92HD71BXX_AUTO,
        STAC_92HD71BXX_REF,
        STAC_DELL_M4_1,
        STAC_DELL_M4_2,
        STAC_DELL_M4_3,
        STAC_HP_M4,
        STAC_HP_DV5,
+       STAC_HP_HDX,
        STAC_92HD71BXX_MODELS
 };
 
 enum {
+       STAC_925x_AUTO,
        STAC_925x_REF,
        STAC_M1,
        STAC_M1_2,
@@ -108,6 +117,7 @@ enum {
 };
 
 enum {
+       STAC_922X_AUTO,
        STAC_D945_REF,
        STAC_D945GTP3,
        STAC_D945GTP5,
@@ -135,6 +145,7 @@ enum {
 };
 
 enum {
+       STAC_927X_AUTO,
        STAC_D965_REF_NO_JD, /* no jack-detection */
        STAC_D965_REF,
        STAC_D965_3ST,
@@ -144,6 +155,12 @@ enum {
        STAC_927X_MODELS
 };
 
+enum {
+       STAC_9872_AUTO,
+       STAC_9872_VAIO,
+       STAC_9872_MODELS
+};
+
 struct sigmatel_event {
        hda_nid_t nid;
        unsigned char type;
@@ -167,6 +184,7 @@ struct sigmatel_spec {
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
+       unsigned int check_volume_offset:1;
 
        /* gpio lines */
        unsigned int eapd_mask;
@@ -179,6 +197,7 @@ struct sigmatel_spec {
        unsigned int stream_delay;
 
        /* analog loopback */
+       struct snd_kcontrol_new *aloopback_ctl;
        unsigned char aloopback_mask;
        unsigned char aloopback_shift;
 
@@ -203,6 +222,8 @@ struct sigmatel_spec {
        hda_nid_t hp_dacs[5];
        hda_nid_t speaker_dacs[5];
 
+       int volume_offset;
+
        /* capture */
        hda_nid_t *adc_nids;
        unsigned int num_adcs;
@@ -224,7 +245,6 @@ struct sigmatel_spec {
        /* pin widgets */
        hda_nid_t *pin_nids;
        unsigned int num_pins;
-       unsigned int *pin_configs;
 
        /* codec specific stuff */
        struct hda_verb *init;
@@ -400,6 +420,10 @@ static hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
+static hda_nid_t stac927x_slave_dig_outs[2] = {
+       0x1f, 0,
+};
+
 static hda_nid_t stac927x_adc_nids[3] = {
         0x07, 0x08, 0x09
 };
@@ -472,15 +496,21 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = {
        0x14, 0x22, 0x23
 };
 
-static hda_nid_t stac92hd83xxx_pin_nids[14] = {
+static hda_nid_t stac92hd83xxx_pin_nids[10] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-       0x0f, 0x10, 0x11, 0x12, 0x13,
-       0x1d, 0x1e, 0x1f, 0x20
+       0x0f, 0x10, 0x11, 0x1f, 0x20,
+};
+
+#define STAC92HD71BXX_NUM_PINS 13
+static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x00,
+       0x00, 0x14, 0x18, 0x19, 0x1e,
+       0x1f, 0x20, 0x27
 };
-static hda_nid_t stac92hd71bxx_pin_nids[11] = {
+static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x18, 0x19, 0x1e,
-       0x1f,
+       0x1f, 0x20, 0x27
 };
 
 static hda_nid_t stac927x_pin_nids[14] = {
@@ -842,9 +872,9 @@ static struct hda_verb stac92hd73xx_10ch_core_init[] = {
 };
 
 static struct hda_verb stac92hd83xxx_core_init[] = {
-       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x0},
 
        /* power state controls amps */
        { 0x01, AC_VERB_SET_EAPD, 1 << 2},
@@ -854,26 +884,25 @@ static struct hda_verb stac92hd83xxx_core_init[] = {
 static struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
-       { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {}
 };
 
-#define HD_DISABLE_PORTF 2
+#define HD_DISABLE_PORTF 1
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        /* start of config #1 */
 
        /* connect port 0f to audio mixer */
        { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-       /* unmute right and left channels for node 0x0f */
-       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* start of config #2 */
 
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* unmute right and left channels for nodes 0x0a, 0xd */
+       {}
+};
+
+static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+       /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
+       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {}
@@ -954,16 +983,6 @@ static struct hda_verb stac9205_core_init[] = {
                .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
        }
 
-#define STAC_INPUT_SOURCE(cnt) \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               .name = "Input Source", \
-               .count = cnt, \
-               .info = stac92xx_mux_enum_info, \
-               .get = stac92xx_mux_enum_get, \
-               .put = stac92xx_mux_enum_put, \
-       }
-
 #define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -978,7 +997,6 @@ static struct hda_verb stac9205_core_init[] = {
 static struct snd_kcontrol_new stac9200_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
-       STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
        { } /* end */
@@ -1003,8 +1021,6 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
        HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
 
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1014,9 +1030,22 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
+static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
+       {}
+};
+
+static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
+       {}
+};
 
+static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
+       {}
+};
+
+static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1041,8 +1070,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1094,9 +1121,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 
@@ -1122,10 +1146,11 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
+};
 
+static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 
@@ -1137,16 +1162,12 @@ static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 static struct snd_kcontrol_new stac925x_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
-       STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new stac9205_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
 
@@ -1155,9 +1176,13 @@ static struct snd_kcontrol_new stac9205_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac9205_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
+       {}
+};
+
 /* This needs to be generated dynamically based on sequence */
 static struct snd_kcontrol_new stac922x_mixer[] = {
-       STAC_INPUT_SOURCE(2),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
 
@@ -1168,9 +1193,6 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
 
 
 static struct snd_kcontrol_new stac927x_mixer[] = {
-       STAC_INPUT_SOURCE(3),
-       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
 
@@ -1182,6 +1204,11 @@ static struct snd_kcontrol_new stac927x_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac927x_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
+       {}
+};
+
 static struct snd_kcontrol_new stac_dmux_mixer = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Digital Input Source",
@@ -1207,10 +1234,7 @@ static const char *slave_vols[] = {
        "LFE Playback Volume",
        "Side Playback Volume",
        "Headphone Playback Volume",
-       "Headphone2 Playback Volume",
        "Speaker Playback Volume",
-       "External Speaker Playback Volume",
-       "Speaker2 Playback Volume",
        NULL
 };
 
@@ -1221,10 +1245,7 @@ static const char *slave_sws[] = {
        "LFE Playback Switch",
        "Side Playback Switch",
        "Headphone Playback Switch",
-       "Headphone2 Playback Switch",
        "Speaker Playback Switch",
-       "External Speaker Playback Switch",
-       "Speaker2 Playback Switch",
        "IEC958 Playback Switch",
        NULL
 };
@@ -1294,6 +1315,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                unsigned int vmaster_tlv[4];
                snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
                                        HDA_OUTPUT, vmaster_tlv);
+               /* correct volume offset */
+               vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
                                          vmaster_tlv, slave_vols);
                if (err < 0)
@@ -1306,6 +1329,13 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       if (spec->aloopback_ctl &&
+           snd_hda_get_bool_hint(codec, "loopback") == 1) {
+               err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl);
+               if (err < 0)
+                       return err;
+       }
+
        stac92xx_free_kctls(codec); /* no longer needed */
 
        /* create jack input elements */
@@ -1490,6 +1520,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
 };
 
 static const char *stac9200_models[STAC_9200_MODELS] = {
+       [STAC_AUTO] = "auto",
        [STAC_REF] = "ref",
        [STAC_9200_OQO] = "oqo",
        [STAC_9200_DELL_D21] = "dell-d21",
@@ -1511,6 +1542,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
                      "unknown Dell", STAC_9200_DELL_D21),
@@ -1633,6 +1666,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
 };
 
 static const char *stac925x_models[STAC_925x_MODELS] = {
+       [STAC_925x_AUTO] = "auto",
        [STAC_REF] = "ref",
        [STAC_M1] = "m1",
        [STAC_M1_2] = "m1-2",
@@ -1660,6 +1694,7 @@ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
 static struct snd_pci_quirk stac925x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
        SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
 
        /* Default table for unknown ID */
@@ -1691,6 +1726,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
 };
 
 static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+       [STAC_92HD73XX_AUTO] = "auto",
        [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
        [STAC_DELL_M6_AMIC] = "dell-m6-amic",
@@ -1703,6 +1739,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                                "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                               "DFI LanParty", STAC_92HD73XX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
                                "Dell Studio 1535", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
@@ -1726,52 +1764,68 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        {} /* terminator */
 };
 
-static unsigned int ref92hd83xxx_pin_configs[14] = {
+static unsigned int ref92hd83xxx_pin_configs[10] = {
        0x02214030, 0x02211010, 0x02a19020, 0x02170130,
        0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
-       0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
        0x01451160, 0x98560170,
 };
 
+static unsigned int dell_s14_pin_configs[10] = {
+       0x02214030, 0x02211010, 0x02a19020, 0x01014050,
+       0x40f000f0, 0x01819040, 0x40f000f0, 0x90a60160,
+       0x40f000f0, 0x40f000f0,
+};
+
 static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
        [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
+       [STAC_DELL_S14] = dell_s14_pin_configs,
 };
 
 static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+       [STAC_92HD83XXX_AUTO] = "auto",
        [STAC_92HD83XXX_REF] = "ref",
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
+       [STAC_DELL_S14] = "dell-s14",
 };
 
 static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
+                     "unknown Dell", STAC_DELL_S14),
        {} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[11] = {
+static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
        0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
-       0x90a000f0, 0x01452050, 0x01452050,
+       0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_1_pin_configs[11] = {
+static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
-       0x40f000f0, 0x4f0000f0, 0x4f0000f0,
+       0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_2_pin_configs[11] = {
+static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
-       0x40f000f0, 0x044413b0, 0x044413b0,
+       0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_3_pin_configs[11] = {
+static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
-       0x40f000f0, 0x044413b0, 0x044413b0,
+       0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+       0x00000000
 };
 
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
@@ -1781,35 +1835,38 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
        [STAC_DELL_M4_3]        = dell_m4_3_pin_configs,
        [STAC_HP_M4]            = NULL,
        [STAC_HP_DV5]           = NULL,
+       [STAC_HP_HDX]           = NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+       [STAC_92HD71BXX_AUTO] = "auto",
        [STAC_92HD71BXX_REF] = "ref",
        [STAC_DELL_M4_1] = "dell-m4-1",
        [STAC_DELL_M4_2] = "dell-m4-2",
        [STAC_DELL_M4_3] = "dell-m4-3",
        [STAC_HP_M4] = "hp-m4",
        [STAC_HP_DV5] = "hp-dv5",
+       [STAC_HP_HDX] = "hp-hdx",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD71BXX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
-                     "HP dv5", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
-                     "HP dv7", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7,
-                     "HP dv4", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
-                     "HP dv7", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600,
-                     "HP dv5", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
-                     "HP dv5", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
+                     "HP", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
+                     "HP dv4-7", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
+                     "HP dv4-7", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
+                     "HP HDX", STAC_HP_HDX),  /* HDX18 */
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
-                               "unknown HP", STAC_HP_M4),
+                     "HP mini 1000", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
+                     "HP HDX", STAC_HP_HDX),  /* HDX16 */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
                                "unknown Dell", STAC_DELL_M4_1),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@ -1961,6 +2018,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 };
 
 static const char *stac922x_models[STAC_922X_MODELS] = {
+       [STAC_922X_AUTO] = "auto",
        [STAC_D945_REF] = "ref",
        [STAC_D945GTP5] = "5stack",
        [STAC_D945GTP3] = "3stack",
@@ -1988,6 +2046,8 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_D945_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D945_REF),
        /* Intel 945G based systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
                      "Intel D945G", STAC_D945GTP3),
@@ -2041,6 +2101,9 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
                      "Intel D945P", STAC_D945GTP3),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
                      "Intel D945P", STAC_D945GTP5),
+       /* other intel */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
+                     "Intel D945", STAC_D945_REF),
        /* other systems  */
        /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
        SND_PCI_QUIRK(0x8384, 0x7680,
@@ -2065,31 +2128,7 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
                      "Dell XPS M1210", STAC_922X_DELL_M82),
        /* ECS/PC Chips boards */
-       SND_PCI_QUIRK(0x1019, 0x2144,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2608,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2633,
-                     "ECS/PC chips P17G/1333", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2811,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2812,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2813,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2814,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2815,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2816,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2817,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2818,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2819,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2820,
+       SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
                      "ECS/PC chips", STAC_ECS_202),
        {} /* terminator */
 };
@@ -2132,6 +2171,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
 };
 
 static const char *stac927x_models[STAC_927X_MODELS] = {
+       [STAC_927X_AUTO]        = "auto",
        [STAC_D965_REF_NO_JD]   = "ref-no-jd",
        [STAC_D965_REF]         = "ref",
        [STAC_D965_3ST]         = "3stack",
@@ -2144,26 +2184,16 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_D965_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D965_REF),
         /* Intel 946 based systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
        /* 965 based 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
+                          "Intel D965", STAC_D965_3ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
+                          "Intel D965", STAC_D965_3ST),
        /* Dell 3 stack systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
@@ -2179,15 +2209,10 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
        /* 965 based 5 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
+                          "Intel D965", STAC_D965_5ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
+                          "Intel D965", STAC_D965_5ST),
        {} /* terminator */
 };
 
@@ -2240,19 +2265,25 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
        [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
        [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
        [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
+       [STAC_9205_EAPD] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
+       [STAC_9205_AUTO] = "auto",
        [STAC_9205_REF] = "ref",
        [STAC_9205_DELL_M42] = "dell-m42",
        [STAC_9205_DELL_M43] = "dell-m43",
        [STAC_9205_DELL_M44] = "dell-m44",
+       [STAC_9205_EAPD] = "eapd",
 };
 
 static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_9205_REF),
+       /* Dell */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
                      "unknown Dell", STAC_9205_DELL_M42),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
@@ -2283,101 +2314,24 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
                      "Dell Inspiron", STAC_9205_DELL_M44),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
                      "Dell Vostro 1500", STAC_9205_DELL_M42),
+       /* Gateway */
+       SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
        {} /* terminator */
 };
 
-static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
+static void stac92xx_set_config_regs(struct hda_codec *codec,
+                                    unsigned int *pincfgs)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
-       
-       kfree(spec->pin_configs);
-       spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
-                                   GFP_KERNEL);
-       if (!spec->pin_configs)
-               return -ENOMEM;
-       
-       for (i = 0; i < spec->num_pins; i++) {
-               hda_nid_t nid = spec->pin_nids[i];
-               unsigned int pin_cfg;
-               
-               pin_cfg = snd_hda_codec_read(codec, nid, 0, 
-                       AC_VERB_GET_CONFIG_DEFAULT, 0x00);      
-               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
-                                       nid, pin_cfg);
-               spec->pin_configs[i] = pin_cfg;
-       }
-       
-       return 0;
-}
 
-static void stac92xx_set_config_reg(struct hda_codec *codec,
-                                   hda_nid_t pin_nid, unsigned int pin_config)
-{
-       int i;
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                           pin_config & 0x000000ff);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                           (pin_config & 0x0000ff00) >> 8);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                           (pin_config & 0x00ff0000) >> 16);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                           pin_config >> 24);
-       i = snd_hda_codec_read(codec, pin_nid, 0,
-                              AC_VERB_GET_CONFIG_DEFAULT,
-                              0x00);   
-       snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
-                   pin_nid, i);
-}
-
-static void stac92xx_set_config_regs(struct hda_codec *codec)
-{
-       int i;
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!spec->pin_configs)
-               return;
+       if (!pincfgs)
+               return;
 
        for (i = 0; i < spec->num_pins; i++)
-               stac92xx_set_config_reg(codec, spec->pin_nids[i],
-                                       spec->pin_configs[i]);
-}
-
-static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!pins)
-               return stac92xx_save_bios_config_regs(codec);
-
-       kfree(spec->pin_configs);
-       spec->pin_configs = kmemdup(pins,
-                                   spec->num_pins * sizeof(*pins),
-                                   GFP_KERNEL);
-       if (!spec->pin_configs)
-               return -ENOMEM;
-
-       stac92xx_set_config_regs(codec);
-       return 0;
-}
-
-static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
-                                  unsigned int cfg)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               if (spec->pin_nids[i] == nid) {
-                       spec->pin_configs[i] = cfg;
-                       stac92xx_set_config_reg(codec, nid, cfg);
-                       break;
-               }
-       }
+               if (spec->pin_nids[i] && pincfgs[i])
+                       snd_hda_codec_set_pincfg(codec, spec->pin_nids[i],
+                                                pincfgs[i]);
 }
 
 /*
@@ -2567,7 +2521,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
                codec->num_pcms++;
                info++;
                info->name = "STAC92xx Digital";
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               info->pcm_type = spec->autocfg.dig_out_type[0];
                if (spec->multiout.dig_out_nid) {
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -2583,8 +2537,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
 
 static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
 {
-       unsigned int pincap = snd_hda_param_read(codec, nid,
-                                                AC_PAR_PIN_CAP);
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
        pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
        if (pincap & AC_PINCAP_VREF_100)
                return AC_PINCTL_VREF_100;
@@ -2759,22 +2712,37 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
 };
 
 /* add dynamic controls */
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
-                                    struct snd_kcontrol_new *ktemp,
-                                    int idx, const char *name,
-                                    unsigned long val)
+static struct snd_kcontrol_new *
+stac_control_new(struct sigmatel_spec *spec,
+                struct snd_kcontrol_new *ktemp,
+                const char *name)
 {
        struct snd_kcontrol_new *knew;
 
        snd_array_init(&spec->kctls, sizeof(*knew), 32);
        knew = snd_array_new(&spec->kctls);
        if (!knew)
-               return -ENOMEM;
+               return NULL;
        *knew = *ktemp;
-       knew->index = idx;
        knew->name = kstrdup(name, GFP_KERNEL);
-       if (!knew->name)
+       if (!knew->name) {
+               /* roolback */
+               memset(knew, 0, sizeof(*knew));
+               spec->kctls.alloced--;
+               return NULL;
+       }
+       return knew;
+}
+
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+                                    struct snd_kcontrol_new *ktemp,
+                                    int idx, const char *name,
+                                    unsigned long val)
+{
+       struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name);
+       if (!knew)
                return -ENOMEM;
+       knew->index = idx;
        knew->private_value = val;
        return 0;
 }
@@ -2796,6 +2764,29 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
        return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 
+static struct snd_kcontrol_new stac_input_src_temp = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Input Source",
+       .info = stac92xx_mux_enum_info,
+       .get = stac92xx_mux_enum_get,
+       .put = stac92xx_mux_enum_put,
+};
+
+static int stac92xx_add_input_source(struct sigmatel_spec *spec)
+{
+       struct snd_kcontrol_new *knew;
+       struct hda_input_mux *imux = &spec->private_imux;
+
+       if (!spec->num_adcs || imux->num_items <= 1)
+               return 0; /* no need for input source control */
+       knew = stac_control_new(spec, &stac_input_src_temp,
+                               stac_input_src_temp.name);
+       if (!knew)
+               return -ENOMEM;
+       knew->count = spec->num_adcs;
+       return 0;
+}
+
 /* check whether the line-input can be used as line-out */
 static hda_nid_t check_line_out_switch(struct hda_codec *codec)
 {
@@ -2807,7 +2798,7 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
        nid = cfg->input_pins[AUTO_PIN_LINE];
-       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+       pincap = snd_hda_query_pin_caps(codec, nid);
        if (pincap & AC_PINCAP_OUT)
                return nid;
        return 0;
@@ -2826,12 +2817,11 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
        mic_pin = AUTO_PIN_MIC;
        for (;;) {
                hda_nid_t nid = cfg->input_pins[mic_pin];
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
                /* some laptops have an internal analog microphone
                 * which can't be used as a output */
                if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
-                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       pincap = snd_hda_query_pin_caps(codec, nid);
                        if (pincap & AC_PINCAP_OUT)
                                return nid;
                }
@@ -2879,8 +2869,7 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
        conn_len = snd_hda_get_connections(codec, nid, conn,
                                           HDA_MAX_CONNECTIONS);
        for (j = 0; j < conn_len; j++) {
-               wcaps = snd_hda_param_read(codec, conn[j],
-                                          AC_PAR_AUDIO_WIDGET_CAP);
+               wcaps = get_wcaps(codec, conn[j]);
                wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
                /* we check only analog outputs */
                if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
@@ -2895,6 +2884,16 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
                        return conn[j];
                }
        }
+       /* if all DACs are already assigned, connect to the primary DAC */
+       if (conn_len > 1) {
+               for (j = 0; j < conn_len; j++) {
+                       if (conn[j] == spec->multiout.dac_nids[0]) {
+                               snd_hda_codec_write_cache(codec, nid, 0,
+                                                 AC_VERB_SET_CONNECT_SEL, j);
+                               break;
+                       }
+               }
+       }
        return 0;
 }
 
@@ -2935,6 +2934,26 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                add_spec_dacs(spec, dac);
        }
 
+       for (i = 0; i < cfg->hp_outs; i++) {
+               nid = cfg->hp_pins[i];
+               dac = get_unassigned_dac(codec, nid);
+               if (dac) {
+                       if (!spec->multiout.hp_nid)
+                               spec->multiout.hp_nid = dac;
+                       else
+                               add_spec_extra_dacs(spec, dac);
+               }
+               spec->hp_dacs[i] = dac;
+       }
+
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               nid = cfg->speaker_pins[i];
+               dac = get_unassigned_dac(codec, nid);
+               if (dac)
+                       add_spec_extra_dacs(spec, dac);
+               spec->speaker_dacs[i] = dac;
+       }
+
        /* add line-in as output */
        nid = check_line_out_switch(codec);
        if (nid) {
@@ -2962,26 +2981,6 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
-       for (i = 0; i < cfg->hp_outs; i++) {
-               nid = cfg->hp_pins[i];
-               dac = get_unassigned_dac(codec, nid);
-               if (dac) {
-                       if (!spec->multiout.hp_nid)
-                               spec->multiout.hp_nid = dac;
-                       else
-                               add_spec_extra_dacs(spec, dac);
-               }
-               spec->hp_dacs[i] = dac;
-       }
-
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               nid = cfg->speaker_pins[i];
-               dac = get_unassigned_dac(codec, nid);
-               if (dac)
-                       add_spec_extra_dacs(spec, dac);
-               spec->speaker_dacs[i] = dac;
-       }
-
        snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   spec->multiout.num_dacs,
                   spec->multiout.dac_nids[0],
@@ -2994,24 +2993,47 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
 }
 
 /* create volume control/switch for the given prefx type */
-static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
+static int create_controls_idx(struct hda_codec *codec, const char *pfx,
+                              int idx, hda_nid_t nid, int chs)
 {
+       struct sigmatel_spec *spec = codec->spec;
        char name[32];
        int err;
 
+       if (!spec->check_volume_offset) {
+               unsigned int caps, step, nums, db_scale;
+               caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+               step = (caps & AC_AMPCAP_STEP_SIZE) >>
+                       AC_AMPCAP_STEP_SIZE_SHIFT;
+               step = (step + 1) * 25; /* in .01dB unit */
+               nums = (caps & AC_AMPCAP_NUM_STEPS) >>
+                       AC_AMPCAP_NUM_STEPS_SHIFT;
+               db_scale = nums * step;
+               /* if dB scale is over -64dB, and finer enough,
+                * let's reduce it to half
+                */
+               if (db_scale > 6400 && nums >= 0x1f)
+                       spec->volume_offset = nums / 2;
+               spec->check_volume_offset = 1;
+       }
+
        sprintf(name, "%s Playback Volume", pfx);
-       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
-                                  HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+       err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name,
+               HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
+                                       spec->volume_offset));
        if (err < 0)
                return err;
        sprintf(name, "%s Playback Switch", pfx);
-       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
+       err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name,
                                   HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
        return 0;
 }
 
+#define create_controls(codec, pfx, nid, chs) \
+       create_controls_idx(codec, pfx, 0, nid, chs)
+
 static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
        if (spec->multiout.num_dacs > 4) {
@@ -3037,40 +3059,32 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
        return 1;
 }
 
-static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
-{
-       int i;
-
-       if (spec->autocfg.line_outs != 1)
-               return 0;
-       if (spec->multiout.hp_nid == nid)
-               return 0;
-       for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
-               if (spec->multiout.extra_out_nid[i] == nid)
-                       return 0;
-       return 1;
-}
-
-/* add playback controls from the parsed DAC table */
-static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                              const struct auto_pin_cfg *cfg)
+/* Create output controls
+ * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
+ */
+static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
+                                const hda_nid_t *pins,
+                                const hda_nid_t *dac_nids,
+                                int type)
 {
        struct sigmatel_spec *spec = codec->spec;
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
-       hda_nid_t nid = 0;
+       hda_nid_t nid;
        int i, err;
        unsigned int wid_caps;
 
-       for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
-               nid = spec->multiout.dac_nids[i];
-               if (i == 2) {
+       for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
+               nid = dac_nids[i];
+               if (!nid)
+                       continue;
+               if (type != AUTO_PIN_HP_OUT && i == 2) {
                        /* Center/LFE */
-                       err = create_controls(spec, "Center", nid, 1);
+                       err = create_controls(codec, "Center", nid, 1);
                        if (err < 0)
                                return err;
-                       err = create_controls(spec, "LFE", nid, 2);
+                       err = create_controls(codec, "LFE", nid, 2);
                        if (err < 0)
                                return err;
 
@@ -3086,23 +3100,47 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        }
 
                } else {
-                       const char *name = chname[i];
-                       /* if it's a single DAC, assign a better name */
-                       if (!i && is_unique_dac(spec, nid)) {
-                               switch (cfg->line_out_type) {
-                               case AUTO_PIN_HP_OUT:
-                                       name = "Headphone";
-                                       break;
-                               case AUTO_PIN_SPEAKER_OUT:
-                                       name = "Speaker";
-                                       break;
-                               }
+                       const char *name;
+                       int idx;
+                       switch (type) {
+                       case AUTO_PIN_HP_OUT:
+                               name = "Headphone";
+                               idx = i;
+                               break;
+                       case AUTO_PIN_SPEAKER_OUT:
+                               name = "Speaker";
+                               idx = i;
+                               break;
+                       default:
+                               name = chname[i];
+                               idx = 0;
+                               break;
                        }
-                       err = create_controls(spec, name, nid, 3);
+                       err = create_controls_idx(codec, name, idx, nid, 3);
                        if (err < 0)
                                return err;
+                       if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
+                               wid_caps = get_wcaps(codec, pins[i]);
+                               if (wid_caps & AC_WCAP_UNSOL_CAP)
+                                       spec->hp_detect = 1;
+                       }
                }
        }
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
+                                              const struct auto_pin_cfg *cfg)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int err;
+
+       err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
+                                   spec->multiout.dac_nids,
+                                   cfg->line_out_type);
+       if (err < 0)
+               return err;
 
        if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
                err = stac92xx_add_control(spec,
@@ -3137,40 +3175,18 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
                                        struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i, err, nums;
+       int err;
+
+       err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
+                                   spec->hp_dacs, AUTO_PIN_HP_OUT);
+       if (err < 0)
+               return err;
+
+       err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
+                                   spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
+       if (err < 0)
+               return err;
 
-       nums = 0;
-       for (i = 0; i < cfg->hp_outs; i++) {
-               static const char *pfxs[] = {
-                       "Headphone", "Headphone2", "Headphone3",
-               };
-               unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
-               if (wid_caps & AC_WCAP_UNSOL_CAP)
-                       spec->hp_detect = 1;
-               if (nums >= ARRAY_SIZE(pfxs))
-                       continue;
-               nid = spec->hp_dacs[i];
-               if (!nid)
-                       continue;
-               err = create_controls(spec, pfxs[nums++], nid, 3);
-               if (err < 0)
-                       return err;
-       }
-       nums = 0;
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               static const char *pfxs[] = {
-                       "Speaker", "External Speaker", "Speaker2",
-               };
-               if (nums >= ARRAY_SIZE(pfxs))
-                       continue;
-               nid = spec->speaker_dacs[i];
-               if (!nid)
-                       continue;
-               err = create_controls(spec, pfxs[nums++], nid, 3);
-               if (err < 0)
-                       return err;
-       }
        return 0;
 }
 
@@ -3379,11 +3395,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                unsigned int wcaps;
                unsigned int def_conf;
 
-               def_conf = snd_hda_codec_read(codec,
-                                             spec->dmic_nids[i],
-                                             0,
-                                             AC_VERB_GET_CONFIG_DEFAULT,
-                                             0);
+               def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
                if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
                        continue;
 
@@ -3507,6 +3519,7 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
 static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
 {
        struct sigmatel_spec *spec = codec->spec;
+       int hp_swap = 0;
        int err;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
@@ -3516,7 +3529,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (! spec->autocfg.line_outs)
                return 0; /* can't find valid pin config */
 
-#if 0 /* FIXME: temporarily disabled */
        /* If we have no real line-out pin and multiple hp-outs, HPs should
         * be set up as multi-channel outputs.
         */
@@ -3535,8 +3547,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->autocfg.line_outs = spec->autocfg.hp_outs;
                spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
                spec->autocfg.hp_outs = 0;
+               hp_swap = 1;
        }
-#endif /* FIXME: temporarily disabled */
        if (spec->autocfg.mono_out_pin) {
                int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
                        (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
@@ -3629,12 +3641,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 #endif
 
        err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
-
        if (err < 0)
                return err;
 
-       err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       /* All output parsing done, now restore the swapped hp pins */
+       if (hp_swap) {
+               memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
+                      sizeof(spec->autocfg.hp_pins));
+               spec->autocfg.hp_outs = spec->autocfg.line_outs;
+               spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
+               spec->autocfg.line_outs = 0;
+       }
 
+       err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -3663,11 +3682,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                        return err;
        }
 
+       err = stac92xx_add_input_source(spec);
+       if (err < 0)
+               return err;
+
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
        if (spec->multiout.max_channels > 2)
                spec->surr_switch = 1;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = dig_out;
        if (dig_in && spec->autocfg.dig_in_pin)
                spec->dig_in_nid = dig_in;
@@ -3730,9 +3753,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
                for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
                        hda_nid_t pin = spec->autocfg.line_out_pins[i];
                        unsigned int defcfg;
-                       defcfg = snd_hda_codec_read(codec, pin, 0,
-                                                AC_VERB_GET_CONFIG_DEFAULT,
-                                                0x00);
+                       defcfg = snd_hda_codec_get_pincfg(codec, pin);
                        if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
                                unsigned int wcaps = get_wcaps(codec, pin);
                                wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
@@ -3745,7 +3766,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
        }
 
        if (lfe_pin) {
-               err = create_controls(spec, "LFE", lfe_pin, 1);
+               err = create_controls(codec, "LFE", lfe_pin, 1);
                if (err < 0)
                        return err;
        }
@@ -3776,7 +3797,11 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
                        return err;
        }
 
-       if (spec->autocfg.dig_out_pin)
+       err = stac92xx_add_input_source(spec);
+       if (err < 0)
+               return err;
+
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = 0x05;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = 0x04;
@@ -3832,8 +3857,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
 #ifdef CONFIG_SND_JACK
        struct sigmatel_spec *spec = codec->spec;
        struct sigmatel_jack *jack;
-       int def_conf = snd_hda_codec_read(codec, nid,
-                       0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
        int connectivity = get_defcfg_connect(def_conf);
        char name[32];
 
@@ -3948,6 +3972,36 @@ static void stac92xx_power_down(struct hda_codec *codec)
 static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
                                  int enable);
 
+/* override some hints from the hwdep entry */
+static void stac_store_hints(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       const char *p;
+       int val;
+
+       val = snd_hda_get_bool_hint(codec, "hp_detect");
+       if (val >= 0)
+               spec->hp_detect = val;
+       p = snd_hda_get_hint(codec, "gpio_mask");
+       if (p) {
+               spec->gpio_mask = simple_strtoul(p, NULL, 0);
+               spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
+                       spec->gpio_mask;
+       }
+       p = snd_hda_get_hint(codec, "gpio_dir");
+       if (p)
+               spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       p = snd_hda_get_hint(codec, "gpio_data");
+       if (p)
+               spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       p = snd_hda_get_hint(codec, "eapd_mask");
+       if (p)
+               spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       val = snd_hda_get_bool_hint(codec, "eapd_switch");
+       if (val >= 0)
+               spec->eapd_switch = val;
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -3964,6 +4018,9 @@ static int stac92xx_init(struct hda_codec *codec)
                                spec->adc_nids[i], 0,
                                AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 
+       /* override some hints */
+       stac_store_hints(codec);
+
        /* set up GPIO */
        gpio = spec->gpio_data;
        /* turn on EAPD statically when spec->eapd_switch isn't set.
@@ -4013,8 +4070,7 @@ static int stac92xx_init(struct hda_codec *codec)
                                                                 pinctl);
                                }
                        }
-                       conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       conf = snd_hda_codec_get_pincfg(codec, nid);
                        if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
                                enable_pin_detect(codec, nid,
                                                  STAC_INSERT_EVENT);
@@ -4026,8 +4082,8 @@ static int stac92xx_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_dmics; i++)
                stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
                                        AC_PINCTL_IN_EN);
-       if (cfg->dig_out_pin)
-               stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
+       if (cfg->dig_out_pins[0])
+               stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0],
                                         AC_PINCTL_OUT_EN);
        if (cfg->dig_in_pin)
                stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
@@ -4055,8 +4111,7 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
                def_conf = get_defcfg_connect(def_conf);
                /* skip any ports that don't have jacks since presence
                 * detection is useless */
@@ -4110,7 +4165,6 @@ static void stac92xx_free(struct hda_codec *codec)
        if (! spec)
                return;
 
-       kfree(spec->pin_configs);
        stac92xx_free_jacks(codec);
        snd_array_free(&spec->events);
 
@@ -4121,7 +4175,9 @@ static void stac92xx_free(struct hda_codec *codec)
 static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
                                unsigned int flag)
 {
-       unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+       unsigned int old_ctl, pin_ctl;
+
+       pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
 
        if (pin_ctl & AC_PINCTL_IN_EN) {
@@ -4135,14 +4191,17 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
                        return;
        }
 
+       old_ctl = pin_ctl;
        /* if setting pin direction bits, clear the current
           direction bits first */
        if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
                pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
        
-       snd_hda_codec_write_cache(codec, nid, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pin_ctl | flag);
+       pin_ctl |= flag;
+       if (old_ctl != pin_ctl)
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         pin_ctl);
 }
 
 static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4150,9 +4209,10 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
-       snd_hda_codec_write_cache(codec, nid, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pin_ctl & ~flag);
+       if (pin_ctl & flag)
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         pin_ctl & ~flag);
 }
 
 static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4415,7 +4475,6 @@ static int stac92xx_resume(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
-       stac92xx_set_config_regs(codec);
        stac92xx_init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
@@ -4426,6 +4485,37 @@ static int stac92xx_resume(struct hda_codec *codec)
        return 0;
 }
 
+
+/*
+ * using power check for controlling mute led of HP HDX notebooks
+ * check for mute state only on Speakers (nid = 0x10)
+ *
+ * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
+ * the LED is NOT working properly !
+ */
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec,
+                                             hda_nid_t nid)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (nid == 0x10) {
+               if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+                   HDA_AMP_MUTE)
+                       spec->gpio_data &= ~0x08;  /* orange */
+               else
+                       spec->gpio_data |= 0x08;   /* white */
+
+               stac_gpio_set(codec, spec->gpio_mask,
+                             spec->gpio_dir,
+                             spec->gpio_data);
+       }
+
+       return 0;
+}
+#endif
+
 static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4464,16 +4554,11 @@ static int patch_stac9200(struct hda_codec *codec)
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
                                                        stac9200_cfg_tbl);
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac9200_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = 1;
@@ -4541,17 +4626,12 @@ static int patch_stac925x(struct hda_codec *codec)
                                                        stac925x_models,
                                                        stac925x_cfg_tbl);
  again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
                                      "using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac925x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = 1;
@@ -4629,17 +4709,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
                                                        stac92hd73xx_models,
                                                        stac92hd73xx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD73XX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd73xx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        num_dacs = snd_hda_get_connections(codec, 0x0a,
                        conn, STAC92HD73_DAC_COUNT + 2) - 1;
@@ -4653,14 +4728,18 @@ again:
        case 0x3: /* 6 Channel */
                spec->mixer = stac92hd73xx_6ch_mixer;
                spec->init = stac92hd73xx_6ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_6ch_loopback;
                break;
        case 0x4: /* 8 Channel */
                spec->mixer = stac92hd73xx_8ch_mixer;
                spec->init = stac92hd73xx_8ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_8ch_loopback;
                break;
        case 0x5: /* 10 Channel */
                spec->mixer = stac92hd73xx_10ch_mixer;
                spec->init = stac92hd73xx_10ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_10ch_loopback;
+               break;
        }
        spec->multiout.dac_nids = spec->dac_nids;
 
@@ -4699,18 +4778,18 @@ again:
                        spec->init = dell_m6_core_init;
                switch (spec->board_config) {
                case STAC_DELL_M6_AMIC: /* Analog Mics */
-                       stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+                       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
                        spec->num_dmics = 0;
                        spec->private_dimux.num_items = 1;
                        break;
                case STAC_DELL_M6_DMIC: /* Digital Mics */
-                       stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+                       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
                        spec->private_dimux.num_items = 2;
                        break;
                case STAC_DELL_M6_BOTH: /* Both */
-                       stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
-                       stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+                       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
+                       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
                        spec->private_dimux.num_items = 2;
                        break;
@@ -4773,6 +4852,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
        int err;
        int num_dacs;
+       hda_nid_t nid;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4791,15 +4871,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->multiout.dac_nids = spec->dac_nids;
 
-
-       /* set port 0xe to select the last DAC
-        */
-       num_dacs = snd_hda_get_connections(codec, 0x0e,
-               conn, STAC92HD83_DAC_COUNT + 1) - 1;
-
-       snd_hda_codec_write_cache(codec, 0xe, 0,
-               AC_VERB_SET_CONNECT_SEL, num_dacs);
-
        spec->init = stac92hd83xxx_core_init;
        spec->mixer = stac92hd83xxx_mixer;
        spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
@@ -4814,17 +4885,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
                                                        stac92hd83xxx_models,
                                                        stac92hd83xxx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD83XXX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        switch (codec->vendor_id) {
        case 0x111d7604:
@@ -4851,6 +4917,23 @@ again:
                return err;
        }
 
+       switch (spec->board_config) {
+       case STAC_DELL_S14:
+               nid = 0xf;
+               break;
+       default:
+               nid = 0xe;
+               break;
+       }
+
+       num_dacs = snd_hda_get_connections(codec, nid,
+                               conn, STAC92HD83_DAC_COUNT + 1) - 1;
+
+       /* set port X to select the last DAC
+        */
+       snd_hda_codec_write_cache(codec, nid, 0,
+                       AC_VERB_SET_CONNECT_SEL, num_dacs);
+
        codec->patch_ops = stac92xx_patch_ops;
 
        codec->proc_widget_hook = stac92hd_proc_hook;
@@ -4858,7 +4941,16 @@ again:
        return 0;
 }
 
-static struct hda_input_mux stac92hd71bxx_dmux = {
+static struct hda_input_mux stac92hd71bxx_dmux_nomixer = {
+       .num_items = 3,
+       .items = {
+               { "Analog Inputs", 0x00 },
+               { "Digital Mic 1", 0x02 },
+               { "Digital Mic 2", 0x03 },
+       }
+};
+
+static struct hda_input_mux stac92hd71bxx_dmux_amixer = {
        .num_items = 4,
        .items = {
                { "Analog Inputs", 0x00 },
@@ -4868,10 +4960,67 @@ static struct hda_input_mux stac92hd71bxx_dmux = {
        }
 };
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int cfg;
+
+       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+       return get_defcfg_connect(cfg);
+}
+
+static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
+                                        hda_nid_t *nids, int num_nids)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx, num;
+       unsigned int def_conf;
+
+       for (num = 0; num < num_nids; num++) {
+               for (idx = 0; idx < spec->num_pins; idx++)
+                       if (spec->pin_nids[idx] == nids[num])
+                               break;
+               if (idx >= spec->num_pins)
+                       break;
+               def_conf = stac_get_defcfg_connect(codec, idx);
+               if (def_conf == AC_JACK_PORT_NONE)
+                       break;
+       }
+       return num;
+}
+
+static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
+                                         hda_nid_t dig0pin)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx;
+
+       for (idx = 0; idx < spec->num_pins; idx++)
+               if (spec->pin_nids[idx] == dig0pin)
+                       break;
+       if ((idx + 2) >= spec->num_pins)
+               return 0;
+
+       /* dig1pin case */
+       if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE)
+               return 2;
+
+       /* dig0pin + dig2pin case */
+       if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE)
+               return 2;
+       if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE)
+               return 1;
+       else
+               return 0;
+}
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
+       struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
        int err = 0;
+       unsigned int ndmic_nids = 0;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4879,27 +5028,32 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 
        codec->spec = spec;
        codec->patch_ops = stac92xx_patch_ops;
-       spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+       spec->num_pins = STAC92HD71BXX_NUM_PINS;
+       switch (codec->vendor_id) {
+       case 0x111d76b6:
+       case 0x111d76b7:
+               spec->pin_nids = stac92hd71bxx_pin_nids_4port;
+               break;
+       case 0x111d7603:
+       case 0x111d7608:
+               /* On 92HD75Bx 0x27 isn't a pin nid */
+               spec->num_pins--;
+               /* fallthrough */
+       default:
+               spec->pin_nids = stac92hd71bxx_pin_nids_6port;
+       }
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
-       spec->pin_nids = stac92hd71bxx_pin_nids;
-       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
-                       sizeof(stac92hd71bxx_dmux));
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD71BXX_MODELS,
                                                        stac92hd71bxx_models,
                                                        stac92hd71bxx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD71BXX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd71bxx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        if (spec->board_config > STAC_92HD71BXX_REF) {
                /* GPIO0 = EAPD */
@@ -4908,16 +5062,34 @@ again:
                spec->gpio_data = 0x01;
        }
 
+       spec->dmic_nids = stac92hd71bxx_dmic_nids;
+       spec->dmux_nids = stac92hd71bxx_dmux_nids;
+
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
+               unmute_init++;
+               /* fallthru */
        case 0x111d76b4: /* 6 Port without Analog Mixer */
        case 0x111d76b5:
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
+                      sizeof(stac92hd71bxx_dmux_nomixer));
                spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS);
+               if (spec->num_dmics) {
+                       spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+                       spec->dinput_mux = &spec->private_dimux;
+                       ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
+               }
                break;
        case 0x111d7608: /* 5 Port with Analog Mixer */
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                      sizeof(stac92hd71bxx_dmux_amixer));
+               spec->private_dimux.num_items--;
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
@@ -4944,7 +5116,15 @@ again:
 
                /* disable VSW */
                spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
-               stac_change_pin_config(codec, 0xf, 0x40f000f0);
+               unmute_init++;
+               snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
+               stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS - 1);
+               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+               ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2;
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
                if ((codec->revision_id & 0xf) == 1)
@@ -4954,12 +5134,23 @@ again:
                spec->num_pwrs = 0;
                /* fallthru */
        default:
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                      sizeof(stac92hd71bxx_dmux_amixer));
                spec->dinput_mux = &spec->private_dimux;
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS);
+               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+               ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
        }
 
+       if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
+               snd_hda_sequence_write_cache(codec, unmute_init);
+
+       spec->aloopback_ctl = stac92hd71bxx_loopback;
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
 
@@ -4967,18 +5158,17 @@ again:
        spec->digbeep_nid = 0x26;
        spec->mux_nids = stac92hd71bxx_mux_nids;
        spec->adc_nids = stac92hd71bxx_adc_nids;
-       spec->dmic_nids = stac92hd71bxx_dmic_nids;
-       spec->dmux_nids = stac92hd71bxx_dmux_nids;
        spec->smux_nids = stac92hd71bxx_smux_nids;
        spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
        spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+       spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
 
        switch (spec->board_config) {
        case STAC_HP_M4:
                /* enable internal microphone */
-               stac_change_pin_config(codec, 0x0e, 0x01813040);
+               snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
                stac92xx_auto_set_pinctl(codec, 0x0e,
                        AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
                /* fallthru */
@@ -4993,19 +5183,36 @@ again:
                spec->num_smuxes = 0;
                spec->num_dmuxes = 1;
                break;
-       default:
-               spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-               spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
-               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+       case STAC_HP_DV5:
+               snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
+               stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
+               break;
+       case STAC_HP_HDX:
+               spec->num_dmics = 1;
+               spec->num_dmuxes = 1;
+               spec->num_smuxes = 1;
+               /*
+                * For controlling MUTE LED on HP HDX16/HDX18 notebooks,
+                * the CONFIG_SND_HDA_POWER_SAVE is needed to be set.
+                */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               /* orange/white mute led on GPIO3, orange=0, white=1 */
+               spec->gpio_mask |= 0x08;
+               spec->gpio_dir  |= 0x08;
+               spec->gpio_data |= 0x08;  /* set to white */
+
+               /* register check_power_status callback. */
+               codec->patch_ops.check_power_status =
+                   stac92xx_hp_hdx_check_power_status;
+#endif 
+               break;
        };
 
        spec->multiout.dac_nids = spec->dac_nids;
        if (spec->dinput_mux)
-               spec->private_dimux.num_items +=
-                       spec->num_dmics -
-                               (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
+               spec->private_dimux.num_items += spec->num_dmics - ndmic_nids;
 
-       err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
+       err = stac92xx_parse_auto_config(codec, 0x21, 0);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5080,17 +5287,12 @@ static int patch_stac922x(struct hda_codec *codec)
        }
 
  again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
                        "using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac922x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->adc_nids = stac922x_adc_nids;
        spec->mux_nids = stac922x_mux_nids;
@@ -5141,24 +5343,19 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       codec->slave_dig_outs = stac927x_slave_dig_outs;
        spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
                                                        stac927x_models,
                                                        stac927x_cfg_tbl);
  again:
-       if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
-               if (spec->board_config < 0)
-                       snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                                   "STAC927x, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                           "STAC927x, using BIOS defaults\n");
+       else
+               stac92xx_set_config_regs(codec,
                                stac927x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->digbeep_nid = 0x23;
        spec->adc_nids = stac927x_adc_nids;
@@ -5187,15 +5384,15 @@ static int patch_stac927x(struct hda_codec *codec)
                case 0x10280209:
                case 0x1028022e:
                        /* correct the device field to SPDIF out */
-                       stac_change_pin_config(codec, 0x21, 0x01442070);
+                       snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
                        break;
                };
                /* configure the analog microphone on some laptops */
-               stac_change_pin_config(codec, 0x0c, 0x90a79130);
+               snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
                /* correct the front output jack as a hp out */
-               stac_change_pin_config(codec, 0x0f, 0x0227011f);
+               snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f);
                /* correct the front input jack as a mic */
-               stac_change_pin_config(codec, 0x0e, 0x02a79130);
+               snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130);
                /* fallthru */
        case STAC_DELL_3ST:
                /* GPIO2 High = Enable EAPD */
@@ -5222,6 +5419,7 @@ static int patch_stac927x(struct hda_codec *codec)
        }
 
        spec->num_pwrs = 0;
+       spec->aloopback_ctl = stac927x_loopback;
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
        spec->eapd_switch = 1;
@@ -5280,16 +5478,11 @@ static int patch_stac9205(struct hda_codec *codec)
                                                        stac9205_models,
                                                        stac9205_cfg_tbl);
  again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac9205_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->digbeep_nid = 0x23;
        spec->adc_nids = stac9205_adc_nids;
@@ -5306,17 +5499,20 @@ static int patch_stac9205(struct hda_codec *codec)
 
        spec->init = stac9205_core_init;
        spec->mixer = stac9205_mixer;
+       spec->aloopback_ctl = stac9205_loopback;
 
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
-       spec->eapd_switch = 1;
+       /* Turn on/off EAPD per HP plugging */
+       if (spec->board_config != STAC_9205_EAPD)
+               spec->eapd_switch = 1;
        spec->multiout.dac_nids = spec->dac_nids;
        
        switch (spec->board_config){
        case STAC_9205_DELL_M43:
                /* Enable SPDIF in/out */
-               stac_change_pin_config(codec, 0x1f, 0x01441030);
-               stac_change_pin_config(codec, 0x20, 0x1c410030);
+               snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030);
+               snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
                err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
@@ -5373,223 +5569,87 @@ static int patch_stac9205(struct hda_codec *codec)
  * STAC9872 hack
  */
 
-/* static config for Sony VAIO FE550G and Sony VAIO AR */
-static hda_nid_t vaio_dacs[] = { 0x2 };
-#define VAIO_HP_DAC    0x5
-static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
-static hda_nid_t vaio_mux_nids[] = { 0x15 };
-
-static struct hda_input_mux vaio_mux = {
-       .num_items = 3,
-       .items = {
-               /* { "HP", 0x0 }, */
-               { "Mic Jack", 0x1 },
-               { "Internal Mic", 0x2 },
-               { "PCM", 0x3 },
-       }
-};
-
-static struct hda_verb vaio_init[] = {
-       {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
-       {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
-       {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
-       {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
+static struct hda_verb stac9872_core_init[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
        {}
 };
 
-static struct hda_verb vaio_ar_init[] = {
-       {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
-       {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
-       {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
-/*     {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
-/*     {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
-       {}
-};
-
-static struct snd_kcontrol_new vaio_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
+static struct snd_kcontrol_new stac9872_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .count = 1,
-               .info = stac92xx_mux_enum_info,
-               .get = stac92xx_mux_enum_get,
-               .put = stac92xx_mux_enum_put,
-       },
-       {}
+       { } /* end */
 };
 
-static struct snd_kcontrol_new vaio_ar_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
-       /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .count = 1,
-               .info = stac92xx_mux_enum_info,
-               .get = stac92xx_mux_enum_get,
-               .put = stac92xx_mux_enum_put,
-       },
-       {}
+static hda_nid_t stac9872_pin_nids[] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x11, 0x13, 0x14,
 };
 
-static struct hda_codec_ops stac9872_patch_ops = {
-       .build_controls = stac92xx_build_controls,
-       .build_pcms = stac92xx_build_pcms,
-       .init = stac92xx_init,
-       .free = stac92xx_free,
-#ifdef SND_HDA_NEEDS_RESUME
-       .resume = stac92xx_resume,
-#endif
+static hda_nid_t stac9872_adc_nids[] = {
+       0x8 /*,0x6*/
 };
 
-static int stac9872_vaio_init(struct hda_codec *codec)
-{
-       int err;
-
-       err = stac92xx_init(codec);
-       if (err < 0)
-               return err;
-       if (codec->patch_ops.unsol_event)
-               codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
-       return 0;
-}
-
-static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
-{
-       if (get_pin_presence(codec, 0x0a)) {
-               stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
-               stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
-       } else {
-               stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
-               stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
-       }
-} 
-
-static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case STAC_HP_EVENT:
-               stac9872_vaio_hp_detect(codec, res);
-               break;
-       }
-}
-
-static struct hda_codec_ops stac9872_vaio_patch_ops = {
-       .build_controls = stac92xx_build_controls,
-       .build_pcms = stac92xx_build_pcms,
-       .init = stac9872_vaio_init,
-       .free = stac92xx_free,
-       .unsol_event = stac9872_vaio_unsol_event,
-#ifdef CONFIG_PM
-       .resume = stac92xx_resume,
-#endif
+static hda_nid_t stac9872_mux_nids[] = {
+       0x15
 };
 
-enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
-       CXD9872RD_VAIO,
-       /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
-       STAC9872AK_VAIO, 
-       /* Unknown. id=0x83847661 and subsys=0x104D1200. */
-       STAC9872K_VAIO,
-       /* AR Series. id=0x83847664 and subsys=104D1300 */
-       CXD9872AKD_VAIO,
-       STAC_9872_MODELS,
+static unsigned int stac9872_vaio_pin_configs[9] = {
+       0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
+       0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
+       0x90a7013e
 };
 
 static const char *stac9872_models[STAC_9872_MODELS] = {
-       [CXD9872RD_VAIO]        = "vaio",
-       [CXD9872AKD_VAIO]       = "vaio-ar",
+       [STAC_9872_AUTO] = "auto",
+       [STAC_9872_VAIO] = "vaio",
+};
+
+static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
+       [STAC_9872_VAIO] = stac9872_vaio_pin_configs,
 };
 
 static struct snd_pci_quirk stac9872_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
-       {}
+       {} /* terminator */
 };
 
 static int patch_stac9872(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       int board_config;
+       int err;
 
-       board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
-                                                 stac9872_models,
-                                                 stac9872_cfg_tbl);
-       if (board_config < 0)
-               /* unknown config, let generic-parser do its job... */
-               return snd_hda_parse_generic_codec(codec);
-       
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
-
        codec->spec = spec;
-       switch (board_config) {
-       case CXD9872RD_VAIO:
-       case STAC9872AK_VAIO:
-       case STAC9872K_VAIO:
-               spec->mixer = vaio_mixer;
-               spec->init = vaio_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
-               spec->multiout.dac_nids = vaio_dacs;
-               spec->multiout.hp_nid = VAIO_HP_DAC;
-               spec->num_adcs = ARRAY_SIZE(vaio_adcs);
-               spec->adc_nids = vaio_adcs;
-               spec->num_pwrs = 0;
-               spec->input_mux = &vaio_mux;
-               spec->mux_nids = vaio_mux_nids;
-               codec->patch_ops = stac9872_vaio_patch_ops;
-               break;
-       
-       case CXD9872AKD_VAIO:
-               spec->mixer = vaio_ar_mixer;
-               spec->init = vaio_ar_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
-               spec->multiout.dac_nids = vaio_dacs;
-               spec->multiout.hp_nid = VAIO_HP_DAC;
-               spec->num_adcs = ARRAY_SIZE(vaio_adcs);
-               spec->num_pwrs = 0;
-               spec->adc_nids = vaio_adcs;
-               spec->input_mux = &vaio_mux;
-               spec->mux_nids = vaio_mux_nids;
-               codec->patch_ops = stac9872_patch_ops;
-               break;
-       }
 
+       spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+                                                       stac9872_models,
+                                                       stac9872_cfg_tbl);
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, "
+                           "using BIOS defaults\n");
+       else
+               stac92xx_set_config_regs(codec,
+                                        stac9872_brd_tbl[spec->board_config]);
+
+       spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
+       spec->pin_nids = stac9872_pin_nids;
+       spec->multiout.dac_nids = spec->dac_nids;
+       spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
+       spec->adc_nids = stac9872_adc_nids;
+       spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
+       spec->mux_nids = stac9872_mux_nids;
+       spec->mixer = stac9872_mixer;
+       spec->init = stac9872_core_init;
+
+       err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
+       if (err < 0) {
+               stac92xx_free(codec);
+               return -EINVAL;
+       }
+       spec->input_mux = &spec->private_imux;
+       codec->patch_ops = stac92xx_patch_ops;
        return 0;
 }
 
index c761394cbe84baabf9433c0bdd3c1d928f79f08c..b25a5cc637d6072cbbad235753d64ff6c12c3ff1 100644 (file)
@@ -1308,16 +1308,13 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
        unsigned int def_conf;
        unsigned char seqassoc;
 
-       def_conf = snd_hda_codec_read(codec, nid, 0,
-                                     AC_VERB_GET_CONFIG_DEFAULT, 0);
+       def_conf = snd_hda_codec_get_pincfg(codec, nid);
        seqassoc = (unsigned char) get_defcfg_association(def_conf);
        seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
        if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
                if (seqassoc == 0xff) {
                        def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                           def_conf >> 24);
+                       snd_hda_codec_set_pincfg(codec, nid, def_conf);
                }
        }
 
@@ -1354,7 +1351,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708_DIGIN_NID;
@@ -1827,7 +1824,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1709_DIGIN_NID;
@@ -2371,7 +2368,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708B_DIGIN_NID;
@@ -2836,7 +2833,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
 
        spec->extra_dig_out_nid = 0x15;
@@ -3155,7 +3152,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
 
        spec->extra_dig_out_nid = 0x1B;
index 58d7cda03de5827f44b58ab435c602460c909b0f..3dd63f1cda5363ac6823c5423323eccebe66a239 100644 (file)
@@ -458,7 +458,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
                        u16 pbkstatus;
                        struct snd_pcm_substream *substream;
                        pbkstatus = inw(ICEDS(ice, INTSTAT));
-                       /* printk("pbkstatus = 0x%x\n", pbkstatus); */
+                       /* printk(KERN_DEBUG "pbkstatus = 0x%x\n", pbkstatus); */
                        for (idx = 0; idx < 6; idx++) {
                                if ((pbkstatus & (3 << (idx * 2))) == 0)
                                        continue;
@@ -2648,9 +2648,9 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "ICE1712");
        strcpy(card->shortname, "ICEnsemble ICE1712");
index bb8d8c766b9d1f5ee5e08f85a8a36694ac1b8058..128510e77a785344886cf6d3207b244850ed6245 100644 (file)
@@ -241,6 +241,8 @@ get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream)
                                struct snd_rawmidi_substream, list);
 }
 
+static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable);
+
 static void vt1724_midi_write(struct snd_ice1712 *ice)
 {
        struct snd_rawmidi_substream *s;
@@ -254,6 +256,11 @@ static void vt1724_midi_write(struct snd_ice1712 *ice)
                for (i = 0; i < count; ++i)
                        outb(buffer[i], ICEREG1724(ice, MPU_DATA));
        }
+       /* mask irq when all bytes have been transmitted.
+        * enabled again in output_trigger when the new data comes in.
+        */
+       enable_midi_irq(ice, VT1724_IRQ_MPU_TX,
+                       !snd_rawmidi_transmit_empty(s));
 }
 
 static void vt1724_midi_read(struct snd_ice1712 *ice)
@@ -272,31 +279,34 @@ static void vt1724_midi_read(struct snd_ice1712 *ice)
        }
 }
 
-static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
-                                  u8 flag, int enable)
+/* call with ice->reg_lock */
+static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable)
 {
-       struct snd_ice1712 *ice = substream->rmidi->private_data;
-       u8 mask;
-
-       spin_lock_irq(&ice->reg_lock);
-       mask = inb(ICEREG1724(ice, IRQMASK));
+       u8 mask = inb(ICEREG1724(ice, IRQMASK));
        if (enable)
                mask &= ~flag;
        else
                mask |= flag;
        outb(mask, ICEREG1724(ice, IRQMASK));
+}
+
+static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
+                                  u8 flag, int enable)
+{
+       struct snd_ice1712 *ice = substream->rmidi->private_data;
+
+       spin_lock_irq(&ice->reg_lock);
+       enable_midi_irq(ice, flag, enable);
        spin_unlock_irq(&ice->reg_lock);
 }
 
 static int vt1724_midi_output_open(struct snd_rawmidi_substream *s)
 {
-       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1);
        return 0;
 }
 
 static int vt1724_midi_output_close(struct snd_rawmidi_substream *s)
 {
-       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
        return 0;
 }
 
@@ -311,6 +321,7 @@ static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
                vt1724_midi_write(ice);
        } else {
                ice->midi_output = 0;
+               enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
        }
        spin_unlock_irqrestore(&ice->reg_lock, flags);
 }
@@ -320,6 +331,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
        struct snd_ice1712 *ice = s->rmidi->private_data;
        unsigned long timeout;
 
+       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
        /* 32 bytes should be transmitted in less than about 12 ms */
        timeout = jiffies + msecs_to_jiffies(15);
        do {
@@ -389,24 +401,24 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                status &= status_mask;
                if (status == 0)
                        break;
+               spin_lock(&ice->reg_lock);
                if (++timeout > 10) {
                        status = inb(ICEREG1724(ice, IRQSTAT));
                        printk(KERN_ERR "ice1724: Too long irq loop, "
                               "status = 0x%x\n", status);
                        if (status & VT1724_IRQ_MPU_TX) {
                                printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
-                               outb(inb(ICEREG1724(ice, IRQMASK)) |
-                                    VT1724_IRQ_MPU_TX,
-                                    ICEREG1724(ice, IRQMASK));
+                               enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
                        }
+                       spin_unlock(&ice->reg_lock);
                        break;
                }
                handled = 1;
                if (status & VT1724_IRQ_MPU_TX) {
-                       spin_lock(&ice->reg_lock);
                        if (ice->midi_output)
                                vt1724_midi_write(ice);
-                       spin_unlock(&ice->reg_lock);
+                       else
+                               enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
                        /* Due to mysterical reasons, MPU_TX is always
                         * generated (and can't be cleared) when a PCM
                         * playback is going.  So let's ignore at the
@@ -415,15 +427,14 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                        status_mask &= ~VT1724_IRQ_MPU_TX;
                }
                if (status & VT1724_IRQ_MPU_RX) {
-                       spin_lock(&ice->reg_lock);
                        if (ice->midi_input)
                                vt1724_midi_read(ice);
                        else
                                vt1724_midi_clear_rx(ice);
-                       spin_unlock(&ice->reg_lock);
                }
                /* ack MPU irq */
                outb(status, ICEREG1724(ice, IRQSTAT));
+               spin_unlock(&ice->reg_lock);
                if (status & VT1724_IRQ_MTPCM) {
                        /*
                         * Multi-track PCM
@@ -745,7 +756,14 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
 
        spin_unlock_irq(&ice->reg_lock);
 
-       /* printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream)); */
+       /*
+       printk(KERN_DEBUG "pro prepare: ch = %d, addr = 0x%x, "
+              "buffer = 0x%x, period = 0x%x\n",
+              substream->runtime->channels,
+              (unsigned int)substream->runtime->dma_addr,
+              snd_pcm_lib_buffer_bytes(substream),
+              snd_pcm_lib_period_bytes(substream));
+       */
        return 0;
 }
 
@@ -2122,7 +2140,9 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
        wait_i2c_busy(ice);
        val = inb(ICEREG1724(ice, I2C_DATA));
        mutex_unlock(&ice->i2c_mutex);
-       /* printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */
+       /*
+       printk(KERN_DEBUG "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+       */
        return val;
 }
 
@@ -2131,7 +2151,9 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
 {
        mutex_lock(&ice->i2c_mutex);
        wait_i2c_busy(ice);
-       /* printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); */
+       /*
+       printk(KERN_DEBUG "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
+       */
        outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
        outb(data, ICEREG1724(ice, I2C_DATA));
        outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
@@ -2456,9 +2478,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "ICE1724");
        strcpy(card->shortname, "ICEnsemble ICE1724");
index c51659b9caf6cfd5fa44a47337c664b729246194..fd948bfd9aef64ccaf223b84233cd361e7a7bbbb 100644 (file)
@@ -345,8 +345,9 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol,
                        new_gpio =  old_gpio &
                                ~((unsigned int) kcontrol->private_value);
        }
-       /* printk("JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, \
-               new_gpio 0x%x\n",
+       /* printk(KERN_DEBUG
+               "JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, "
+               "new_gpio 0x%x\n",
                (unsigned int)ucontrol->value.integer.value[0], old_gpio,
                new_gpio); */
        if (old_gpio != new_gpio) {
index 48d3679292a7f81a4137e055a1724f2e21dbfd74..2a8e5cd8f2d8093f18b3f2c12591ed503c483530 100644 (file)
@@ -133,8 +133,10 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
                idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
        /* due to possible conflicts with stac9460_set_rate_val, mutexing */
        mutex_lock(&spec->mute_mutex);
-       /*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
-               ucontrol->value.integer.value[0]);*/
+       /*
+       printk(KERN_DEBUG "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
+              ucontrol->value.integer.value[0]);
+       */
        change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
        mutex_unlock(&spec->mute_mutex);
        return change;
@@ -185,7 +187,10 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        change = (ovol != nvol);
        if (change) {
                ovol =  (0x7f - nvol) | (tmp & 0x80);
-               /*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/
+               /*
+               printk(KERN_DEBUG "DAC Volume: reg 0x%02x: 0x%02x\n",
+                      idx, ovol);
+               */
                stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
        }
        return change;
@@ -344,7 +349,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
        for (idx = 0; idx < 7 ; ++idx)
                changed[idx] = stac9460_dac_mute(ice,
                                STAC946X_MASTER_VOLUME + idx, 0);
-       /*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+       /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
        stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
        udelay(10);
        /* unmuting - only originally unmuted dacs -
index e900cdc84849ae7a7e8eb1225c917ebfc8639dd3..57648810eaf16430049f9e3300441e2a58954b9f 100644 (file)
@@ -689,7 +689,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
                        bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
                                                     ichdev->fragsize >> ichdev->pos_shift);
 #if 0
-                       printk("bdbar[%i] = 0x%x [0x%x]\n",
+                       printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
                               idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
 #endif
                }
@@ -701,8 +701,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
        ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
        ichdev->position = 0;
 #if 0
-       printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
-                       ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
+       printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
+              "period_size1 = 0x%x\n",
+              ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
+              ichdev->fragsize1);
 #endif
        /* clear interrupts */
        iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
@@ -768,7 +770,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
                ichdev->lvi_frag %= ichdev->frags;
                ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
 #if 0
-       printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
+       printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, "
+              "all = 0x%x, 0x%x\n",
               ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
               ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
               inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -2287,23 +2290,23 @@ static void do_ali_reset(struct intel8x0 *chip)
        iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
 }
 
-static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
-{
-       unsigned long end_time;
-       unsigned int cnt, status, nstatus;
-       
-       /* put logic to right state */
-       /* first clear status bits */
-       status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
-       if (chip->device_type == DEVICE_NFORCE)
-               status |= ICH_NVSPINT;
-       cnt = igetdword(chip, ICHREG(GLOB_STA));
-       iputdword(chip, ICHREG(GLOB_STA), cnt & status);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+static struct snd_pci_quirk ich_chip_reset_mode[] = {
+       SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1),
+       { } /* end */
+};
 
+static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip)
+{
+       unsigned int cnt;
        /* ACLink on, 2 channels */
+
+       if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
+               return -EIO;
+
        cnt = igetdword(chip, ICHREG(GLOB_CNT));
        cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
+
        /* do cold reset - the full ac97 powerdown may leave the controller
         * in a warm state but actually it cannot communicate with the codec.
         */
@@ -2312,22 +2315,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
        udelay(10);
        iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
        msleep(1);
+       return 0;
+}
+#define snd_intel8x0_ich_chip_can_cold_reset(chip) \
+       (!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
 #else
+#define snd_intel8x0_ich_chip_cold_reset(chip) 0
+#define snd_intel8x0_ich_chip_can_cold_reset(chip) (0)
+#endif
+
+static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
+{
+       unsigned long end_time;
+       unsigned int cnt;
+       /* ACLink on, 2 channels */
+       cnt = igetdword(chip, ICHREG(GLOB_CNT));
+       cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
        /* finish cold or do warm reset */
        cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
        iputdword(chip, ICHREG(GLOB_CNT), cnt);
        end_time = (jiffies + (HZ / 4)) + 1;
        do {
                if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
-                       goto __ok;
+                       return 0;
                schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
        snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
                   igetdword(chip, ICHREG(GLOB_CNT)));
        return -EIO;
+}
+
+static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
+{
+       unsigned long end_time;
+       unsigned int status, nstatus;
+       unsigned int cnt;
+       int err;
+
+       /* put logic to right state */
+       /* first clear status bits */
+       status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
+       if (chip->device_type == DEVICE_NFORCE)
+               status |= ICH_NVSPINT;
+       cnt = igetdword(chip, ICHREG(GLOB_STA));
+       iputdword(chip, ICHREG(GLOB_STA), cnt & status);
+
+       if (snd_intel8x0_ich_chip_can_cold_reset(chip))
+               err = snd_intel8x0_ich_chip_cold_reset(chip);
+       else
+               err = snd_intel8x0_ich_chip_reset(chip);
+       if (err < 0)
+               return err;
 
-      __ok:
-#endif
        if (probing) {
                /* wait for any codec ready status.
                 * Once it becomes ready it should remain ready
@@ -3058,9 +3097,9 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
        int err;
        struct shortname_table *name;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if (spdif_aclink < 0)
                spdif_aclink = check_default_spdif_aclink(pci);
index 93449e464566c019a5a0a3c11677bd8b2654fc56..6ec0fc50d6be16bf064b27ca83e61b172deb045e 100644 (file)
@@ -411,7 +411,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ic
                        bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size));
                        bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
                                                     ichdev->fragsize >> chip->pcm_pos_shift);
-                       // printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
+                       /*
+                       printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
+                              idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
+                       */
                }
                ichdev->frags = ichdev->size / ichdev->fragsize;
        }
@@ -421,8 +424,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ic
        ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
        ichdev->position = 0;
 #if 0
-       printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
-                       ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
+       printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
+              "period_size1 = 0x%x\n",
+              ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
+              ichdev->fragsize1);
 #endif
        /* clear interrupts */
        iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
@@ -465,7 +470,8 @@ static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ic
                                                             ichdev->lvi_frag *
                                                             ichdev->fragsize1);
 #if 0
-               printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
+               printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], "
+                      "prefetch = %i, all = 0x%x, 0x%x\n",
                       ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
                       ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
                       inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -1269,9 +1275,9 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
        int err;
        struct shortname_table *name;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "ICH-MODEM");
        strcpy(card->shortname, "Intel ICH");
index 5f8006b4275019ddd475e55e0ea7c8238b514b47..8b79969034be24853b57afda72a88566ed316d10 100644 (file)
@@ -2443,9 +2443,9 @@ snd_korg1212_probe(struct pci_dev *pci,
                dev++;
                return -ENOENT;
        }
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-        if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
         if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) {
                snd_card_free(card);
index 59bbaf8f3e5b9bbe026fe13162e5258408598958..70141548f251236879c6d23765c318648cabca56 100644 (file)
@@ -2691,9 +2691,9 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        switch (pci->device) {
        case PCI_DEVICE_ID_ESS_ALLEGRO:
index bb162507fe6c7b20166198fbcf6afd7d9baac042..c1eb84a14c4264f0c35728675cba420d927daf1a 100644 (file)
@@ -1366,12 +1366,12 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
                else
                        idx = index[dev] + i;
                snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
-               card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+               err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
 
-               if (! card) {
+               if (err < 0) {
                        snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
                        snd_mixart_free(mgr);
-                       return -ENOMEM;
+                       return err;
                }
 
                strcpy(card->driver, CARD_NAME);
index 3782b52bc0e8cb714466f0466991050e52c29b15..4cf4cd8c939c518629200903123ede9d7eec94d2 100644 (file)
@@ -345,8 +345,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
 
        /* motherboard xilinx status 5 will say that the board is performing a reset */
-       if( status_xilinx == 5 ) {
-               snd_printk( KERN_ERR "miXart is resetting !\n");
+       if (status_xilinx == 5) {
+               snd_printk(KERN_ERR "miXart is resetting !\n");
                return -EAGAIN; /* try again later */
        }
 
@@ -354,13 +354,14 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        case MIXART_MOTHERBOARD_XLX_INDEX:
 
                /* xilinx already loaded ? */ 
-               if( status_xilinx == 4 ) {
-                       snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
+               if (status_xilinx == 4) {
+                       snd_printk(KERN_DEBUG "xilinx is already loaded !\n");
                        return 0;
                }
                /* the status should be 0 == "idle" */
-               if( status_xilinx != 0 ) {
-                       snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
+               if (status_xilinx != 0) {
+                       snd_printk(KERN_ERR "xilinx load error ! status = %d\n",
+                                  status_xilinx);
                        return -EIO; /* modprob -r may help ? */
                }
 
@@ -389,21 +390,23 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
        case MIXART_MOTHERBOARD_ELF_INDEX:
 
-               if( status_elf == 4 ) {
-                       snd_printk( KERN_DEBUG "elf file already loaded !\n");
+               if (status_elf == 4) {
+                       snd_printk(KERN_DEBUG "elf file already loaded !\n");
                        return 0;
                }
 
                /* the status should be 0 == "idle" */
-               if( status_elf != 0 ) {
-                       snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
+               if (status_elf != 0) {
+                       snd_printk(KERN_ERR "elf load error ! status = %d\n",
+                                  status_elf);
                        return -EIO; /* modprob -r may help ? */
                }
 
                /* wait for xilinx status == 4 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
                if (err < 0) {
-                       snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
+                       snd_printk(KERN_ERR "xilinx was not loaded or "
+                                  "could not be started\n");
                        return err;
                }
 
@@ -424,7 +427,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for elf status == 4 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
                if (err < 0) {
-                       snd_printk( KERN_ERR "elf could not be started\n");
+                       snd_printk(KERN_ERR "elf could not be started\n");
                        return err;
                }
 
@@ -437,15 +440,16 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        default:
 
                /* elf and xilinx should be loaded */
-               if( (status_elf != 4) || (status_xilinx != 4) ) {
-                       printk( KERN_ERR "xilinx or elf not successfully loaded\n");
+               if (status_elf != 4 || status_xilinx != 4) {
+                       printk(KERN_ERR "xilinx or elf not "
+                              "successfully loaded\n");
                        return -EIO; /* modprob -r may help ? */
                }
 
                /* wait for daughter detection != 0 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
                if (err < 0) {
-                       snd_printk( KERN_ERR "error starting elf file\n");
+                       snd_printk(KERN_ERR "error starting elf file\n");
                        return err;
                }
 
@@ -460,8 +464,9 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                        return -EINVAL;
 
                /* daughter should be idle */
-               if( status_daught != 0 ) {
-                       printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
+               if (status_daught != 0) {
+                       printk(KERN_ERR "daughter load error ! status = %d\n",
+                              status_daught);
                        return -EIO; /* modprob -r may help ? */
                }
  
@@ -480,7 +485,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for status == 2 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
                if (err < 0) {
-                       snd_printk( KERN_ERR "daughter board load error\n");
+                       snd_printk(KERN_ERR "daughter board load error\n");
                        return err;
                }
 
@@ -502,7 +507,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
         /* wait for daughter status == 3 */
         err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
         if (err < 0) {
-               snd_printk( KERN_ERR "daughter board could not be initialised\n");
+               snd_printk(KERN_ERR
+                          "daughter board could not be initialised\n");
                return err;
        }
 
@@ -512,7 +518,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        /* first communication with embedded */
        err = mixart_first_init(mgr);
         if (err < 0) {
-               snd_printk( KERN_ERR "miXart could not be set up\n");
+               snd_printk(KERN_ERR "miXart could not be set up\n");
                return err;
        }
 
@@ -581,16 +587,6 @@ MODULE_FIRMWARE("mixart/miXart8AES.xlx");
 /* miXart hwdep interface id string */
 #define SND_MIXART_HWDEP_ID       "miXart Loader"
 
-static int mixart_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
-static int mixart_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
 static int mixart_hwdep_dsp_status(struct snd_hwdep *hw,
                                   struct snd_hwdep_dsp_status *info)
 {
@@ -643,8 +639,6 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
 
        hw->iface = SNDRV_HWDEP_IFACE_MIXART;
        hw->private_data = mgr;
-       hw->ops.open = mixart_hwdep_open;
-       hw->ops.release = mixart_hwdep_release;
        hw->ops.dsp_status = mixart_hwdep_dsp_status;
        hw->ops.dsp_load = mixart_hwdep_dsp_load;
        hw->exclusive = 1;
index 50c9f8a05082fa6c5aa67919203d80e030895b18..522a040855d41e7321414cfbd2b5c3e22b0d47a8 100644 (file)
@@ -1668,9 +1668,9 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci,
                }
        }
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        switch (pci->device) {
        case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO:
index 1ab833f843eb70404a586a59da232eff20ce4467..84ef131834191b9b64c6d2b1ed266a39573ea7d0 100644 (file)
@@ -45,6 +45,7 @@ MODULE_PARM_DESC(enable, "enable card");
 static struct pci_device_id hifier_ids[] __devinitdata = {
        { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
        { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
+       { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
 };
 MODULE_DEVICE_TABLE(pci, hifier_ids);
@@ -151,7 +152,6 @@ static const struct oxygen_model model_hifier = {
        .shortname = "C-Media CMI8787",
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8788",
-       .owner = THIS_MODULE,
        .init = hifier_init,
        .control_filter = hifier_control_filter,
        .cleanup = hifier_cleanup,
@@ -173,6 +173,13 @@ static const struct oxygen_model model_hifier = {
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
+static int __devinit get_hifier_model(struct oxygen *chip,
+                                     const struct pci_device_id *id)
+{
+       chip->model = model_hifier;
+       return 0;
+}
+
 static int __devinit hifier_probe(struct pci_dev *pci,
                                  const struct pci_device_id *pci_id)
 {
@@ -185,7 +192,8 @@ static int __devinit hifier_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
-       err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier, 0);
+       err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+                              hifier_ids, get_hifier_model);
        if (err >= 0)
                ++dev;
        return err;
index de999c6d6dd3a4b457737d7bb748614f166bd508..72db4c39007fbc8bd8739819a580c0b2b2da48a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian
+ * C-Media CMI8788 driver for C-Media's reference design and similar models
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
@@ -26,6 +26,7 @@
  *
  * GPIO 0 -> DFS0 of AK5385
  * GPIO 1 -> DFS1 of AK5385
+ * GPIO 8 -> enable headphone amplifier on HT-Omega models
  */
 
 #include <linux/delay.h>
@@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card");
 enum {
        MODEL_CMEDIA_REF,       /* C-Media's reference design */
        MODEL_MERIDIAN,         /* AuzenTech X-Meridian */
-       MODEL_HALO,             /* HT-Omega Claro halo */
+       MODEL_CLARO,            /* HT-Omega Claro */
+       MODEL_CLARO_HALO,       /* HT-Omega Claro halo */
 };
 
 static struct pci_device_id oxygen_ids[] __devinitdata = {
@@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
        { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
-       { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
-       { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO },
+       { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
+       { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
        { }
 };
 MODULE_DEVICE_TABLE(pci, oxygen_ids);
@@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
 #define GPIO_AK5385_DFS_DOUBLE 0x0001
 #define GPIO_AK5385_DFS_QUAD   0x0002
 
+#define GPIO_CLARO_HP          0x0100
+
 struct generic_data {
        u8 ak4396_ctl2;
        u16 saved_wm8785_registers[2];
@@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip)
        ak5385_init(chip);
 }
 
+static void claro_enable_hp(struct oxygen *chip)
+{
+       msleep(300);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
+}
+
+static void claro_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+       wm8785_init(chip);
+       claro_enable_hp(chip);
+}
+
+static void claro_halo_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+       ak5385_init(chip);
+       claro_enable_hp(chip);
+}
+
 static void generic_cleanup(struct oxygen *chip)
 {
 }
 
+static void claro_disable_hp(struct oxygen *chip)
+{
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
+}
+
+static void claro_cleanup(struct oxygen *chip)
+{
+       claro_disable_hp(chip);
+}
+
+static void claro_suspend(struct oxygen *chip)
+{
+       claro_disable_hp(chip);
+}
+
 static void generic_resume(struct oxygen *chip)
 {
        ak4396_registers_init(chip);
@@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip)
        ak4396_registers_init(chip);
 }
 
+static void claro_resume(struct oxygen *chip)
+{
+       ak4396_registers_init(chip);
+       claro_enable_hp(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
@@ -293,30 +339,10 @@ static void set_ak5385_params(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
-static int generic_probe(struct oxygen *chip, unsigned long driver_data)
-{
-       if (driver_data == MODEL_MERIDIAN) {
-               chip->model.init = meridian_init;
-               chip->model.resume = meridian_resume;
-               chip->model.set_adc_params = set_ak5385_params;
-               chip->model.device_config = PLAYBACK_0_TO_I2S |
-                                           PLAYBACK_1_TO_SPDIF |
-                                           CAPTURE_0_FROM_I2S_2 |
-                                           CAPTURE_1_FROM_SPDIF;
-       }
-       if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) {
-               chip->model.misc_flags = OXYGEN_MISC_MIDI;
-               chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
-       }
-       return 0;
-}
-
 static const struct oxygen_model model_generic = {
        .shortname = "C-Media CMI8788",
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8788",
-       .owner = THIS_MODULE,
-       .probe = generic_probe,
        .init = generic_init,
        .cleanup = generic_cleanup,
        .resume = generic_resume,
@@ -341,6 +367,42 @@ static const struct oxygen_model model_generic = {
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
+static int __devinit get_oxygen_model(struct oxygen *chip,
+                                     const struct pci_device_id *id)
+{
+       chip->model = model_generic;
+       switch (id->driver_data) {
+       case MODEL_MERIDIAN:
+               chip->model.init = meridian_init;
+               chip->model.resume = meridian_resume;
+               chip->model.set_adc_params = set_ak5385_params;
+               chip->model.device_config = PLAYBACK_0_TO_I2S |
+                                           PLAYBACK_1_TO_SPDIF |
+                                           CAPTURE_0_FROM_I2S_2 |
+                                           CAPTURE_1_FROM_SPDIF;
+               break;
+       case MODEL_CLARO:
+               chip->model.init = claro_init;
+               chip->model.cleanup = claro_cleanup;
+               chip->model.suspend = claro_suspend;
+               chip->model.resume = claro_resume;
+               break;
+       case MODEL_CLARO_HALO:
+               chip->model.init = claro_halo_init;
+               chip->model.cleanup = claro_cleanup;
+               chip->model.suspend = claro_suspend;
+               chip->model.resume = claro_resume;
+               chip->model.set_adc_params = set_ak5385_params;
+               break;
+       }
+       if (id->driver_data == MODEL_MERIDIAN ||
+           id->driver_data == MODEL_CLARO_HALO) {
+               chip->model.misc_flags = OXYGEN_MISC_MIDI;
+               chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
+       }
+       return 0;
+}
+
 static int __devinit generic_oxygen_probe(struct pci_dev *pci,
                                          const struct pci_device_id *pci_id)
 {
@@ -353,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
-       err = oxygen_pci_probe(pci, index[dev], id[dev],
-                              &model_generic, pci_id->driver_data);
+       err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+                              oxygen_ids, get_oxygen_model);
        if (err >= 0)
                ++dev;
        return err;
index 19107c6307e5e297c35555ee3c66ea2e70672e43..bd615dbffadbec807d39f03c9bd2336907c8d670 100644 (file)
@@ -18,6 +18,8 @@
 
 #define OXYGEN_IO_SIZE 0x100
 
+#define OXYGEN_EEPROM_ID       0x434d  /* "CM" */
+
 /* model-specific configuration of outputs/inputs */
 #define PLAYBACK_0_TO_I2S      0x0001
      /* PLAYBACK_0_TO_AC97_0           not implemented */
@@ -49,7 +51,13 @@ enum {
        .subvendor = sv, \
        .subdevice = sd
 
+#define BROKEN_EEPROM_DRIVER_DATA ((unsigned long)-1)
+#define OXYGEN_PCI_SUBID_BROKEN_EEPROM \
+       OXYGEN_PCI_SUBID(PCI_VENDOR_ID_CMEDIA, 0x8788), \
+       .driver_data = BROKEN_EEPROM_DRIVER_DATA
+
 struct pci_dev;
+struct pci_device_id;
 struct snd_card;
 struct snd_pcm_substream;
 struct snd_pcm_hardware;
@@ -62,8 +70,6 @@ struct oxygen_model {
        const char *shortname;
        const char *longname;
        const char *chip;
-       struct module *owner;
-       int (*probe)(struct oxygen *chip, unsigned long driver_data);
        void (*init)(struct oxygen *chip);
        int (*control_filter)(struct snd_kcontrol_new *template);
        int (*mixer_init)(struct oxygen *chip);
@@ -83,6 +89,7 @@ struct oxygen_model {
        void (*ac97_switch)(struct oxygen *chip,
                            unsigned int reg, unsigned int mute);
        const unsigned int *dac_tlv;
+       unsigned long private_data;
        size_t model_data_size;
        unsigned int device_config;
        u8 dac_channels;
@@ -134,8 +141,12 @@ struct oxygen {
 /* oxygen_lib.c */
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-                    const struct oxygen_model *model,
-                    unsigned long driver_data);
+                    struct module *owner,
+                    const struct pci_device_id *ids,
+                    int (*get_model)(struct oxygen *chip,
+                                     const struct pci_device_id *id
+                                    )
+                   );
 void oxygen_pci_remove(struct pci_dev *pci);
 #ifdef CONFIG_PM
 int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
@@ -180,6 +191,9 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
 void oxygen_reset_uart(struct oxygen *chip);
 void oxygen_write_uart(struct oxygen *chip, u8 data);
 
+u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index);
+void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value);
+
 static inline void oxygen_set_bits8(struct oxygen *chip,
                                    unsigned int reg, u8 value)
 {
index 3126c4b403dd2634e2f29c0d1c5ca68a566c2370..c1eb923f2ac94b63b83318e688d98fdcd0dff931 100644 (file)
@@ -254,3 +254,34 @@ void oxygen_write_uart(struct oxygen *chip, u8 data)
        _write_uart(chip, 0, data);
 }
 EXPORT_SYMBOL(oxygen_write_uart);
+
+u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index)
+{
+       unsigned int timeout;
+
+       oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
+                     index | OXYGEN_EEPROM_DIR_READ);
+       for (timeout = 0; timeout < 100; ++timeout) {
+               udelay(1);
+               if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
+                     & OXYGEN_EEPROM_BUSY))
+                       break;
+       }
+       return oxygen_read16(chip, OXYGEN_EEPROM_DATA);
+}
+
+void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
+{
+       unsigned int timeout;
+
+       oxygen_write16(chip, OXYGEN_EEPROM_DATA, value);
+       oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
+                     index | OXYGEN_EEPROM_DIR_WRITE);
+       for (timeout = 0; timeout < 10; ++timeout) {
+               msleep(1);
+               if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
+                     & OXYGEN_EEPROM_BUSY))
+                       return;
+       }
+       snd_printk(KERN_ERR "EEPROM write timeout\n");
+}
index 84f481d41efa5910eeda20b0b8840556d6fd6183..312251d396965404b96311bcc7cda92f409b600b 100644 (file)
@@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 helper library");
 MODULE_LICENSE("GPL v2");
 
+#define DRIVER "oxygen"
 
 static inline int oxygen_uart_input_ready(struct oxygen *chip)
 {
@@ -243,6 +244,62 @@ static void oxygen_proc_init(struct oxygen *chip)
 #define oxygen_proc_init(chip)
 #endif
 
+static const struct pci_device_id *
+oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
+{
+       u16 subdevice;
+
+       /*
+        * Make sure the EEPROM pins are available, i.e., not used for SPI.
+        * (This function is called before we initialize or use SPI.)
+        */
+       oxygen_clear_bits8(chip, OXYGEN_FUNCTION,
+                          OXYGEN_FUNCTION_ENABLE_SPI_4_5);
+       /*
+        * Read the subsystem device ID directly from the EEPROM, because the
+        * chip didn't if the first EEPROM word was overwritten.
+        */
+       subdevice = oxygen_read_eeprom(chip, 2);
+       /*
+        * We use only the subsystem device ID for searching because it is
+        * unique even without the subsystem vendor ID, which may have been
+        * overwritten in the EEPROM.
+        */
+       for (; ids->vendor; ++ids)
+               if (ids->subdevice == subdevice &&
+                   ids->driver_data != BROKEN_EEPROM_DRIVER_DATA)
+                       return ids;
+       return NULL;
+}
+
+static void oxygen_restore_eeprom(struct oxygen *chip,
+                                 const struct pci_device_id *id)
+{
+       if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
+               /*
+                * This function gets called only when a known card model has
+                * been detected, i.e., we know there is a valid subsystem
+                * product ID at index 2 in the EEPROM.  Therefore, we have
+                * been able to deduce the correct subsystem vendor ID, and
+                * this is enough information to restore the original EEPROM
+                * contents.
+                */
+               oxygen_write_eeprom(chip, 1, id->subvendor);
+               oxygen_write_eeprom(chip, 0, OXYGEN_EEPROM_ID);
+
+               oxygen_set_bits8(chip, OXYGEN_MISC,
+                                OXYGEN_MISC_WRITE_PCI_SUBID);
+               pci_write_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID,
+                                     id->subvendor);
+               pci_write_config_word(chip->pci, PCI_SUBSYSTEM_ID,
+                                     id->subdevice);
+               oxygen_clear_bits8(chip, OXYGEN_MISC,
+                                  OXYGEN_MISC_WRITE_PCI_SUBID);
+
+               snd_printk(KERN_INFO "EEPROM ID restored\n");
+       }
+}
+
 static void oxygen_init(struct oxygen *chip)
 {
        unsigned int i;
@@ -446,30 +503,33 @@ static void oxygen_card_free(struct snd_card *card)
                free_irq(chip->irq, chip);
        flush_scheduled_work();
        chip->model.cleanup(chip);
+       kfree(chip->model_data);
        mutex_destroy(&chip->mutex);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
 }
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-                    const struct oxygen_model *model,
-                    unsigned long driver_data)
+                    struct module *owner,
+                    const struct pci_device_id *ids,
+                    int (*get_model)(struct oxygen *chip,
+                                     const struct pci_device_id *id
+                                    )
+                   )
 {
        struct snd_card *card;
        struct oxygen *chip;
+       const struct pci_device_id *pci_id;
        int err;
 
-       card = snd_card_new(index, id, model->owner,
-                           sizeof *chip + model->model_data_size);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index, id, owner, sizeof(*chip), &card);
+       if (err < 0)
+               return err;
 
        chip = card->private_data;
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
-       chip->model = *model;
-       chip->model_data = chip + 1;
        spin_lock_init(&chip->reg_lock);
        mutex_init(&chip->mutex);
        INIT_WORK(&chip->spdif_input_bits_work,
@@ -481,7 +541,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        if (err < 0)
                goto err_card;
 
-       err = pci_request_regions(pci, model->chip);
+       err = pci_request_regions(pci, DRIVER);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot reserve PCI resources\n");
                goto err_pci_enable;
@@ -495,20 +555,34 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        }
        chip->addr = pci_resource_start(pci, 0);
 
+       pci_id = oxygen_search_pci_id(chip, ids);
+       if (!pci_id) {
+               err = -ENODEV;
+               goto err_pci_regions;
+       }
+       oxygen_restore_eeprom(chip, pci_id);
+       err = get_model(chip, pci_id);
+       if (err < 0)
+               goto err_pci_regions;
+
+       if (chip->model.model_data_size) {
+               chip->model_data = kzalloc(chip->model.model_data_size,
+                                          GFP_KERNEL);
+               if (!chip->model_data) {
+                       err = -ENOMEM;
+                       goto err_pci_regions;
+               }
+       }
+
        pci_set_master(pci);
        snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
-       if (chip->model.probe) {
-               err = chip->model.probe(chip, driver_data);
-               if (err < 0)
-                       goto err_card;
-       }
        oxygen_init(chip);
        chip->model.init(chip);
 
        err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
-                         chip->model.chip, chip);
+                         DRIVER, chip);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
                goto err_card;
index 6c870c12a1777f887076166b4009d7d18b6cd315..bc5ce11c8b1444fa632b81ba2684ac4f0410bd08 100644 (file)
  * CS4362A: AD0 <- 0
  */
 
+/*
+ * Xonar Essence STX
+ * -----------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1792A
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 7 -> route output to speaker jacks (0) or HP (1)
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * PCM1792A:
+ *
+ * AD0 <- 0
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -152,6 +180,7 @@ enum {
        MODEL_DX,
        MODEL_HDAV,     /* without daughterboard */
        MODEL_HDAV_H6,  /* with H6 daughterboard */
+       MODEL_STX,
 };
 
 static struct pci_device_id xonar_ids[] __devinitdata = {
@@ -160,6 +189,8 @@ static struct pci_device_id xonar_ids[] __devinitdata = {
        { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
        { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
        { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
+       { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX },
+       { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
 };
 MODULE_DEVICE_TABLE(pci, xonar_ids);
@@ -183,12 +214,14 @@ MODULE_DEVICE_TABLE(pci, xonar_ids);
 #define GPIO_HDAV_DB_H6                0x0000
 #define GPIO_HDAV_DB_XX                0x0020
 
+#define GPIO_ST_HP_REAR                0x0002
+#define GPIO_ST_HP             0x0080
+
 #define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ADx=i, /W=0 */
 #define I2C_DEVICE_CS4398      0x9e    /* 10011, AD1=1, AD0=1, /W=0 */
 #define I2C_DEVICE_CS4362A     0x30    /* 001100, AD0=0, /W=0 */
 
 struct xonar_data {
-       unsigned int model;
        unsigned int anti_pop_delay;
        unsigned int dacs;
        u16 output_enable_bit;
@@ -334,15 +367,9 @@ static void xonar_d2_init(struct oxygen *chip)
        struct xonar_data *data = chip->model_data;
 
        data->anti_pop_delay = 300;
+       data->dacs = 4;
        data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
        data->pcm1796_oversampling = PCM1796_OS_64;
-       if (data->model == MODEL_D2X) {
-               data->ext_power_reg = OXYGEN_GPIO_DATA;
-               data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
-               data->ext_power_bit = GPIO_D2X_EXT_POWER;
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-                                   GPIO_D2X_EXT_POWER);
-       }
 
        pcm1796_init(chip);
 
@@ -355,6 +382,18 @@ static void xonar_d2_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5381");
 }
 
+static void xonar_d2x_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       data->ext_power_reg = OXYGEN_GPIO_DATA;
+       data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+       data->ext_power_bit = GPIO_D2X_EXT_POWER;
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
+
+       xonar_d2_init(chip);
+}
+
 static void update_cs4362a_volumes(struct oxygen *chip)
 {
        u8 mute;
@@ -422,11 +461,6 @@ static void xonar_d1_init(struct oxygen *chip)
        data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
        data->cs4362a_fm = CS4362A_FM_SINGLE |
                CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
-       if (data->model == MODEL_DX) {
-               data->ext_power_reg = OXYGEN_GPI_DATA;
-               data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-               data->ext_power_bit = GPI_DX_EXT_POWER;
-       }
 
        oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
                       OXYGEN_2WIRE_LENGTH_8 |
@@ -447,6 +481,17 @@ static void xonar_d1_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5361");
 }
 
+static void xonar_dx_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       data->ext_power_reg = OXYGEN_GPI_DATA;
+       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->ext_power_bit = GPI_DX_EXT_POWER;
+
+       xonar_d1_init(chip);
+}
+
 static void xonar_hdav_init(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
@@ -458,6 +503,7 @@ static void xonar_hdav_init(struct oxygen *chip)
                       OXYGEN_2WIRE_SPEED_FAST);
 
        data->anti_pop_delay = 100;
+       data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1;
        data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
        data->ext_power_reg = OXYGEN_GPI_DATA;
        data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
@@ -484,6 +530,36 @@ static void xonar_hdav_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5381");
 }
 
+static void xonar_stx_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+
+       data->anti_pop_delay = 100;
+       data->dacs = 1;
+       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
+       data->ext_power_reg = OXYGEN_GPI_DATA;
+       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->ext_power_bit = GPI_DX_EXT_POWER;
+       data->pcm1796_oversampling = PCM1796_OS_64;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+                           GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+
+       xonar_common_init(chip);
+
+       snd_component_add(chip->card, "PCM1792A");
+       snd_component_add(chip->card, "CS5381");
+}
+
 static void xonar_disable_output(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
@@ -511,6 +587,11 @@ static void xonar_hdav_cleanup(struct oxygen *chip)
        xonar_disable_output(chip);
 }
 
+static void xonar_st_cleanup(struct oxygen *chip)
+{
+       xonar_disable_output(chip);
+}
+
 static void xonar_d2_suspend(struct oxygen *chip)
 {
        xonar_d2_cleanup(chip);
@@ -527,6 +608,11 @@ static void xonar_hdav_suspend(struct oxygen *chip)
        msleep(2);
 }
 
+static void xonar_st_suspend(struct oxygen *chip)
+{
+       xonar_st_cleanup(chip);
+}
+
 static void xonar_d2_resume(struct oxygen *chip)
 {
        pcm1796_init(chip);
@@ -554,6 +640,12 @@ static void xonar_hdav_resume(struct oxygen *chip)
        xonar_enable_output(chip);
 }
 
+static void xonar_st_resume(struct oxygen *chip)
+{
+       pcm1796_init(chip);
+       xonar_enable_output(chip);
+}
+
 static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
                                           struct snd_pcm_hardware *hardware)
 {
@@ -733,6 +825,72 @@ static const struct snd_kcontrol_new front_panel_switch = {
        .private_value = GPIO_DX_FRONT_PANEL,
 };
 
+static int st_output_switch_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "Speakers", "Headphones", "FP Headphones"
+       };
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = 3;
+       if (info->value.enumerated.item >= 3)
+               info->value.enumerated.item = 2;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int st_output_switch_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio;
+
+       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (!(gpio & GPIO_ST_HP))
+               value->value.enumerated.item[0] = 0;
+       else if (gpio & GPIO_ST_HP_REAR)
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+
+static int st_output_switch_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio_old, gpio;
+
+       mutex_lock(&chip->mutex);
+       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       gpio = gpio_old;
+       switch (value->value.enumerated.item[0]) {
+       case 0:
+               gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
+               break;
+       case 1:
+               gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
+               break;
+       case 2:
+               gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
+               break;
+       }
+       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+       mutex_unlock(&chip->mutex);
+       return gpio != gpio_old;
+}
+
+static const struct snd_kcontrol_new st_output_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Analog Output",
+       .info = st_output_switch_info,
+       .get = st_output_switch_get,
+       .put = st_output_switch_put,
+};
+
 static void xonar_line_mic_ac97_switch(struct oxygen *chip,
                                       unsigned int reg, unsigned int mute)
 {
@@ -745,8 +903,8 @@ static void xonar_line_mic_ac97_switch(struct oxygen *chip,
        }
 }
 
-static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
-static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
 
 static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
 {
@@ -763,6 +921,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
        return 0;
 }
 
+static int xonar_st_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "CD Capture ", 11))
+               return 1; /* no CD input */
+       if (!strcmp(template->name, "Stereo Upmixing"))
+               return 1; /* stereo only - we don't need upmixing */
+       return 0;
+}
+
 static int xonar_d2_mixer_init(struct oxygen *chip)
 {
        return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
@@ -773,51 +940,14 @@ static int xonar_d1_mixer_init(struct oxygen *chip)
        return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
 }
 
-static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data)
+static int xonar_st_mixer_init(struct oxygen *chip)
 {
-       static const char *const names[] = {
-               [MODEL_D1]      = "Xonar D1",
-               [MODEL_DX]      = "Xonar DX",
-               [MODEL_D2]      = "Xonar D2",
-               [MODEL_D2X]     = "Xonar D2X",
-               [MODEL_HDAV]    = "Xonar HDAV1.3",
-               [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
-       };
-       static const u8 dacs[] = {
-               [MODEL_D1]      = 2,
-               [MODEL_DX]      = 2,
-               [MODEL_D2]      = 4,
-               [MODEL_D2X]     = 4,
-               [MODEL_HDAV]    = 1,
-               [MODEL_HDAV_H6] = 4,
-       };
-       struct xonar_data *data = chip->model_data;
-
-       data->model = driver_data;
-       if (data->model == MODEL_HDAV) {
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-                                   GPIO_HDAV_DB_MASK);
-               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
-                       GPIO_HDAV_DB_MASK) {
-               case GPIO_HDAV_DB_H6:
-                       data->model = MODEL_HDAV_H6;
-                       break;
-               case GPIO_HDAV_DB_XX:
-                       snd_printk(KERN_ERR "unknown daughterboard\n");
-                       return -ENODEV;
-               }
-       }
-
-       data->dacs = dacs[data->model];
-       chip->model.shortname = names[data->model];
-       return 0;
+       return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip));
 }
 
 static const struct oxygen_model model_xonar_d2 = {
        .longname = "Asus Virtuoso 200",
        .chip = "AV200",
-       .owner = THIS_MODULE,
-       .probe = xonar_model_probe,
        .init = xonar_d2_init,
        .control_filter = xonar_d2_control_filter,
        .mixer_init = xonar_d2_mixer_init,
@@ -837,8 +967,8 @@ static const struct oxygen_model model_xonar_d2 = {
                         MIDI_OUTPUT |
                         MIDI_INPUT,
        .dac_channels = 8,
-       .dac_volume_min = 0x0f,
-       .dac_volume_max = 0xff,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
        .misc_flags = OXYGEN_MISC_MIDI,
        .function_flags = OXYGEN_FUNCTION_SPI |
                          OXYGEN_FUNCTION_ENABLE_SPI_4_5,
@@ -849,8 +979,6 @@ static const struct oxygen_model model_xonar_d2 = {
 static const struct oxygen_model model_xonar_d1 = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
-       .owner = THIS_MODULE,
-       .probe = xonar_model_probe,
        .init = xonar_d1_init,
        .control_filter = xonar_d1_control_filter,
        .mixer_init = xonar_d1_mixer_init,
@@ -868,7 +996,7 @@ static const struct oxygen_model model_xonar_d1 = {
                         PLAYBACK_1_TO_SPDIF |
                         CAPTURE_0_FROM_I2S_2,
        .dac_channels = 8,
-       .dac_volume_min = 0,
+       .dac_volume_min = 127 - 60,
        .dac_volume_max = 127,
        .function_flags = OXYGEN_FUNCTION_2WIRE,
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
@@ -878,8 +1006,6 @@ static const struct oxygen_model model_xonar_d1 = {
 static const struct oxygen_model model_xonar_hdav = {
        .longname = "Asus Virtuoso 200",
        .chip = "AV200",
-       .owner = THIS_MODULE,
-       .probe = xonar_model_probe,
        .init = xonar_hdav_init,
        .cleanup = xonar_hdav_cleanup,
        .suspend = xonar_hdav_suspend,
@@ -897,16 +1023,43 @@ static const struct oxygen_model model_xonar_hdav = {
                         PLAYBACK_1_TO_SPDIF |
                         CAPTURE_0_FROM_I2S_2,
        .dac_channels = 8,
-       .dac_volume_min = 0x0f,
-       .dac_volume_max = 0xff,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
        .misc_flags = OXYGEN_MISC_MIDI,
        .function_flags = OXYGEN_FUNCTION_2WIRE,
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
-static int __devinit xonar_probe(struct pci_dev *pci,
-                                const struct pci_device_id *pci_id)
+static const struct oxygen_model model_xonar_st = {
+       .longname = "Asus Virtuoso 100",
+       .chip = "AV200",
+       .init = xonar_stx_init,
+       .control_filter = xonar_st_control_filter,
+       .mixer_init = xonar_st_mixer_init,
+       .cleanup = xonar_st_cleanup,
+       .suspend = xonar_st_suspend,
+       .resume = xonar_st_resume,
+       .set_dac_params = set_pcm1796_params,
+       .set_adc_params = set_cs53x1_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .ac97_switch = xonar_line_mic_ac97_switch,
+       .dac_tlv = pcm1796_db_scale,
+       .model_data_size = sizeof(struct xonar_data),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels = 2,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static int __devinit get_xonar_model(struct oxygen *chip,
+                                    const struct pci_device_id *id)
 {
        static const struct oxygen_model *const models[] = {
                [MODEL_D1]      = &model_xonar_d1,
@@ -914,7 +1067,57 @@ static int __devinit xonar_probe(struct pci_dev *pci,
                [MODEL_D2]      = &model_xonar_d2,
                [MODEL_D2X]     = &model_xonar_d2,
                [MODEL_HDAV]    = &model_xonar_hdav,
+               [MODEL_STX]     = &model_xonar_st,
        };
+       static const char *const names[] = {
+               [MODEL_D1]      = "Xonar D1",
+               [MODEL_DX]      = "Xonar DX",
+               [MODEL_D2]      = "Xonar D2",
+               [MODEL_D2X]     = "Xonar D2X",
+               [MODEL_HDAV]    = "Xonar HDAV1.3",
+               [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
+               [MODEL_STX]     = "Xonar Essence STX",
+       };
+       unsigned int model = id->driver_data;
+
+       if (model >= ARRAY_SIZE(models) || !models[model])
+               return -EINVAL;
+       chip->model = *models[model];
+
+       switch (model) {
+       case MODEL_D2X:
+               chip->model.init = xonar_d2x_init;
+               break;
+       case MODEL_DX:
+               chip->model.init = xonar_dx_init;
+               break;
+       case MODEL_HDAV:
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                                   GPIO_HDAV_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                       GPIO_HDAV_DB_MASK) {
+               case GPIO_HDAV_DB_H6:
+                       model = MODEL_HDAV_H6;
+                       break;
+               case GPIO_HDAV_DB_XX:
+                       snd_printk(KERN_ERR "unknown daughterboard\n");
+                       return -ENODEV;
+               }
+               break;
+       case MODEL_STX:
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                                   GPIO_HDAV_DB_MASK);
+               break;
+       }
+
+       chip->model.shortname = names[model];
+       chip->model.private_data = model;
+       return 0;
+}
+
+static int __devinit xonar_probe(struct pci_dev *pci,
+                                const struct pci_device_id *pci_id)
+{
        static int dev;
        int err;
 
@@ -924,10 +1127,8 @@ static int __devinit xonar_probe(struct pci_dev *pci,
                ++dev;
                return -ENOENT;
        }
-       BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models));
-       err = oxygen_pci_probe(pci, index[dev], id[dev],
-                              models[pci_id->driver_data],
-                              pci_id->driver_data);
+       err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+                              xonar_ids, get_xonar_model);
        if (err >= 0)
                ++dev;
        return err;
index 27cf2c28d1131eac14cf96ac3b55eb34c51ec543..80e064a3efff94d1c37c81276d15b7d95c9b5533 100644 (file)
@@ -1334,6 +1334,40 @@ static void pcxhr_proc_sync(struct snd_info_entry *entry,
        snd_iprintf(buffer, "\n");
 }
 
+static void pcxhr_proc_gpio_read(struct snd_info_entry *entry,
+                                struct snd_info_buffer *buffer)
+{
+       struct snd_pcxhr *chip = entry->private_data;
+       struct pcxhr_mgr *mgr = chip->mgr;
+       /* commands available when embedded DSP is running */
+       if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
+               /* gpio ports on stereo boards only available */
+               int value = 0;
+               hr222_read_gpio(mgr, 1, &value);        /* GPI */
+               snd_iprintf(buffer, "GPI: 0x%x\n", value);
+               hr222_read_gpio(mgr, 0, &value);        /* GP0 */
+               snd_iprintf(buffer, "GPO: 0x%x\n", value);
+       } else
+               snd_iprintf(buffer, "no firmware loaded\n");
+       snd_iprintf(buffer, "\n");
+}
+static void pcxhr_proc_gpo_write(struct snd_info_entry *entry,
+                                struct snd_info_buffer *buffer)
+{
+       struct snd_pcxhr *chip = entry->private_data;
+       struct pcxhr_mgr *mgr = chip->mgr;
+       char line[64];
+       int value;
+       /* commands available when embedded DSP is running */
+       if (!(mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)))
+               return;
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "GPO: 0x%x", &value) != 1)
+                       continue;
+               hr222_write_gpo(mgr, value);    /* GP0 */
+       }
+}
+
 static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
 {
        struct snd_info_entry *entry;
@@ -1342,6 +1376,13 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
                snd_info_set_text_ops(entry, chip, pcxhr_proc_info);
        if (! snd_card_proc_new(chip->card, "sync", &entry))
                snd_info_set_text_ops(entry, chip, pcxhr_proc_sync);
+       /* gpio available on stereo sound cards only */
+       if (chip->mgr->is_hr_stereo &&
+           !snd_card_proc_new(chip->card, "gpio", &entry)) {
+               snd_info_set_text_ops(entry, chip, pcxhr_proc_gpio_read);
+               entry->c.text.write = pcxhr_proc_gpo_write;
+               entry->mode |= S_IWUSR;
+       }
 }
 /* end of proc interface */
 
@@ -1510,12 +1551,12 @@ static int __devinit pcxhr_probe(struct pci_dev *pci,
 
                snprintf(tmpid, sizeof(tmpid), "%s-%d",
                         id[dev] ? id[dev] : card_name, i);
-               card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+               err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
 
-               if (! card) {
+               if (err < 0) {
                        snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
                        pcxhr_free(mgr);
-                       return -ENOMEM;
+                       return err;
                }
 
                strcpy(card->driver, DRIVER_NAME);
index 69d87dee6995f72e174940a44bd0a4f302b7e7f4..bda776c498845b7524ba16bdfc043010d07daca3 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/mutex.h>
 #include <sound/pcm.h>
 
-#define PCXHR_DRIVER_VERSION           0x000905        /* 0.9.5 */
-#define PCXHR_DRIVER_VERSION_STRING    "0.9.5"         /* 0.9.5 */
+#define PCXHR_DRIVER_VERSION           0x000906        /* 0.9.6 */
+#define PCXHR_DRIVER_VERSION_STRING    "0.9.6"         /* 0.9.6 */
 
 
 #define PCXHR_MAX_CARDS                6
@@ -124,6 +124,7 @@ struct pcxhr_mgr {
 
        unsigned char xlx_cfg;          /* copy of PCXHR_XLX_CFG register */
        unsigned char xlx_selmic;       /* copy of PCXHR_XLX_SELMIC register */
+       unsigned char dsp_reset;        /* copy of PCXHR_DSP_RESET register */
 };
 
 
index bbbd66d13a643301230121c00c959779ef9e3fcb..be0173796cdb5b22022ea2cd64dbb368a4d4c60d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for Digigram pcxhr compatible soundcards
  *
- * low level interface with interrupt ans message handling
+ * low level interface with interrupt and message handling
  *
  * Copyright (c) 2004 by Digigram <alsa@digigram.com>
  *
index 592743a298b09c29e295bb59731998165122aad5..17cb1233a903470b9f1e7ab63a4373be37ec97b5 100644 (file)
@@ -471,16 +471,6 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
        return 0;
 }
 
-static int pcxhr_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
-static int pcxhr_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
 int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
 {
        int err;
@@ -495,8 +485,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
 
        hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
        hw->private_data = mgr;
-       hw->ops.open = pcxhr_hwdep_open;
-       hw->ops.release = pcxhr_hwdep_release;
        hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
        hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
        hw->exclusive = 1;
index ff019126b672e4743fba7385134ae7a39e3b873d..1cb82c0a9cb3f4942b258464af2163aa7a0f5064 100644 (file)
@@ -53,6 +53,8 @@
 #define PCXHR_DSP_RESET_DSP    0x01
 #define PCXHR_DSP_RESET_MUTE   0x02
 #define PCXHR_DSP_RESET_CODEC  0x08
+#define PCXHR_DSP_RESET_GPO_OFFSET     5
+#define PCXHR_DSP_RESET_GPO_MASK       0x60
 
 /* values for PCHR_XLX_CFG register */
 #define PCXHR_CFG_SYNCDSP_MASK         0x80
@@ -81,6 +83,8 @@
 /* values for PCHR_XLX_STATUS register - READ */
 #define PCXHR_STAT_SRC_LOCK            0x01
 #define PCXHR_STAT_LEVEL_IN            0x02
+#define PCXHR_STAT_GPI_OFFSET          2
+#define PCXHR_STAT_GPI_MASK            0x0C
 #define PCXHR_STAT_MIC_CAPS            0x10
 /* values for PCHR_XLX_STATUS register - WRITE */
 #define PCXHR_STAT_FREQ_SYNC_MASK      0x01
@@ -291,10 +295,11 @@ int hr222_sub_init(struct pcxhr_mgr *mgr)
        PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
                    PCXHR_DSP_RESET_DSP);
        msleep(5);
-       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
-                   PCXHR_DSP_RESET_DSP  |
-                   PCXHR_DSP_RESET_MUTE |
-                   PCXHR_DSP_RESET_CODEC);
+       mgr->dsp_reset = PCXHR_DSP_RESET_DSP  |
+                        PCXHR_DSP_RESET_MUTE |
+                        PCXHR_DSP_RESET_CODEC;
+       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
+       /* hr222_write_gpo(mgr, 0); does the same */
        msleep(5);
 
        /* config AKM */
@@ -496,6 +501,33 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
 }
 
 
+int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value)
+{
+       if (is_gpi) {
+               unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
+               *value = (int)(reg & PCXHR_STAT_GPI_MASK) >>
+                             PCXHR_STAT_GPI_OFFSET;
+       } else {
+               *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >>
+                        PCXHR_DSP_RESET_GPO_OFFSET;
+       }
+       return 0;
+}
+
+
+int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
+{
+       unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK;
+
+       reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) &
+              PCXHR_DSP_RESET_GPO_MASK;
+
+       PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg);
+       mgr->dsp_reset = reg;
+       return 0;
+}
+
+
 int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
                                    int is_capture, int channel)
 {
index 6b318b2f0100af693bdf8a4a3798d25671a3e179..5a37a0007e8fd071cc430ad67bfe5853bfef15c6 100644 (file)
@@ -32,6 +32,9 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
                             enum pcxhr_clock_type clock_type,
                             int *sample_rate);
 
+int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value);
+int hr222_write_gpo(struct pcxhr_mgr *mgr, int value);
+
 #define HR222_LINE_PLAYBACK_LEVEL_MIN          0       /* -25.5 dB */
 #define HR222_LINE_PLAYBACK_ZERO_LEVEL         51      /* 0.0 dB */
 #define HR222_LINE_PLAYBACK_LEVEL_MAX          99      /* +24.0 dB */
index 2436e374586f84aada1cc71c9fa565a4e9b72d85..fec049344621ef97f922c395e8ff5693e3c48945 100644 (file)
@@ -789,11 +789,15 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
        if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
                mutex_lock(&mgr->setup_mutex);
                mgr->use_clock_type = ucontrol->value.enumerated.item[0];
-               if (mgr->use_clock_type)
+               rate = 0;
+               if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) {
                        pcxhr_get_external_clock(mgr, mgr->use_clock_type,
                                                 &rate);
-               else
+               } else {
                        rate = mgr->sample_rate;
+                       if (!rate)
+                               rate = 48000;
+               }
                if (rate) {
                        pcxhr_set_clock(mgr, rate);
                        if (mgr->sample_rate)
index 3caacfb9d8e005c3382b76ef8a742b798837a77d..6f1034417a0209e6532ba33197f4490583a8ec6b 100644 (file)
@@ -2102,9 +2102,9 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        if ((err = snd_riptide_create(card, pci, &chip)) < 0) {
                snd_card_free(card);
                return err;
index e7ef3a1a25a89a4643b85c888435f22cb28c34a1..d7b966e7c4cf69270358a6070979e904e072f3d4 100644 (file)
@@ -1941,9 +1941,10 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct rme32))) == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct rme32), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_rme32_card_free;
        rme32 = (struct rme32 *) card->private_data;
        rme32->card = card;
index 3fdd488d09759afca5389383c76590e57bb4dc63..55fb1c131f5809a1b2b62383c99c3ac6037e90c8 100644 (file)
@@ -2348,9 +2348,10 @@ snd_rme96_probe(struct pci_dev *pci,
                dev++;
                return -ENOENT;
        }
-       if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct rme96))) == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct rme96), &card);
+       if (err < 0)
+               return err;
        card->private_free = snd_rme96_card_free;
        rme96 = (struct rme96 *)card->private_data;     
        rme96->card = card;
index 44d0c15e2b71a150cf2643194a978e6c6fa7ee95..314e73531bd176121dead403390c1cdfca4dc13f 100644 (file)
@@ -113,7 +113,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 
 /* the meters are regular i/o-mapped registers, but offset
    considerably from the rest. the peak registers are reset
-   when read; the least-significant 4 bits are full-scale counters; 
+   when read; the least-significant 4 bits are full-scale counters;
    the actual peak value is in the most-significant 24 bits.
 */
 
@@ -131,7 +131,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
    26*3 values are read in ss mode
    14*3 in ds mode, with no gap between values
 */
-#define HDSP_9652_peakBase     7164    
+#define HDSP_9652_peakBase     7164
 #define HDSP_9652_rmsBase      4096
 
 /* c.f. the hdsp_9632_meters_t struct */
@@ -173,12 +173,12 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_SPDIFEmphasis        (1<<10) /* 0=none, 1=on */
 #define HDSP_SPDIFNonAudio        (1<<11) /* 0=off, 1=on */
 #define HDSP_SPDIFOpticalOut      (1<<12) /* 1=use 1st ADAT connector for SPDIF, 0=do not */
-#define HDSP_SyncRef2             (1<<13) 
-#define HDSP_SPDIFInputSelect0    (1<<14) 
-#define HDSP_SPDIFInputSelect1    (1<<15) 
-#define HDSP_SyncRef0             (1<<16) 
+#define HDSP_SyncRef2             (1<<13)
+#define HDSP_SPDIFInputSelect0    (1<<14)
+#define HDSP_SPDIFInputSelect1    (1<<15)
+#define HDSP_SyncRef0             (1<<16)
 #define HDSP_SyncRef1             (1<<17)
-#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */ 
+#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */
 #define HDSP_XLRBreakoutCable     (1<<20) /* For H9632 cards */
 #define HDSP_Midi0InterruptEnable (1<<22)
 #define HDSP_Midi1InterruptEnable (1<<23)
@@ -314,7 +314,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_TimecodeSync       (1<<27)
 #define HDSP_AEBO              (1<<28) /* H9632 specific Analog Extension Boards */
 #define HDSP_AEBI              (1<<29) /* 0 = present, 1 = absent */
-#define HDSP_midi0IRQPending    (1<<30) 
+#define HDSP_midi0IRQPending    (1<<30)
 #define HDSP_midi1IRQPending    (1<<31)
 
 #define HDSP_spdifFrequencyMask    (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2)
@@ -391,7 +391,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_CHANNEL_BUFFER_BYTES    (4*HDSP_CHANNEL_BUFFER_SAMPLES)
 
 /* the size of the area we need to allocate for DMA transfers. the
-   size is the same regardless of the number of channels - the 
+   size is the same regardless of the number of channels - the
    Multiface still uses the same memory area.
 
    Note that we allocate 1 more channel than is apparently needed
@@ -460,7 +460,7 @@ struct hdsp {
        unsigned char         qs_in_channels;        /* quad speed mode for H9632 */
        unsigned char         ds_in_channels;
        unsigned char         ss_in_channels;       /* different for multiface/digiface */
-       unsigned char         qs_out_channels;      
+       unsigned char         qs_out_channels;
        unsigned char         ds_out_channels;
        unsigned char         ss_out_channels;
 
@@ -502,9 +502,9 @@ static char channel_map_df_ss[HDSP_MAX_CHANNELS] = {
 
 static char channel_map_mf_ss[HDSP_MAX_CHANNELS] = { /* Multiface */
        /* Analog */
-       0, 1, 2, 3, 4, 5, 6, 7, 
+       0, 1, 2, 3, 4, 5, 6, 7,
        /* ADAT 2 */
-       16, 17, 18, 19, 20, 21, 22, 23, 
+       16, 17, 18, 19, 20, 21, 22, 23,
        /* SPDIF */
        24, 25,
        -1, -1, -1, -1, -1, -1, -1, -1
@@ -525,11 +525,11 @@ static char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = {
        /* SPDIF */
        8, 9,
        /* Analog */
-       10, 11, 
+       10, 11,
        /* AO4S-192 and AI4S-192 extension boards */
        12, 13, 14, 15,
        /* others don't exist */
-       -1, -1, -1, -1, -1, -1, -1, -1, 
+       -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1
 };
 
@@ -539,7 +539,7 @@ static char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = {
        /* SPDIF */
        8, 9,
        /* Analog */
-       10, 11, 
+       10, 11,
        /* AO4S-192 and AI4S-192 extension boards */
        12, 13, 14, 15,
        /* others don't exist */
@@ -587,7 +587,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d
 static struct pci_device_id snd_hdsp_ids[] = {
        {
                .vendor = PCI_VENDOR_ID_XILINX,
-               .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, 
+               .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
        }, /* RME Hammerfall-DSP */
@@ -653,7 +653,6 @@ static unsigned int hdsp_read(struct hdsp *hdsp, int reg)
 
 static int hdsp_check_for_iobox (struct hdsp *hdsp)
 {
-
        if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
        if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
                snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n");
@@ -661,7 +660,29 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
                return -EIO;
        }
        return 0;
+}
 
+static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
+                              unsigned int delay)
+{
+       unsigned int i;
+
+       if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
+               return 0;
+
+       for (i = 0; i != loops; ++i) {
+               if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
+                       msleep(delay);
+               else {
+                       snd_printd("Hammerfall-DSP: iobox found after %ums!\n",
+                                  i * delay);
+                       return 0;
+               }
+       }
+
+       snd_printk("Hammerfall-DSP: no Digiface or Multiface connected!\n");
+       hdsp->state &= ~HDSP_FirmwareLoaded;
+       return -EIO;
 }
 
 static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
@@ -670,19 +691,19 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
        unsigned long flags;
 
        if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
-               
+
                snd_printk ("Hammerfall-DSP: loading firmware\n");
 
                hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
                hdsp_write (hdsp, HDSP_fifoData, 0);
-               
+
                if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
                        snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
                        return -EIO;
                }
-               
+
                hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
-               
+
                for (i = 0; i < 24413; ++i) {
                        hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]);
                        if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
@@ -692,7 +713,7 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
                }
 
                ssleep(3);
-               
+
                if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
                        snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n");
                        return -EIO;
@@ -705,15 +726,15 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
 #endif
                hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
                snd_printk ("Hammerfall-DSP: finished firmware loading\n");
-               
+
        }
        if (hdsp->state & HDSP_InitializationComplete) {
                snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n");
                spin_lock_irqsave(&hdsp->lock, flags);
                snd_hdsp_set_defaults(hdsp);
-               spin_unlock_irqrestore(&hdsp->lock, flags); 
+               spin_unlock_irqrestore(&hdsp->lock, flags);
        }
-       
+
        hdsp->state |= HDSP_FirmwareLoaded;
 
        return 0;
@@ -722,7 +743,7 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
 static int hdsp_get_iobox_version (struct hdsp *hdsp)
 {
        if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
-       
+
                hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM);
                hdsp_write (hdsp, HDSP_fifoData, 0);
                if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0)
@@ -738,7 +759,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                        hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
                } else {
                        hdsp->io_type = Digiface;
-               } 
+               }
        } else {
                /* firmware was already loaded, get iobox type */
                if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
@@ -786,13 +807,13 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
 
 
 static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
-{    
+{
        int i;
 
        /* the fifoStatus registers reports on how many words
           are available in the command FIFO.
        */
-       
+
        for (i = 0; i < timeout; i++) {
 
                if ((int)(hdsp_read (hdsp, HDSP_fifoStatus) & 0xff) <= count)
@@ -824,11 +845,11 @@ static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short
 
        if (addr >= HDSP_MATRIX_MIXER_SIZE)
                return -1;
-       
+
        if (hdsp->io_type == H9652 || hdsp->io_type == H9632) {
 
                /* from martin bjornsen:
-                  
+
                   "You can only write dwords to the
                   mixer memory which contain two
                   mixer values in the low and high
@@ -847,7 +868,7 @@ static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short
 
                hdsp->mixer_matrix[addr] = data;
 
-               
+
                /* `addr' addresses a 16-bit wide address, but
                   the address space accessed via hdsp_write
                   uses byte offsets. put another way, addr
@@ -856,17 +877,17 @@ static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short
                   to access 0 to 2703 ...
                */
                ad = addr/2;
-       
-               hdsp_write (hdsp, 4096 + (ad*4), 
-                           (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) + 
+
+               hdsp_write (hdsp, 4096 + (ad*4),
+                           (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) +
                            hdsp->mixer_matrix[addr&0x7fe]);
-               
+
                return 0;
 
        } else {
 
                ad = (addr << 16) + data;
-               
+
                if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT))
                        return -1;
 
@@ -902,7 +923,7 @@ static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
 
        if (status & HDSP_SPDIFErrorFlag)
                return 0;
-       
+
        switch (rate_bits) {
        case HDSP_spdifFrequency32KHz: return 32000;
        case HDSP_spdifFrequency44_1KHz: return 44100;
@@ -910,13 +931,13 @@ static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
        case HDSP_spdifFrequency64KHz: return 64000;
        case HDSP_spdifFrequency88_2KHz: return 88200;
        case HDSP_spdifFrequency96KHz: return 96000;
-       case HDSP_spdifFrequency128KHz: 
+       case HDSP_spdifFrequency128KHz:
                if (hdsp->io_type == H9632) return 128000;
                break;
-       case HDSP_spdifFrequency176_4KHz: 
+       case HDSP_spdifFrequency176_4KHz:
                if (hdsp->io_type == H9632) return 176400;
                break;
-       case HDSP_spdifFrequency192KHz: 
+       case HDSP_spdifFrequency192KHz:
                if (hdsp->io_type == H9632) return 192000;
                break;
        default:
@@ -1027,7 +1048,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
 {
        u64 n;
        u32 r;
-       
+
        if (rate >= 112000)
                rate /= 4;
        else if (rate >= 56000)
@@ -1053,35 +1074,35 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
           there is no need for it (e.g. during module
           initialization).
        */
-       
-       if (!(hdsp->control_register & HDSP_ClockModeMaster)) { 
+
+       if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
                if (called_internally) {
                        /* request from ctl or card initialization */
                        snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n");
                        return -1;
-               } else {                
+               } else {
                        /* hw_param request while in AutoSync mode */
                        int external_freq = hdsp_external_sample_rate(hdsp);
                        int spdif_freq = hdsp_spdif_sample_rate(hdsp);
-               
+
                        if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
                                snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n");
                        else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
-                               snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n");                     
+                               snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n");
                        else if (rate != external_freq) {
                                snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n");
                                return -1;
-                       }               
-               }       
+                       }
+               }
        }
 
        current_rate = hdsp->system_sample_rate;
 
        /* Changing from a "single speed" to a "double speed" rate is
           not allowed if any substreams are open. This is because
-          such a change causes a shift in the location of 
+          such a change causes a shift in the location of
           the DMA buffers and a reduction in the number of available
-          buffers. 
+          buffers.
 
           Note that a similar but essentially insoluble problem
           exists for externally-driven rate changes. All we can do
@@ -1089,7 +1110,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
 
        if (rate > 96000 && hdsp->io_type != H9632)
                return -EINVAL;
-       
+
        switch (rate) {
        case 32000:
                if (current_rate > 48000)
@@ -1179,7 +1200,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
                        break;
                }
        }
-       
+
        hdsp->system_sample_rate = rate;
 
        return 0;
@@ -1245,16 +1266,16 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
        unsigned char buf[128];
 
        /* Output is not interrupt driven */
-               
+
        spin_lock_irqsave (&hmidi->lock, flags);
        if (hmidi->output) {
                if (!snd_rawmidi_transmit_empty (hmidi->output)) {
                        if ((n_pending = snd_hdsp_midi_output_possible (hmidi->hdsp, hmidi->id)) > 0) {
                                if (n_pending > (int)sizeof (buf))
                                        n_pending = sizeof (buf);
-                               
+
                                if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) {
-                                       for (i = 0; i < to_write; ++i) 
+                                       for (i = 0; i < to_write; ++i)
                                                snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]);
                                }
                        }
@@ -1325,14 +1346,14 @@ static void snd_hdsp_midi_output_timer(unsigned long data)
 {
        struct hdsp_midi *hmidi = (struct hdsp_midi *) data;
        unsigned long flags;
-       
+
        snd_hdsp_midi_output_write(hmidi);
        spin_lock_irqsave (&hmidi->lock, flags);
 
        /* this does not bump hmidi->istimer, because the
           kernel automatically removed the timer when it
           expired, and we are now adding it back, thus
-          leaving istimer wherever it was set before.  
+          leaving istimer wherever it was set before.
        */
 
        if (hmidi->istimer) {
@@ -1501,7 +1522,7 @@ static int snd_hdsp_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd
 static int snd_hdsp_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif);
        return 0;
 }
@@ -1511,7 +1532,7 @@ static int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        u32 val;
-       
+
        val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
        spin_lock_irq(&hdsp->lock);
        change = val != hdsp->creg_spdif;
@@ -1530,7 +1551,7 @@ static int snd_hdsp_control_spdif_stream_info(struct snd_kcontrol *kcontrol, str
 static int snd_hdsp_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif_stream);
        return 0;
 }
@@ -1540,7 +1561,7 @@ static int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, stru
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        u32 val;
-       
+
        val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
        spin_lock_irq(&hdsp->lock);
        change = val != hdsp->creg_spdif_stream;
@@ -1602,7 +1623,7 @@ static int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_
 static int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_spdif_in(hdsp);
        return 0;
 }
@@ -1612,7 +1633,7 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3);
@@ -1649,7 +1670,7 @@ static int hdsp_set_spdif_output(struct hdsp *hdsp, int out)
 static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp);
        return 0;
 }
@@ -1659,7 +1680,7 @@ static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -1693,7 +1714,7 @@ static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val)
 static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp);
        return 0;
 }
@@ -1703,7 +1724,7 @@ static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -1737,7 +1758,7 @@ static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val)
 static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp);
        return 0;
 }
@@ -1747,7 +1768,7 @@ static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -1781,7 +1802,7 @@ static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val)
 static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp);
        return 0;
 }
@@ -1791,7 +1812,7 @@ static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -1828,7 +1849,7 @@ static int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct
 static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        switch (hdsp_spdif_sample_rate(hdsp)) {
        case 32000:
                ucontrol->value.enumerated.item[0] = 0;
@@ -1858,7 +1879,7 @@ static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct
                ucontrol->value.enumerated.item[0] = 9;
                break;
        default:
-               ucontrol->value.enumerated.item[0] = 6;         
+               ucontrol->value.enumerated.item[0] = 6;
        }
        return 0;
 }
@@ -1882,7 +1903,7 @@ static int snd_hdsp_info_system_sample_rate(struct snd_kcontrol *kcontrol, struc
 static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp->system_sample_rate;
        return 0;
 }
@@ -1899,7 +1920,7 @@ static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct
 static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};    
+       static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ;
@@ -1912,7 +1933,7 @@ static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, str
 static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        switch (hdsp_external_sample_rate(hdsp)) {
        case 32000:
                ucontrol->value.enumerated.item[0] = 0;
@@ -1940,9 +1961,9 @@ static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, stru
                break;
        case 192000:
                ucontrol->value.enumerated.item[0] = 9;
-               break;  
+               break;
        default:
-               ucontrol->value.enumerated.item[0] = 6;         
+               ucontrol->value.enumerated.item[0] = 6;
        }
        return 0;
 }
@@ -1968,7 +1989,7 @@ static int hdsp_system_clock_mode(struct hdsp *hdsp)
 static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {"Master", "Slave" };
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 2;
@@ -1981,7 +2002,7 @@ static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct
 static int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_system_clock_mode(hdsp);
        return 0;
 }
@@ -2018,7 +2039,7 @@ static int hdsp_clock_source(struct hdsp *hdsp)
                case 192000:
                        return 9;
                default:
-                       return 3;       
+                       return 3;
                }
        } else {
                return 0;
@@ -2032,7 +2053,7 @@ static int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
        case HDSP_CLOCK_SOURCE_AUTOSYNC:
                if (hdsp_external_sample_rate(hdsp) != 0) {
                    if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) {
-                       hdsp->control_register &= ~HDSP_ClockModeMaster;                
+                       hdsp->control_register &= ~HDSP_ClockModeMaster;
                        hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
                        return 0;
                    }
@@ -2043,7 +2064,7 @@ static int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
                break;
        case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
                rate = 44100;
-               break;      
+               break;
        case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
                rate = 48000;
                break;
@@ -2078,13 +2099,13 @@ static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_
 {
        static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" };
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        if (hdsp->io_type == H9632)
            uinfo->value.enumerated.items = 10;
        else
-           uinfo->value.enumerated.items = 7;  
+           uinfo->value.enumerated.items = 7;
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
@@ -2094,7 +2115,7 @@ static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_
 static int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_clock_source(hdsp);
        return 0;
 }
@@ -2104,7 +2125,7 @@ static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_c
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0];
@@ -2130,7 +2151,7 @@ static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_c
 static int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
        return 0;
 }
@@ -2165,7 +2186,7 @@ static int hdsp_da_gain(struct hdsp *hdsp)
        case HDSP_DAGainMinus10dBV:
                return 2;
        default:
-               return 1;       
+               return 1;
        }
 }
 
@@ -2180,8 +2201,8 @@ static int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
                hdsp->control_register |= HDSP_DAGainPlus4dBu;
                break;
        case 2:
-               hdsp->control_register |= HDSP_DAGainMinus10dBV;                
-               break;      
+               hdsp->control_register |= HDSP_DAGainMinus10dBV;
+               break;
        default:
                return -1;
 
@@ -2193,7 +2214,7 @@ static int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
 static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 3;
@@ -2206,7 +2227,7 @@ static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 static int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp);
        return 0;
 }
@@ -2216,7 +2237,7 @@ static int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0];
@@ -2250,7 +2271,7 @@ static int hdsp_ad_gain(struct hdsp *hdsp)
        case HDSP_ADGainLowGain:
                return 2;
        default:
-               return 1;       
+               return 1;
        }
 }
 
@@ -2262,11 +2283,11 @@ static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
                hdsp->control_register |= HDSP_ADGainMinus10dBV;
                break;
        case 1:
-               hdsp->control_register |= HDSP_ADGainPlus4dBu;          
+               hdsp->control_register |= HDSP_ADGainPlus4dBu;
                break;
        case 2:
-               hdsp->control_register |= HDSP_ADGainLowGain;           
-               break;      
+               hdsp->control_register |= HDSP_ADGainLowGain;
+               break;
        default:
                return -1;
 
@@ -2278,7 +2299,7 @@ static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
 static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 3;
@@ -2291,7 +2312,7 @@ static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 static int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp);
        return 0;
 }
@@ -2301,7 +2322,7 @@ static int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0];
@@ -2335,7 +2356,7 @@ static int hdsp_phone_gain(struct hdsp *hdsp)
        case HDSP_PhoneGainMinus12dB:
                return 2;
        default:
-               return 0;       
+               return 0;
        }
 }
 
@@ -2347,11 +2368,11 @@ static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
                hdsp->control_register |= HDSP_PhoneGain0dB;
                break;
        case 1:
-               hdsp->control_register |= HDSP_PhoneGainMinus6dB;               
+               hdsp->control_register |= HDSP_PhoneGainMinus6dB;
                break;
        case 2:
-               hdsp->control_register |= HDSP_PhoneGainMinus12dB;              
-               break;      
+               hdsp->control_register |= HDSP_PhoneGainMinus12dB;
+               break;
        default:
                return -1;
 
@@ -2363,7 +2384,7 @@ static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
 static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {"0 dB", "-6 dB", "-12 dB"};
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 3;
@@ -2376,7 +2397,7 @@ static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ct
 static int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp);
        return 0;
 }
@@ -2386,7 +2407,7 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0];
@@ -2432,7 +2453,7 @@ static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode)
 static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp);
        return 0;
 }
@@ -2442,7 +2463,7 @@ static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -2488,7 +2509,7 @@ static int hdsp_set_aeb(struct hdsp *hdsp, int mode)
 static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp);
        return 0;
 }
@@ -2498,7 +2519,7 @@ static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -2576,7 +2597,7 @@ static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd
 {
        static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" };
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
 
@@ -2595,7 +2616,7 @@ static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd
                uinfo->value.enumerated.items = 0;
                break;
        }
-               
+
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
        strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
@@ -2605,7 +2626,7 @@ static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd
 static int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp);
        return 0;
 }
@@ -2615,7 +2636,7 @@ static int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change, max;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
 
@@ -2664,7 +2685,7 @@ static int hdsp_autosync_ref(struct hdsp *hdsp)
        case HDSP_SelSyncRef_SPDIF:
                return HDSP_AUTOSYNC_FROM_SPDIF;
        case HDSP_SelSyncRefMask:
-               return HDSP_AUTOSYNC_FROM_NONE; 
+               return HDSP_AUTOSYNC_FROM_NONE;
        case HDSP_SelSyncRef_ADAT1:
                return HDSP_AUTOSYNC_FROM_ADAT1;
        case HDSP_SelSyncRef_ADAT2:
@@ -2680,7 +2701,7 @@ static int hdsp_autosync_ref(struct hdsp *hdsp)
 static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" };
-       
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 7;
@@ -2693,7 +2714,7 @@ static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_
 static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_autosync_ref(hdsp);
        return 0;
 }
@@ -2727,7 +2748,7 @@ static int hdsp_set_line_output(struct hdsp *hdsp, int out)
 static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        spin_lock_irq(&hdsp->lock);
        ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
        spin_unlock_irq(&hdsp->lock);
@@ -2739,7 +2760,7 @@ static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -2773,7 +2794,7 @@ static int hdsp_set_precise_pointer(struct hdsp *hdsp, int precise)
 static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        spin_lock_irq(&hdsp->lock);
        ucontrol->value.integer.value[0] = hdsp->precise_ptr;
        spin_unlock_irq(&hdsp->lock);
@@ -2785,7 +2806,7 @@ static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct sn
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -2819,7 +2840,7 @@ static int hdsp_set_use_midi_tasklet(struct hdsp *hdsp, int use_tasklet)
 static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        spin_lock_irq(&hdsp->lock);
        ucontrol->value.integer.value[0] = hdsp->use_midi_tasklet;
        spin_unlock_irq(&hdsp->lock);
@@ -2831,7 +2852,7 @@ static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct s
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        unsigned int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.integer.value[0] & 1;
@@ -2873,12 +2894,12 @@ static int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 
        source = ucontrol->value.integer.value[0];
        destination = ucontrol->value.integer.value[1];
-       
+
        if (source >= hdsp->max_channels)
                addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination);
        else
                addr = hdsp_input_to_output_key(hdsp,source, destination);
-       
+
        spin_lock_irq(&hdsp->lock);
        ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr);
        spin_unlock_irq(&hdsp->lock);
@@ -2926,7 +2947,7 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 
 static int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = {"No Lock", "Lock", "Sync" };    
+       static char *texts[] = {"No Lock", "Lock", "Sync" };
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = 3;
@@ -2971,7 +2992,7 @@ static int hdsp_spdif_sync_check(struct hdsp *hdsp)
        int status = hdsp_read(hdsp, HDSP_statusRegister);
        if (status & HDSP_SPDIFErrorFlag)
                return 0;
-       else {  
+       else {
                if (status & HDSP_SPDIFSync)
                        return 2;
                else
@@ -3007,7 +3028,7 @@ static int hdsp_adatsync_sync_check(struct hdsp *hdsp)
                        return 1;
        } else
                return 0;
-}      
+}
 
 static int snd_hdsp_get_adatsync_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
@@ -3025,17 +3046,17 @@ static int snd_hdsp_get_adatsync_sync_check(struct snd_kcontrol *kcontrol, struc
 }
 
 static int hdsp_adat_sync_check(struct hdsp *hdsp, int idx)
-{      
+{
        int status = hdsp_read(hdsp, HDSP_statusRegister);
-       
+
        if (status & (HDSP_Lock0>>idx)) {
                if (status & (HDSP_Sync0>>idx))
                        return 2;
                else
-                       return 1;               
+                       return 1;
        } else
                return 0;
-} 
+}
 
 static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
@@ -3053,7 +3074,7 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn
                break;
        case Multiface:
        case H9632:
-               if (offset >= 1) 
+               if (offset >= 1)
                        return -EINVAL;
                break;
        default:
@@ -3115,7 +3136,7 @@ static int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ct
 static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-       
+
        ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp);
        return 0;
 }
@@ -3125,7 +3146,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
        int change;
        int val;
-       
+
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
        val = ucontrol->value.enumerated.item[0];
@@ -3170,7 +3191,7 @@ static struct snd_kcontrol_new snd_hdsp_controls[] = {
        .get =          snd_hdsp_control_spdif_mask_get,
        .private_value = IEC958_AES0_NONAUDIO |
                         IEC958_AES0_PROFESSIONAL |
-                        IEC958_AES0_CON_EMPHASIS,                                                                                            
+                        IEC958_AES0_CON_EMPHASIS,
 },
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
@@ -3188,7 +3209,7 @@ HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
 HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0),
 HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0),
 HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
-/* 'Sample Clock Source' complies with the alsa control naming scheme */ 
+/* 'Sample Clock Source' complies with the alsa control naming scheme */
 HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -3240,7 +3261,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
                                return err;
                }
        }
-       
+
        /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */
        if (hdsp->io_type == H9632) {
                for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) {
@@ -3259,7 +3280,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 }
 
 /*------------------------------------------------------------
-   /proc interface 
+   /proc interface
  ------------------------------------------------------------*/
 
 static void
@@ -3298,7 +3319,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                        }
                }
        }
-       
+
        status = hdsp_read(hdsp, HDSP_statusRegister);
        status2 = hdsp_read(hdsp, HDSP_status2Register);
 
@@ -3362,17 +3383,17 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                break;
                case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
                clock_source = "Internal 192 kHz";
-               break;  
+               break;
        default:
-               clock_source = "Error";         
+               clock_source = "Error";
        }
        snd_iprintf (buffer, "Sample Clock Source: %s\n", clock_source);
-                       
+
        if (hdsp_system_clock_mode(hdsp))
                system_clock_mode = "Slave";
        else
                system_clock_mode = "Master";
-       
+
        switch (hdsp_pref_sync_ref (hdsp)) {
        case HDSP_SYNC_FROM_WORD:
                pref_sync_ref = "Word Clock";
@@ -3397,7 +3418,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                break;
        }
        snd_iprintf (buffer, "Preferred Sync Reference: %s\n", pref_sync_ref);
-       
+
        switch (hdsp_autosync_ref (hdsp)) {
        case HDSP_AUTOSYNC_FROM_WORD:
                autosync_ref = "Word Clock";
@@ -3410,7 +3431,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                break;
        case HDSP_AUTOSYNC_FROM_NONE:
                autosync_ref = "None";
-               break;  
+               break;
        case HDSP_AUTOSYNC_FROM_ADAT1:
                autosync_ref = "ADAT1";
                break;
@@ -3425,14 +3446,14 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                break;
        }
        snd_iprintf (buffer, "AutoSync Reference: %s\n", autosync_ref);
-       
+
        snd_iprintf (buffer, "AutoSync Frequency: %d\n", hdsp_external_sample_rate(hdsp));
-       
+
        snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
 
        snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
        snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
-               
+
        snd_iprintf(buffer, "\n");
 
        switch (hdsp_spdif_in(hdsp)) {
@@ -3452,7 +3473,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                snd_iprintf(buffer, "IEC958 input: ???\n");
                break;
        }
-       
+
        if (hdsp->control_register & HDSP_SPDIFOpticalOut)
                snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
        else
@@ -3510,13 +3531,13 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                snd_iprintf (buffer, "SPDIF: No Lock\n");
        else
                snd_iprintf (buffer, "SPDIF: %s\n", x ? "Sync" : "Lock");
-       
+
        x = status2 & HDSP_wc_sync;
        if (status2 & HDSP_wc_lock)
                snd_iprintf (buffer, "Word Clock: %s\n", x ? "Sync" : "Lock");
        else
                snd_iprintf (buffer, "Word Clock: No Lock\n");
-       
+
        x = status & HDSP_TimecodeSync;
        if (status & HDSP_TimecodeLock)
                snd_iprintf(buffer, "ADAT Sync: %s\n", x ? "Sync" : "Lock");
@@ -3524,11 +3545,11 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                snd_iprintf(buffer, "ADAT Sync: No Lock\n");
 
        snd_iprintf(buffer, "\n");
-       
+
        /* Informations about H9632 specific controls */
        if (hdsp->io_type == H9632) {
                char *tmp;
-       
+
                switch (hdsp_ad_gain(hdsp)) {
                case 0:
                        tmp = "-10 dBV";
@@ -3554,7 +3575,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                        break;
                }
                snd_iprintf(buffer, "DA Gain : %s\n", tmp);
-               
+
                switch (hdsp_phone_gain(hdsp)) {
                case 0:
                        tmp = "0 dB";
@@ -3568,8 +3589,8 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
                }
                snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
 
-               snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); 
-               
+               snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no");
+
                if (hdsp->control_register & HDSP_AnalogExtensionBoard)
                        snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
                else
@@ -3632,18 +3653,18 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
 
        /* set defaults:
 
-          SPDIF Input via Coax 
+          SPDIF Input via Coax
           Master clock mode
           maximum latency (7 => 2^7 = 8192 samples, 64Kbyte buffer,
                            which implies 2 4096 sample, 32Kbyte periods).
-           Enable line out.                        
+           Enable line out.
         */
 
-       hdsp->control_register = HDSP_ClockModeMaster | 
-                                HDSP_SPDIFInputCoaxial | 
-                                hdsp_encode_latency(7) | 
+       hdsp->control_register = HDSP_ClockModeMaster |
+                                HDSP_SPDIFInputCoaxial |
+                                hdsp_encode_latency(7) |
                                 HDSP_LineOut;
-       
+
 
        hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
 
@@ -3661,7 +3682,7 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
        hdsp_compute_period_size(hdsp);
 
        /* silence everything */
-       
+
        for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i)
                hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN;
 
@@ -3669,7 +3690,7 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
                if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN))
                        return -EIO;
        }
-       
+
        /* H9632 specific defaults */
        if (hdsp->io_type == H9632) {
                hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB);
@@ -3687,12 +3708,12 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
 static void hdsp_midi_tasklet(unsigned long arg)
 {
        struct hdsp *hdsp = (struct hdsp *)arg;
-       
+
        if (hdsp->midi[0].pending)
                snd_hdsp_midi_input_read (&hdsp->midi[0]);
        if (hdsp->midi[1].pending)
                snd_hdsp_midi_input_read (&hdsp->midi[1]);
-} 
+}
 
 static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
 {
@@ -3704,7 +3725,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
        unsigned int midi0status;
        unsigned int midi1status;
        int schedule = 0;
-       
+
        status = hdsp_read(hdsp, HDSP_statusRegister);
 
        audio = status & HDSP_audioIRQPending;
@@ -3718,15 +3739,18 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
 
        midi0status = hdsp_read (hdsp, HDSP_midiStatusIn0) & 0xff;
        midi1status = hdsp_read (hdsp, HDSP_midiStatusIn1) & 0xff;
-       
+
+       if (!(hdsp->state & HDSP_InitializationComplete))
+               return IRQ_HANDLED;
+
        if (audio) {
                if (hdsp->capture_substream)
                        snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
-               
+
                if (hdsp->playback_substream)
                        snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
        }
-       
+
        if (midi0 && midi0status) {
                if (hdsp->use_midi_tasklet) {
                        /* we disable interrupts for this input until processing is done */
@@ -3769,10 +3793,10 @@ static char *hdsp_channel_buffer_location(struct hdsp *hdsp,
 
         if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
                return NULL;
-        
+
        if ((mapped_channel = hdsp->channel_map[channel]) < 0)
                return NULL;
-       
+
        if (stream == SNDRV_PCM_STREAM_CAPTURE)
                return hdsp->capture_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
        else
@@ -3965,7 +3989,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
        struct hdsp *hdsp = snd_pcm_substream_chip(substream);
        struct snd_pcm_substream *other;
        int running;
-       
+
        if (hdsp_check_for_iobox (hdsp))
                return -EIO;
 
@@ -4059,10 +4083,10 @@ static struct snd_pcm_hardware snd_hdsp_playback_subinfo =
        .formats =              SNDRV_PCM_FMTBIT_S32_LE,
 #endif
        .rates =                (SNDRV_PCM_RATE_32000 |
-                                SNDRV_PCM_RATE_44100 | 
-                                SNDRV_PCM_RATE_48000 | 
-                                SNDRV_PCM_RATE_64000 | 
-                                SNDRV_PCM_RATE_88200 | 
+                                SNDRV_PCM_RATE_44100 |
+                                SNDRV_PCM_RATE_48000 |
+                                SNDRV_PCM_RATE_64000 |
+                                SNDRV_PCM_RATE_88200 |
                                 SNDRV_PCM_RATE_96000),
        .rate_min =             32000,
        .rate_max =             96000,
@@ -4088,10 +4112,10 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo =
        .formats =              SNDRV_PCM_FMTBIT_S32_LE,
 #endif
        .rates =                (SNDRV_PCM_RATE_32000 |
-                                SNDRV_PCM_RATE_44100 | 
-                                SNDRV_PCM_RATE_48000 | 
-                                SNDRV_PCM_RATE_64000 | 
-                                SNDRV_PCM_RATE_88200 | 
+                                SNDRV_PCM_RATE_44100 |
+                                SNDRV_PCM_RATE_48000 |
+                                SNDRV_PCM_RATE_64000 |
+                                SNDRV_PCM_RATE_88200 |
                                 SNDRV_PCM_RATE_96000),
        .rate_min =             32000,
        .rate_max =             96000,
@@ -4170,7 +4194,7 @@ static int snd_hdsp_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
                        .max = hdsp->qs_in_channels,
                        .integer = 1,
                };
-               return snd_interval_refine(c, &t);      
+               return snd_interval_refine(c, &t);
        } else if (r->min > 48000 && r->max <= 96000) {
                struct snd_interval t = {
                        .min = hdsp->ds_in_channels,
@@ -4201,7 +4225,7 @@ static int snd_hdsp_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
                        .max = hdsp->qs_out_channels,
                        .integer = 1,
                };
-               return snd_interval_refine(c, &t);      
+               return snd_interval_refine(c, &t);
        } else if (r->min > 48000 && r->max <= 96000) {
                struct snd_interval t = {
                        .min = hdsp->ds_out_channels,
@@ -4318,8 +4342,8 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
        if (hdsp->io_type == H9632) {
                runtime->hw.channels_min = hdsp->qs_out_channels;
                runtime->hw.channels_max = hdsp->ss_out_channels;
-       }       
-       
+       }
+
        snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
                             snd_hdsp_hw_rule_out_channels, hdsp,
                             SNDRV_PCM_HW_PARAM_CHANNELS, -1);
@@ -4413,13 +4437,6 @@ static int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int snd_hdsp_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file)
-{
-       /* we have nothing to initialize but the call is required */
-       return 0;
-}
-
-
 /* helper functions for copying meter values */
 static inline int copy_u32_le(void __user *dest, void __iomem *src)
 {
@@ -4536,7 +4553,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
                                hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4,
                                hdsp->iobase + HDSP_playbackRmsLevel + i * 8))
                        return -EFAULT;
-               if (copy_u64_le(&peak_rms->input_rms[i], 
+               if (copy_u64_le(&peak_rms->input_rms[i],
                                hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4,
                                hdsp->iobase + HDSP_inputRmsLevel + i * 8))
                        return -EFAULT;
@@ -4546,7 +4563,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
 
 static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct hdsp *hdsp = (struct hdsp *)hw->private_data;    
+       struct hdsp *hdsp = (struct hdsp *)hw->private_data;
        void __user *argp = (void __user *)arg;
        int err;
 
@@ -4580,7 +4597,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                struct hdsp_config_info info;
                unsigned long flags;
                int i;
-               
+
                err = hdsp_check_for_iobox(hdsp);
                if (err < 0)
                        return err;
@@ -4614,7 +4631,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
                        info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
                        info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
-               
+
                }
                if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
                        info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
@@ -4625,7 +4642,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
        }
        case SNDRV_HDSP_IOCTL_GET_9632_AEB: {
                struct hdsp_9632_aeb h9632_aeb;
-               
+
                if (hdsp->io_type != H9632) return -EINVAL;
                h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS;
                h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS;
@@ -4636,7 +4653,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
        case SNDRV_HDSP_IOCTL_GET_VERSION: {
                struct hdsp_version hdsp_version;
                int err;
-               
+
                if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
                if (hdsp->io_type == Undefined) {
                        if ((err = hdsp_get_iobox_version(hdsp)) < 0)
@@ -4652,7 +4669,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                struct hdsp_firmware __user *firmware;
                u32 __user *firmware_data;
                int err;
-               
+
                if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
                /* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
                if (hdsp->io_type == Undefined) return -EINVAL;
@@ -4665,25 +4682,25 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
 
                if (get_user(firmware_data, &firmware->firmware_data))
                        return -EFAULT;
-               
+
                if (hdsp_check_for_iobox (hdsp))
                        return -EIO;
 
                if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0)
                        return -EFAULT;
-               
+
                hdsp->state |= HDSP_FirmwareCached;
 
                if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
                        return err;
-               
+
                if (!(hdsp->state & HDSP_InitializationComplete)) {
                        if ((err = snd_hdsp_enable_io(hdsp)) < 0)
                                return err;
-                       
-                       snd_hdsp_initialize_channels(hdsp);             
+
+                       snd_hdsp_initialize_channels(hdsp);
                        snd_hdsp_initialize_midi_flush(hdsp);
-           
+
                        if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
                                snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
                                return err;
@@ -4730,18 +4747,16 @@ static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
 {
        struct snd_hwdep *hw;
        int err;
-       
+
        if ((err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw)) < 0)
                return err;
-               
+
        hdsp->hwdep = hw;
        hw->private_data = hdsp;
        strcpy(hw->name, "HDSP hwdep interface");
 
-       hw->ops.open = snd_hdsp_hwdep_dummy_op;
        hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
-       hw->ops.release = snd_hdsp_hwdep_dummy_op;
-               
+
        return 0;
 }
 
@@ -4774,24 +4789,24 @@ static void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp)
 static int snd_hdsp_enable_io (struct hdsp *hdsp)
 {
        int i;
-       
+
        if (hdsp_fifo_wait (hdsp, 0, 100)) {
                snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n");
                return -EIO;
        }
-       
+
        for (i = 0; i < hdsp->max_channels; ++i) {
                hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1);
                hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1);
        }
-       
+
        return 0;
 }
 
 static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
 {
        int status, aebi_channels, aebo_channels;
-       
+
        switch (hdsp->io_type) {
        case Digiface:
                hdsp->card_name = "RME Hammerfall DSP + Digiface";
@@ -4804,7 +4819,7 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
                hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS;
                hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS;
                break;
-       
+
        case H9632:
                status = hdsp_read(hdsp, HDSP_statusRegister);
                /* HDSP_AEBx bits are low when AEB are connected */
@@ -4824,7 +4839,7 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
                hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS;
                hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
                break;
-               
+
        default:
                /* should never get here */
                break;
@@ -4840,12 +4855,12 @@ static void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp)
 static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp)
 {
        int err;
-       
+
        if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
                snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n");
                return err;
        }
-       
+
 
        if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
                snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n");
@@ -4876,19 +4891,19 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
                snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n");
                return err;
        }
-       
+
        if (!(hdsp->state & HDSP_InitializationComplete)) {
                strcpy(card->shortname, "Hammerfall DSP");
-               sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, 
+               sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
                        hdsp->port, hdsp->irq);
-           
+
                if ((err = snd_card_register(card)) < 0) {
                        snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n");
                        return err;
                }
                hdsp->state |= HDSP_InitializationComplete;
        }
-       
+
        return 0;
 }
 
@@ -4899,7 +4914,7 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
        const char *fwfile;
        const struct firmware *fw;
        int err;
-               
+
        if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
                return 0;
        if (hdsp->io_type == Undefined) {
@@ -4908,7 +4923,7 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
                if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
                        return 0;
        }
-       
+
        /* caution: max length of firmware filename is 30! */
        switch (hdsp->io_type) {
        case Multiface:
@@ -4942,12 +4957,12 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
        memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache));
 
        release_firmware(fw);
-               
+
        hdsp->state |= HDSP_FirmwareCached;
 
        if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
                return err;
-               
+
        if (!(hdsp->state & HDSP_InitializationComplete)) {
                if ((err = snd_hdsp_enable_io(hdsp)) < 0)
                        return err;
@@ -4994,14 +5009,14 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
        hdsp->max_channels = 26;
 
        hdsp->card = card;
-       
+
        spin_lock_init(&hdsp->lock);
 
        tasklet_init(&hdsp->midi_tasklet, hdsp_midi_tasklet, (unsigned long)hdsp);
-       
+
        pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
        hdsp->firmware_rev &= 0xff;
-       
+
        /* From Martin Bjoernsen :
            "It is important that the card's latency timer register in
            the PCI configuration space is set to a value much larger
@@ -5010,7 +5025,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
            to its maximum 255 to avoid problems with some computers."
        */
        pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF);
-       
+
        strcpy(card->driver, "H-DSP");
        strcpy(card->mixername, "Xilinx FPGA");
 
@@ -5024,7 +5039,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
        } else {
                hdsp->card_name = "RME HDSP 9632";
                hdsp->max_channels = 16;
-               is_9632 = 1;    
+               is_9632 = 1;
        }
 
        if ((err = pci_enable_device(pci)) < 0)
@@ -5053,12 +5068,12 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
 
        if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
                return err;
-       
+
        if (!is_9652 && !is_9632) {
-               /* we wait 2 seconds to let freshly inserted cardbus cards do their hardware init */
-               ssleep(2);
+               /* we wait a maximum of 10 seconds to let freshly
+                * inserted cardbus cards do their hardware init */
+               err = hdsp_wait_for_iobox(hdsp, 1000, 10);
 
-               err = hdsp_check_for_iobox(hdsp);
                if (err < 0)
                        return err;
 
@@ -5080,35 +5095,35 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
                                return err;
                        return 0;
                } else {
-                       snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");     
+                       snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
                        if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
                                hdsp->io_type = Multiface;
-                       else 
+                       else
                                hdsp->io_type = Digiface;
                }
        }
-       
+
        if ((err = snd_hdsp_enable_io(hdsp)) != 0)
                return err;
-       
+
        if (is_9652)
                hdsp->io_type = H9652;
-       
+
        if (is_9632)
                hdsp->io_type = H9632;
 
        if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
                return err;
-       
+
        snd_hdsp_initialize_channels(hdsp);
        snd_hdsp_initialize_midi_flush(hdsp);
 
-       hdsp->state |= HDSP_FirmwareLoaded;     
+       hdsp->state |= HDSP_FirmwareLoaded;
 
        if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0)
                return err;
 
-       return 0;       
+       return 0;
 }
 
 static int snd_hdsp_free(struct hdsp *hdsp)
@@ -5124,13 +5139,13 @@ static int snd_hdsp_free(struct hdsp *hdsp)
                free_irq(hdsp->irq, (void *)hdsp);
 
        snd_hdsp_free_buffers(hdsp);
-       
+
        if (hdsp->iobase)
                iounmap(hdsp->iobase);
 
        if (hdsp->port)
                pci_release_regions(hdsp->pci);
-               
+
        pci_disable_device(hdsp->pci);
        return 0;
 }
@@ -5158,8 +5173,10 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       if (!(card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct hdsp))))
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct hdsp), &card);
+       if (err < 0)
+               return err;
 
        hdsp = (struct hdsp *) card->private_data;
        card->private_free = snd_hdsp_card_free;
@@ -5173,7 +5190,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
        }
 
        strcpy(card->shortname, "Hammerfall DSP");
-       sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, 
+       sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
                hdsp->port, hdsp->irq);
 
        if ((err = snd_card_register(card)) < 0) {
index 71231cf1b2b0ac2c335236d40ba4a5f99543d47b..bac2dc0c5d85698bd7bb6796525b6f622d2fbe3d 100644 (file)
@@ -4100,13 +4100,6 @@ static int snd_hdspm_capture_release(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep * hw, struct file *file)
-{
-       /* we have nothing to initialize but the call is required */
-       return 0;
-}
-
-
 static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
                                 unsigned int cmd, unsigned long arg)
 {
@@ -4213,9 +4206,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card,
        hw->private_data = hdspm;
        strcpy(hw->name, "HDSPM hwdep interface");
 
-       hw->ops.open = snd_hdspm_hwdep_dummy_op;
        hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
-       hw->ops.release = snd_hdspm_hwdep_dummy_op;
 
        return 0;
 }
@@ -4503,10 +4494,10 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev],
-                           THIS_MODULE, sizeof(struct hdspm));
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev],
+                             THIS_MODULE, sizeof(struct hdspm), &card);
+       if (err < 0)
+               return err;
 
        hdspm = card->private_data;
        card->private_free = snd_hdspm_card_free;
index 2570907134d75cd89067b14865fbd90355749df9..bc539abb210582c01797a4115916e00088f3be92 100644 (file)
@@ -2594,11 +2594,11 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_rme9652));
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_rme9652), &card);
 
-       if (!card)
-               return -ENOMEM;
+       if (err < 0)
+               return err;
 
        rme9652 = (struct snd_rme9652 *) card->private_data;
        card->private_free = snd_rme9652_card_free;
index df2007e3be7cbf63bb18f68c3ee144b6b5a1520b..baf6d8e3dabc3e703f21337c79f5c25fceb6926c 100644 (file)
@@ -1387,9 +1387,8 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci,
        if (!enable)
                goto error_out;
 
-       rc = -ENOMEM;
-       card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis));
-       if (!card)
+       rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
+       if (rc < 0)
                goto error_out;
 
        strcpy(card->driver, "SiS7019");
index cd408b86c839b1833e6f6a743f3459cc780cf10a..d989215f35563cbbe3b4cfde16cc3256391d3ba5 100644 (file)
@@ -273,7 +273,8 @@ static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic,
        outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
        outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
 #if 0
-       printk("program dmaa: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
+       printk(KERN_DEBUG "program dmaa: addr = 0x%x, paddr = 0x%x\n",
+              addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
 #endif
 }
 
@@ -288,7 +289,8 @@ static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic,
        outl(count, sonic->dmac_port + SV_DMA_COUNT0);
        outb(0x14, sonic->dmac_port + SV_DMA_MODE);
 #if 0
-       printk("program dmac: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
+       printk(KERN_DEBUG "program dmac: addr = 0x%x, paddr = 0x%x\n",
+              addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
 #endif
 }
 
@@ -355,71 +357,104 @@ static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char
 #if 0
 static void snd_sonicvibes_debug(struct sonicvibes * sonic)
 {
-       printk("SV REGS:          INDEX = 0x%02x  ", inb(SV_REG(sonic, INDEX)));
+       printk(KERN_DEBUG
+              "SV REGS:          INDEX = 0x%02x  ", inb(SV_REG(sonic, INDEX)));
        printk("                 STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS)));
-       printk("  0x00: left input      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x00));
+       printk(KERN_DEBUG
+              "  0x00: left input      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x00));
        printk("  0x20: synth rate low  = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20));
-       printk("  0x01: right input     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x01));
+       printk(KERN_DEBUG
+              "  0x01: right input     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x01));
        printk("  0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21));
-       printk("  0x02: left AUX1       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x02));
+       printk(KERN_DEBUG
+              "  0x02: left AUX1       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x02));
        printk("  0x22: ADC clock       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22));
-       printk("  0x03: right AUX1      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x03));
+       printk(KERN_DEBUG
+              "  0x03: right AUX1      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x03));
        printk("  0x23: ADC alt rate    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23));
-       printk("  0x04: left CD         = 0x%02x  ", snd_sonicvibes_in(sonic, 0x04));
+       printk(KERN_DEBUG
+              "  0x04: left CD         = 0x%02x  ", snd_sonicvibes_in(sonic, 0x04));
        printk("  0x24: ADC pll M       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24));
-       printk("  0x05: right CD        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x05));
+       printk(KERN_DEBUG
+              "  0x05: right CD        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x05));
        printk("  0x25: ADC pll N       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25));
-       printk("  0x06: left line       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x06));
+       printk(KERN_DEBUG
+              "  0x06: left line       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x06));
        printk("  0x26: Synth pll M     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26));
-       printk("  0x07: right line      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x07));
+       printk(KERN_DEBUG
+              "  0x07: right line      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x07));
        printk("  0x27: Synth pll N     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27));
-       printk("  0x08: MIC             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x08));
+       printk(KERN_DEBUG
+              "  0x08: MIC             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x08));
        printk("  0x28: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28));
-       printk("  0x09: Game port       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x09));
+       printk(KERN_DEBUG
+              "  0x09: Game port       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x09));
        printk("  0x29: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29));
-       printk("  0x0a: left synth      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0a));
+       printk(KERN_DEBUG
+              "  0x0a: left synth      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0a));
        printk("  0x2a: MPU401          = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a));
-       printk("  0x0b: right synth     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0b));
+       printk(KERN_DEBUG
+              "  0x0b: right synth     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0b));
        printk("  0x2b: drive ctrl      = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b));
-       printk("  0x0c: left AUX2       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0c));
+       printk(KERN_DEBUG
+              "  0x0c: left AUX2       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0c));
        printk("  0x2c: SRS space       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c));
-       printk("  0x0d: right AUX2      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0d));
+       printk(KERN_DEBUG
+              "  0x0d: right AUX2      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0d));
        printk("  0x2d: SRS center      = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d));
-       printk("  0x0e: left analog     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0e));
+       printk(KERN_DEBUG
+              "  0x0e: left analog     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0e));
        printk("  0x2e: wave source     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e));
-       printk("  0x0f: right analog    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0f));
+       printk(KERN_DEBUG
+              "  0x0f: right analog    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0f));
        printk("  0x2f: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f));
-       printk("  0x10: left PCM        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x10));
+       printk(KERN_DEBUG
+              "  0x10: left PCM        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x10));
        printk("  0x30: analog power    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30));
-       printk("  0x11: right PCM       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x11));
+       printk(KERN_DEBUG
+              "  0x11: right PCM       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x11));
        printk("  0x31: analog power    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31));
-       printk("  0x12: DMA data format = 0x%02x  ", snd_sonicvibes_in(sonic, 0x12));
+       printk(KERN_DEBUG
+              "  0x12: DMA data format = 0x%02x  ", snd_sonicvibes_in(sonic, 0x12));
        printk("  0x32: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32));
-       printk("  0x13: P/C enable      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x13));
+       printk(KERN_DEBUG
+              "  0x13: P/C enable      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x13));
        printk("  0x33: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33));
-       printk("  0x14: U/D button      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x14));
+       printk(KERN_DEBUG
+              "  0x14: U/D button      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x14));
        printk("  0x34: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34));
-       printk("  0x15: revision        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x15));
+       printk(KERN_DEBUG
+              "  0x15: revision        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x15));
        printk("  0x35: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35));
-       printk("  0x16: ADC output ctrl = 0x%02x  ", snd_sonicvibes_in(sonic, 0x16));
+       printk(KERN_DEBUG
+              "  0x16: ADC output ctrl = 0x%02x  ", snd_sonicvibes_in(sonic, 0x16));
        printk("  0x36: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36));
-       printk("  0x17: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x17));
+       printk(KERN_DEBUG
+              "  0x17: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x17));
        printk("  0x37: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37));
-       printk("  0x18: DMA A upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x18));
+       printk(KERN_DEBUG
+              "  0x18: DMA A upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x18));
        printk("  0x38: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38));
-       printk("  0x19: DMA A lower cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x19));
+       printk(KERN_DEBUG
+              "  0x19: DMA A lower cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x19));
        printk("  0x39: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39));
-       printk("  0x1a: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1a));
+       printk(KERN_DEBUG
+              "  0x1a: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1a));
        printk("  0x3a: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a));
-       printk("  0x1b: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1b));
+       printk(KERN_DEBUG
+              "  0x1b: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1b));
        printk("  0x3b: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b));
-       printk("  0x1c: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1c));
+       printk(KERN_DEBUG
+              "  0x1c: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1c));
        printk("  0x3c: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c));
-       printk("  0x1d: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1d));
+       printk(KERN_DEBUG
+              "  0x1d: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1d));
        printk("  0x3d: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d));
-       printk("  0x1e: PCM rate low    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1e));
+       printk(KERN_DEBUG
+              "  0x1e: PCM rate low    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1e));
        printk("  0x3e: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e));
-       printk("  0x1f: PCM rate high   = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1f));
+       printk(KERN_DEBUG
+              "  0x1f: PCM rate high   = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1f));
        printk("  0x3f: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f));
 }
 
@@ -476,8 +511,8 @@ static void snd_sonicvibes_pll(unsigned int rate,
        *res_m = m;
        *res_n = n;
 #if 0
-       printk("metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
-       printk("pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
+       printk(KERN_DEBUG "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
+       printk(KERN_DEBUG "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
 #endif
 }
 
@@ -1423,9 +1458,9 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
                return -ENOENT;
        }
  
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
        for (idx = 0; idx < 5; idx++) {
                if (pci_resource_start(pci, idx) == 0 ||
                    !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) {
index d94b16ffb38554660a8bd2647ad4d9024be2927f..21cef97d478dc8fb0a127d73453714d886facedf 100644 (file)
@@ -89,9 +89,9 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_trident_create(card, pci,
                                      pcm_channels[dev],
index c612b435ca2bc6cd43a7ba77ce8ceb4dd81c6a3a..a9da9c184660cf25d8c1748ceba8b4475e83167e 100644 (file)
@@ -68,40 +68,40 @@ static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice)
 {
        unsigned int val, tmp;
 
-       printk("Trident voice %i:\n", voice);
+       printk(KERN_DEBUG "Trident voice %i:\n", voice);
        outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));
        val = inl(TRID_REG(trident, CH_LBA));
-       printk("LBA: 0x%x\n", val);
+       printk(KERN_DEBUG "LBA: 0x%x\n", val);
        val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
-       printk("GVSel: %i\n", val >> 31);
-       printk("Pan: 0x%x\n", (val >> 24) & 0x7f);
-       printk("Vol: 0x%x\n", (val >> 16) & 0xff);
-       printk("CTRL: 0x%x\n", (val >> 12) & 0x0f);
-       printk("EC: 0x%x\n", val & 0x0fff);
+       printk(KERN_DEBUG "GVSel: %i\n", val >> 31);
+       printk(KERN_DEBUG "Pan: 0x%x\n", (val >> 24) & 0x7f);
+       printk(KERN_DEBUG "Vol: 0x%x\n", (val >> 16) & 0xff);
+       printk(KERN_DEBUG "CTRL: 0x%x\n", (val >> 12) & 0x0f);
+       printk(KERN_DEBUG "EC: 0x%x\n", val & 0x0fff);
        if (trident->device != TRIDENT_DEVICE_ID_NX) {
                val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));
-               printk("CSO: 0x%x\n", val >> 16);
+               printk(KERN_DEBUG "CSO: 0x%x\n", val >> 16);
                printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff);
-               printk("FMS: 0x%x\n", val & 0x0f);
+               printk(KERN_DEBUG "FMS: 0x%x\n", val & 0x0f);
                val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));
-               printk("ESO: 0x%x\n", val >> 16);
-               printk("Delta: 0x%x\n", val & 0xffff);
+               printk(KERN_DEBUG "ESO: 0x%x\n", val >> 16);
+               printk(KERN_DEBUG "Delta: 0x%x\n", val & 0xffff);
                val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
        } else {                // TRIDENT_DEVICE_ID_NX
                val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));
                tmp = (val >> 24) & 0xff;
-               printk("CSO: 0x%x\n", val & 0x00ffffff);
+               printk(KERN_DEBUG "CSO: 0x%x\n", val & 0x00ffffff);
                val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));
                tmp |= (val >> 16) & 0xff00;
-               printk("Delta: 0x%x\n", tmp);
-               printk("ESO: 0x%x\n", val & 0x00ffffff);
+               printk(KERN_DEBUG "Delta: 0x%x\n", tmp);
+               printk(KERN_DEBUG "ESO: 0x%x\n", val & 0x00ffffff);
                val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));
-               printk("Alpha: 0x%x\n", val >> 20);
-               printk("FMS: 0x%x\n", (val >> 16) & 0x0f);
+               printk(KERN_DEBUG "Alpha: 0x%x\n", val >> 20);
+               printk(KERN_DEBUG "FMS: 0x%x\n", (val >> 16) & 0x0f);
        }
-       printk("FMC: 0x%x\n", (val >> 14) & 3);
-       printk("RVol: 0x%x\n", (val >> 7) & 0x7f);
-       printk("CVol: 0x%x\n", val & 0x7f);
+       printk(KERN_DEBUG "FMC: 0x%x\n", (val >> 14) & 3);
+       printk(KERN_DEBUG "RVol: 0x%x\n", (val >> 7) & 0x7f);
+       printk(KERN_DEBUG "CVol: 0x%x\n", val & 0x7f);
 }
 #endif
 
@@ -496,12 +496,17 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
        outl(regs[4], TRID_REG(trident, CH_START + 16));
 
 #if 0
-       printk("written %i channel:\n", voice->number);
-       printk("  regs[0] = 0x%x/0x%x\n", regs[0], inl(TRID_REG(trident, CH_START + 0)));
-       printk("  regs[1] = 0x%x/0x%x\n", regs[1], inl(TRID_REG(trident, CH_START + 4)));
-       printk("  regs[2] = 0x%x/0x%x\n", regs[2], inl(TRID_REG(trident, CH_START + 8)));
-       printk("  regs[3] = 0x%x/0x%x\n", regs[3], inl(TRID_REG(trident, CH_START + 12)));
-       printk("  regs[4] = 0x%x/0x%x\n", regs[4], inl(TRID_REG(trident, CH_START + 16)));
+       printk(KERN_DEBUG "written %i channel:\n", voice->number);
+       printk(KERN_DEBUG "  regs[0] = 0x%x/0x%x\n",
+              regs[0], inl(TRID_REG(trident, CH_START + 0)));
+       printk(KERN_DEBUG "  regs[1] = 0x%x/0x%x\n",
+              regs[1], inl(TRID_REG(trident, CH_START + 4)));
+       printk(KERN_DEBUG "  regs[2] = 0x%x/0x%x\n",
+              regs[2], inl(TRID_REG(trident, CH_START + 8)));
+       printk(KERN_DEBUG "  regs[3] = 0x%x/0x%x\n",
+              regs[3], inl(TRID_REG(trident, CH_START + 12)));
+       printk(KERN_DEBUG "  regs[4] = 0x%x/0x%x\n",
+              regs[4], inl(TRID_REG(trident, CH_START + 16)));
 #endif
 }
 
@@ -583,7 +588,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident,
                outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2));
                break;
        case TRIDENT_DEVICE_ID_SI7018:
-               // printk("voice->Vol = 0x%x\n", voice->Vol);
+               /* printk(KERN_DEBUG "voice->Vol = 0x%x\n", voice->Vol); */
                outw((voice->CTRL << 12) | voice->Vol,
                     TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
                break;
index 1aafe956ee2b348d07d02925b6aa1fdd9ec7f7ee..809b233dd4a3add8cb7ef357ae6291a8ad3f083a 100644 (file)
@@ -466,7 +466,10 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                                        flag = VIA_TBL_BIT_FLAG; /* period boundary */
                        } else
                                flag = 0; /* period continues to the next */
-                       // printk("via: tbl %d: at %d  size %d (rest %d)\n", idx, ofs, r, rest);
+                       /*
+                       printk(KERN_DEBUG "via: tbl %d: at %d  size %d "
+                              "(rest %d)\n", idx, ofs, r, rest);
+                       */
                        ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
                        dev->idx_table[idx].offset = ofs;
                        dev->idx_table[idx].size = r;
@@ -2360,14 +2363,14 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
        SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K),
        SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA),
        SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA),
-       SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1019, "ESC K8", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA),
        SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC),
-       SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA),
-       SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS A7/A8", VIA_DXS_NO_VRA),
+       SND_PCI_QUIRK_VENDOR(0x1071, "Diverse Notebook", VIA_DXS_NO_VRA),
        SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
-       SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1106, "ASRock", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_SRC),
@@ -2375,7 +2378,7 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
        SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE),
-       SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1462, "MSI Mobo", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE),
@@ -2389,11 +2392,11 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
        SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K),
        SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE),
-       SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC),
-       SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC),
-       SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1695, "EPoX mobo", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x16f3, "Jetway K8", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1734, "FSC Laptop", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA),
-       SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC),
+       SND_PCI_QUIRK_VENDOR(0x1849, "ASRock mobo", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8",  VIA_DXS_NO_VRA),
        SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC),
        { } /* terminator */
@@ -2433,9 +2436,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
        unsigned int i;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        card_type = pci_id->driver_data;
        switch (card_type) {
index 5bd79d2a5a1555d80ba7466eca75baab6804714b..0d54e3503c1e6edc4ad80d23f246aa3b034aab12 100644 (file)
@@ -328,7 +328,10 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                                        flag = VIA_TBL_BIT_FLAG; /* period boundary */
                        } else
                                flag = 0; /* period continues to the next */
-                       // printk("via: tbl %d: at %d  size %d (rest %d)\n", idx, ofs, r, rest);
+                       /*
+                       printk(KERN_DEBUG "via: tbl %d: at %d  size %d "
+                              "(rest %d)\n", idx, ofs, r, rest);
+                       */
                        ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
                        dev->idx_table[idx].offset = ofs;
                        dev->idx_table[idx].size = r;
@@ -1167,9 +1170,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
        unsigned int i;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        card_type = pci_id->driver_data;
        switch (card_type) {
index acc352f4a44182f5f782fae7301d8bdde0eec235..fc9136c3e0d7824a67d88d4bbc5781e4b7ac375d 100644 (file)
@@ -204,9 +204,9 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        switch ((int)pci_id->driver_data) {
        case VX_PCI_VX222_OLD:
index 7e87f398ff0bda688caa6f212198b881da687445..c0efe4491116bf1857255bbb6a1dcde1e91afe3e 100644 (file)
@@ -107,7 +107,9 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset)
 static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
 {
        outb(val, vx2_reg_addr(chip, offset));
-       //printk("outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       /*
+       printk(KERN_DEBUG "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       */
 }
 
 /**
@@ -126,7 +128,9 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
  */
 static void vx2_outl(struct vx_core *chip, int offset, unsigned int val)
 {
-       // printk("outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       /*
+       printk(KERN_DEBUG "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       */
        outl(val, vx2_reg_addr(chip, offset));
 }
 
index 2631a554845e66c32ac446c283076061f092cfb3..4af66661f9b020b83956559847848b51647fde97 100644 (file)
@@ -187,9 +187,9 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        switch (pci_id->device) {
        case 0x0004: str = "YMF724";  model = "DS-1"; break;
index 90d0d62bd0b40648406bd1db328c280fc572dbfe..2f0925236a1b9c532acaa4c4e6a0273f44a75d0a 100644 (file)
@@ -318,7 +318,12 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
                ypcm->period_pos += delta;
                ypcm->last_pos = pos;
                if (ypcm->period_pos >= ypcm->period_size) {
-                       // printk("done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start);
+                       /*
+                       printk(KERN_DEBUG
+                              "done - active_bank = 0x%x, start = 0x%x\n",
+                              chip->active_bank,
+                              voice->bank[chip->active_bank].start);
+                       */
                        ypcm->period_pos %= ypcm->period_size;
                        spin_unlock(&chip->reg_lock);
                        snd_pcm_period_elapsed(ypcm->substream);
@@ -366,7 +371,12 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
                ypcm->last_pos = pos;
                if (ypcm->period_pos >= ypcm->period_size) {
                        ypcm->period_pos %= ypcm->period_size;
-                       // printk("done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start);
+                       /*
+                       printk(KERN_DEBUG
+                              "done - active_bank = 0x%x, start = 0x%x\n",
+                              chip->active_bank,
+                              voice->bank[chip->active_bank].start);
+                       */
                        spin_unlock(&chip->reg_lock);
                        snd_pcm_period_elapsed(substream);
                        spin_lock(&chip->reg_lock);
index 819aaaac432f839e5667b986142f6da609416d57..7dea74b71cf1ab8e1485a85b4e3f35b658a7b639 100644 (file)
@@ -91,7 +91,7 @@ static int snd_pdacf_dev_free(struct snd_device *device)
  */
 static int snd_pdacf_probe(struct pcmcia_device *link)
 {
-       int i;
+       int i, err;
        struct snd_pdacf *pdacf;
        struct snd_card *card;
        static struct snd_device_ops ops = {
@@ -112,20 +112,23 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
                return -ENODEV; /* disabled explicitly */
 
        /* ok, create a card instance */
-       card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
-       if (card == NULL) {
+       err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
-               return -ENOMEM;
+               return err;
        }
 
        pdacf = snd_pdacf_create(card);
-       if (! pdacf)
-               return -EIO;
+       if (!pdacf) {
+               snd_card_free(card);
+               return -ENOMEM;
+       }
 
-       if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) {
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops);
+       if (err < 0) {
                kfree(pdacf);
                snd_card_free(card);
-               return -ENODEV;
+               return err;
        }
 
        snd_card_set_dev(card, &handle_to_dev(link));
index dfa40b0ed86dc07c3d3260434ea3e331ea9ee029..5d2afa0b0ce430012f48d0c038b455a6dce41a04 100644 (file)
@@ -82,14 +82,21 @@ static void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned c
 #if 0
 void pdacf_dump(struct snd_pdacf *chip)
 {
-       printk("PDAUDIOCF DUMP (0x%lx):\n", chip->port);
-       printk("WPD         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_WDP));
-       printk("RDP         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_RDP));
-       printk("TCR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_TCR));
-       printk("SCR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_SCR));
-       printk("ISR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_ISR));
-       printk("IER         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_IER));
-       printk("AK_IFR      : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_AK_IFR));
+       printk(KERN_DEBUG "PDAUDIOCF DUMP (0x%lx):\n", chip->port);
+       printk(KERN_DEBUG "WPD         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_WDP));
+       printk(KERN_DEBUG "RDP         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_RDP));
+       printk(KERN_DEBUG "TCR         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_TCR));
+       printk(KERN_DEBUG "SCR         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_SCR));
+       printk(KERN_DEBUG "ISR         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_ISR));
+       printk(KERN_DEBUG "IER         : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_IER));
+       printk(KERN_DEBUG "AK_IFR      : 0x%x\n",
+              inw(chip->port + PDAUDIOCF_REG_AK_IFR));
 }
 #endif
 
index ea903c8e90ddb9a27c3b445a0432df2443f4e552..dcd32201bc8c5cf4dfec40b0deba7edfaafe91ea 100644 (file)
@@ -269,7 +269,7 @@ void pdacf_tasklet(unsigned long private_data)
 
        rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
        wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
-       // printk("TASKLET: rdp = %x, wdp = %x\n", rdp, wdp);
+       /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
        size = wdp - rdp;
        if (size < 0)
                size += 0x10000;
@@ -321,5 +321,5 @@ void pdacf_tasklet(unsigned long private_data)
                spin_lock(&chip->reg_lock);
        }
        spin_unlock(&chip->reg_lock);
-       // printk("TASKLET: end\n");
+       /* printk(KERN_DEBUG "TASKLET: end\n"); */
 }
index 706602a40600718666c3a5e5fb7e957dc901e622..7445cc8a47d380df120dadd3b813aa62baf0ff38 100644 (file)
@@ -130,23 +130,26 @@ static struct snd_vx_hardware vxp440_hw = {
 /*
  * create vxpocket instance
  */
-static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl,
-                                            struct pcmcia_device *link)
+static int snd_vxpocket_new(struct snd_card *card, int ibl,
+                           struct pcmcia_device *link,
+                           struct snd_vxpocket **chip_ret)
 {
        struct vx_core *chip;
        struct snd_vxpocket *vxp;
        static struct snd_device_ops ops = {
                .dev_free =     snd_vxpocket_dev_free,
        };
+       int err;
 
        chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops,
                             sizeof(struct snd_vxpocket) - sizeof(struct vx_core));
-       if (! chip)
-               return NULL;
+       if (!chip)
+               return -ENOMEM;
 
-       if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
                kfree(chip);
-               return NULL;
+               return err;
        }
        chip->ibl.size = ibl;
 
@@ -169,7 +172,8 @@ static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl,
        link->conf.ConfigIndex = 1;
        link->conf.Present = PRESENT_OPTION;
 
-       return vxp;
+       *chip_ret = vxp;
+       return 0;
 }
 
 
@@ -292,7 +296,7 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
 {
        struct snd_card *card;
        struct snd_vxpocket *vxp;
-       int i;
+       int i, err;
 
        /* find an empty slot from the card list */
        for (i = 0; i < SNDRV_CARDS; i++) {
@@ -307,16 +311,16 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
                return -ENODEV; /* disabled explicitly */
 
        /* ok, create a card instance */
-       card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
-       if (card == NULL) {
+       err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
-               return -ENOMEM;
+               return err;
        }
 
-       vxp = snd_vxpocket_new(card, ibl[i], p_dev);
-       if (! vxp) {
+       err = snd_vxpocket_new(card, ibl[i], p_dev, &vxp);
+       if (err < 0) {
                snd_card_free(card);
-               return -ENODEV;
+               return err;
        }
        card->private_data = vxp;
 
index 777de2b171781b78eca1a347238efc6a585624b5..bd2338ab2ced8033801bab8700178046db4eab36 100644 (file)
@@ -13,6 +13,7 @@ config SND_POWERMAC
        tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
        depends on I2C && INPUT && PPC_PMAC
        select SND_PCM
+       select SND_VMASTER
        help
          Say Y here to include support for the integrated sound device.
 
index 7bd33e6552ab813967d44b19aca364801a9a93ba..80df9b1f651e01fbfec1302d77cd8673308a7b31 100644 (file)
@@ -608,9 +608,12 @@ static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = {
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __initdata = {
        AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
-       AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = {
+       AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
@@ -627,6 +630,10 @@ static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = {
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __initdata = {
+       AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1),
+};
+
 static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = {
        AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
@@ -645,12 +652,19 @@ static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = {
        AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __initdata = {
+       AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+};
+
 static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =
 AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
 
 static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata =
 AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
 
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __initdata =
+AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1);
+
 static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {
        AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
@@ -766,12 +780,16 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip)
 }
 #endif /* CONFIG_PM */
 
-#define IS_PM7500 (machine_is_compatible("AAPL,7500"))
+#define IS_PM7500 (machine_is_compatible("AAPL,7500") \
+               || machine_is_compatible("AAPL,8500") \
+               || machine_is_compatible("AAPL,9500"))
+#define IS_PM5500 (machine_is_compatible("AAPL,e411"))
 #define IS_BEIGE (machine_is_compatible("AAPL,Gossamer"))
 #define IS_IMAC1 (machine_is_compatible("PowerMac2,1"))
 #define IS_IMAC2 (machine_is_compatible("PowerMac2,2") \
                || machine_is_compatible("PowerMac4,1"))
 #define IS_G4AGP (machine_is_compatible("PowerMac3,1"))
+#define IS_LOMBARD (machine_is_compatible("PowerBook1,1"))
 
 static int imac1, imac2;
 
@@ -858,10 +876,14 @@ int __init
 snd_pmac_awacs_init(struct snd_pmac *chip)
 {
        int pm7500 = IS_PM7500;
+       int pm5500 = IS_PM5500;
        int beige = IS_BEIGE;
        int g4agp = IS_G4AGP;
+       int lombard = IS_LOMBARD;
        int imac;
        int err, vol;
+       struct snd_kcontrol *vmaster_sw, *vmaster_vol;
+       struct snd_kcontrol *master_vol, *speaker_vol;
 
        imac1 = IS_IMAC1;
        imac2 = IS_IMAC2;
@@ -915,7 +937,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
                /* set headphone-jack detection bit */
                switch (chip->model) {
                case PMAC_AWACS:
-                       chip->hp_stat_mask = pm7500 ? MASK_HDPCONN
+                       chip->hp_stat_mask = pm7500 || pm5500 ? MASK_HDPCONN
                                : MASK_LOCONN;
                        break;
                case PMAC_SCREAMER:
@@ -954,7 +976,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
                return err;
        if (beige || g4agp)
                ;
-       else if (chip->model == PMAC_SCREAMER)
+       else if (chip->model == PMAC_SCREAMER || pm5500)
                err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
                                   snd_pmac_screamer_mixers2);
        else if (!pm7500)
@@ -962,19 +984,35 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
                                   snd_pmac_awacs_mixers2);
        if (err < 0)
                return err;
+       if (pm5500) {
+               err = build_mixers(chip,
+                                  ARRAY_SIZE(snd_pmac_awacs_mixers2_pmac5500),
+                                  snd_pmac_awacs_mixers2_pmac5500);
+               if (err < 0)
+                       return err;
+       }
        if (pm7500)
                err = build_mixers(chip,
                                   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500),
                                   snd_pmac_awacs_mixers_pmac7500);
+       else if (pm5500)
+               err = snd_ctl_add(chip->card,
+                   (master_vol = snd_ctl_new1(snd_pmac_awacs_mixers_pmac5500,
+                                               chip)));
        else if (beige)
                err = build_mixers(chip,
                                   ARRAY_SIZE(snd_pmac_screamer_mixers_beige),
                                   snd_pmac_screamer_mixers_beige);
-       else if (imac)
+       else if (imac || lombard) {
+               err = snd_ctl_add(chip->card,
+                   (master_vol = snd_ctl_new1(snd_pmac_screamer_mixers_lo,
+                                               chip)));
+               if (err < 0)
+                       return err;
                err = build_mixers(chip,
                                   ARRAY_SIZE(snd_pmac_screamer_mixers_imac),
                                   snd_pmac_screamer_mixers_imac);
-       else if (g4agp)
+       else if (g4agp)
                err = build_mixers(chip,
                                   ARRAY_SIZE(snd_pmac_screamer_mixers_g4agp),
                                   snd_pmac_screamer_mixers_g4agp);
@@ -984,8 +1022,10 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
                                   snd_pmac_awacs_mixers_pmac);
        if (err < 0)
                return err;
-       chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac || g4agp)
+       chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac || g4agp || lombard)
                        ? &snd_pmac_awacs_master_sw_imac
+                       : pm5500
+                       ? &snd_pmac_awacs_master_sw_pmac5500
                        : &snd_pmac_awacs_master_sw, chip);
        err = snd_ctl_add(chip->card, chip->master_sw_ctl);
        if (err < 0)
@@ -1017,8 +1057,9 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
 #endif /* PMAC_AMP_AVAIL */
        {
                /* route A = headphone, route C = speaker */
-               err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
-                                       snd_pmac_awacs_speaker_vol);
+               err = snd_ctl_add(chip->card,
+                   (speaker_vol = snd_ctl_new1(snd_pmac_awacs_speaker_vol,
+                                               chip)));
                if (err < 0)
                        return err;
                chip->speaker_sw_ctl = snd_ctl_new1(imac1
@@ -1031,6 +1072,33 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
                        return err;
        }
 
+       if (pm5500 || imac || lombard) {
+               vmaster_sw = snd_ctl_make_virtual_master(
+                       "Master Playback Switch", (unsigned int *) NULL);
+               err = snd_ctl_add_slave_uncached(vmaster_sw,
+                                                chip->master_sw_ctl);
+               if (err < 0)
+                       return err;
+               err = snd_ctl_add_slave_uncached(vmaster_sw,
+                                                 chip->speaker_sw_ctl);
+               if (err < 0)
+                       return err;
+               err = snd_ctl_add(chip->card, vmaster_sw);
+               if (err < 0)
+                       return err;
+               vmaster_vol = snd_ctl_make_virtual_master(
+                       "Master Playback Volume", (unsigned int *) NULL);
+               err = snd_ctl_add_slave(vmaster_vol, master_vol);
+               if (err < 0)
+                       return err;
+               err = snd_ctl_add_slave(vmaster_vol, speaker_vol);
+               if (err < 0)
+                       return err;
+               err = snd_ctl_add(chip->card, vmaster_vol);
+               if (err < 0)
+                       return err;
+       }
+
        if (beige || g4agp)
                err = build_mixers(chip,
                                ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige),
index f860d39af36b39e91fafe4ceb33be28b9d5b7167..45a76297c38d2224abd7fee9b3994f04fd2b2dcf 100644 (file)
@@ -35,7 +35,7 @@ snd_pmac_burgundy_busy_wait(struct snd_pmac *chip)
        int timeout = 50;
        while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
                udelay(1);
-       if (! timeout)
+       if (timeout < 0)
                printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
 }
 
index 8a5b29031933a09f1a9d1ef047ee2a1db93364c4..f8d478c2da62b252d719b067ddff75805a8aa561 100644 (file)
@@ -82,7 +82,7 @@ static int daca_set_volume(struct pmac_daca *mix)
        data[1] |= mix->deemphasis ? 0x40 : 0;
        if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
                                       2, data) < 0) {
-               snd_printk("failed to set volume \n");
+               snd_printk(KERN_ERR "failed to set volume \n");
                return -EINVAL;
        }
        return 0;
index af76ee862d2787f89b34313dbba2bd5ff98b715c..9b4e9c316695e2b44cc08099427d3cf015695876 100644 (file)
@@ -299,7 +299,7 @@ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec,
        case SNDRV_PCM_TRIGGER_SUSPEND:
                spin_lock(&chip->reg_lock);
                rec->running = 0;
-               /*printk("stopped!!\n");*/
+               /*printk(KERN_DEBUG "stopped!!\n");*/
                snd_pmac_dma_stop(rec);
                for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
                        out_le16(&cp->command, DBDMA_STOP);
@@ -334,7 +334,7 @@ static snd_pcm_uframes_t snd_pmac_pcm_pointer(struct snd_pmac *chip,
        }
 #endif
        count += rec->cur_period * rec->period_size;
-       /*printk("pointer=%d\n", count);*/
+       /*printk(KERN_DEBUG "pointer=%d\n", count);*/
        return bytes_to_frames(subs->runtime, count);
 }
 
@@ -486,7 +486,7 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
                        if (! (stat & ACTIVE))
                                break;
 
-                       /*printk("update frag %d\n", rec->cur_period);*/
+                       /*printk(KERN_DEBUG "update frag %d\n", rec->cur_period);*/
                        st_le16(&cp->xfer_status, 0);
                        st_le16(&cp->req_count, rec->period_size);
                        /*st_le16(&cp->res_count, 0);*/
@@ -806,7 +806,7 @@ snd_pmac_ctrl_intr(int irq, void *devid)
        struct snd_pmac *chip = devid;
        int ctrl = in_le32(&chip->awacs->control);
 
-       /*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
+       /*printk(KERN_DEBUG "pmac: control interrupt.. 0x%x\n", ctrl);*/
        if (ctrl & MASK_PORTCHG) {
                /* do something when headphone is plugged/unplugged? */
                if (chip->update_automute)
@@ -1033,7 +1033,8 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
        }
        if (of_device_is_compatible(sound, "tumbler")) {
                chip->model = PMAC_TUMBLER;
-               chip->can_capture = machine_is_compatible("PowerMac4,2");
+               chip->can_capture = machine_is_compatible("PowerMac4,2")
+                               || machine_is_compatible("PowerBook4,1");
                chip->can_duplex = 0;
                // chip->can_byte_swap = 0; /* FIXME: check this */
                chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
index c936225771ba0cd8381686c3c6b7424f288b051a..5a929069dce980453a67d526450b9cf877fb9d09 100644 (file)
@@ -58,9 +58,9 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
        char *name_ext;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_pmac_new(card, &chip)) < 0)
                goto __error;
@@ -110,7 +110,7 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
                        goto __error;
                break;
        default:
-               snd_printk("unsupported hardware %d\n", chip->model);
+               snd_printk(KERN_ERR "unsupported hardware %d\n", chip->model);
                err = -EINVAL;
                goto __error;
        }
index ff321110ec029604bd8cd0e4862940fe1e1b88c4..f361c26506aacefd1b5a683c232163294c6f9480 100644 (file)
@@ -969,11 +969,9 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
        }
 
        /* create card instance */
-       the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (!the_card.card) {
-               ret = -ENXIO;
+       ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card);
+       if (ret < 0)
                goto clean_irq;
-       }
 
        strcpy(the_card.card->driver, "PS3");
        strcpy(the_card.card->shortname, "PS3");
index 3eb2233854166e06a7c532f9ec2d555020c7d567..40222fcc08783048bd56c06659d027cdb903ce54 100644 (file)
@@ -41,7 +41,7 @@
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
 #else
 #define DBG(fmt...)
 #endif
@@ -240,7 +240,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix)
   
        if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_VOL, 6,
                                           block) < 0) {
-               snd_printk("failed to set volume \n");
+               snd_printk(KERN_ERR "failed to set volume \n");
                return -EINVAL;
        }
        return 0;
@@ -350,7 +350,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix)
 
        if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
                                           2, val) < 0) {
-               snd_printk("failed to set DRC\n");
+               snd_printk(KERN_ERR "failed to set DRC\n");
                return -EINVAL;
        }
        return 0;
@@ -386,7 +386,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix)
 
        if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
                                           6, val) < 0) {
-               snd_printk("failed to set DRC\n");
+               snd_printk(KERN_ERR "failed to set DRC\n");
                return -EINVAL;
        }
        return 0;
@@ -506,7 +506,8 @@ static int tumbler_set_mono_volume(struct pmac_tumbler *mix,
                block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;
        if (i2c_smbus_write_i2c_block_data(mix->i2c.client, info->reg,
                                           info->bytes, block) < 0) {
-               snd_printk("failed to set mono volume %d\n", info->index);
+               snd_printk(KERN_ERR "failed to set mono volume %d\n",
+                          info->index);
                return -EINVAL;
        }
        return 0;
@@ -643,7 +644,7 @@ static int snapper_set_mix_vol1(struct pmac_tumbler *mix, int idx, int ch, int r
        }
        if (i2c_smbus_write_i2c_block_data(mix->i2c.client, reg,
                                           9, block) < 0) {
-               snd_printk("failed to set mono volume %d\n", reg);
+               snd_printk(KERN_ERR "failed to set mono volume %d\n", reg);
                return -EINVAL;
        }
        return 0;
index cfc1439858029e32956906947ecdf2755299059d..aed0f90c39190c92311e38d611e1e65af92bf412 100644 (file)
@@ -15,6 +15,7 @@ config SND_AICA
        tristate "Dreamcast Yamaha AICA sound"
        depends on SH_DREAMCAST
        select SND_PCM
+       select G2_DMA
        help
          ALSA Sound driver for the SEGA Dreamcast console.
 
index 7c920f3e7fe35e4a917597d92b736011e8a62ba4..f551233c5a08d6958c14caebe24a1e227257e829 100644 (file)
@@ -609,11 +609,11 @@ static int __devinit snd_aica_probe(struct platform_device *devptr)
        dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
        if (unlikely(!dreamcastcard))
                return -ENOMEM;
-       dreamcastcard->card =
-           snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
-       if (unlikely(!dreamcastcard->card)) {
+       err = snd_card_create(index, SND_AICA_DRIVER, THIS_MODULE, 0,
+                             &dreamcastcard->card);
+       if (unlikely(err < 0)) {
                kfree(dreamcastcard);
-               return -ENODEV;
+               return err;
        }
        strcpy(dreamcastcard->card->driver, "snd_aica");
        strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
index ef025c66cc669c49c7b4537893ba76860fbd2397..3d2bb6fc6dcc46ad7f95ef5703059d6144be7849 100644 (file)
@@ -6,6 +6,7 @@ menuconfig SND_SOC
        tristate "ALSA for SoC audio support"
        select SND_PCM
        select AC97_BUS if SND_SOC_AC97_BUS
+       select SND_JACK if INPUT=y || INPUT=SND
        ---help---
 
          If you want ASoC support, you should say Y here and also to the
index 86a9b1f5b0f3cbf83c315505613fd751c8356306..0237879fd4125b47330a7a65a24449643fdaf3a7 100644 (file)
@@ -1,4 +1,4 @@
-snd-soc-core-objs := soc-core.o soc-dapm.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/
index 3dcdc4e3cfa0b221b61deda68eed5d71835ef800..9ef6b96373f598cbb2bf670953a6a85a96bf710c 100644 (file)
@@ -347,7 +347,7 @@ static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
-struct snd_pcm_ops atmel_pcm_ops = {
+static struct snd_pcm_ops atmel_pcm_ops = {
        .open           = atmel_pcm_open,
        .close          = atmel_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
index ff0054b765028062bb0040985777969f940fe6fd..e588e63f18d205e6e7f1d118b4982711f867cd51 100644 (file)
@@ -697,6 +697,15 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
+       .startup        = atmel_ssc_startup,
+       .shutdown       = atmel_ssc_shutdown,
+       .prepare        = atmel_ssc_prepare,
+       .hw_params      = atmel_ssc_hw_params,
+       .set_fmt        = atmel_ssc_set_dai_fmt,
+       .set_clkdiv     = atmel_ssc_set_dai_clkdiv,
+};
+
 struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
        {       .name = "atmel-ssc0",
                .id = 0,
@@ -712,13 +721,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .channels_max = 2,
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
-               .ops = {
-                       .startup = atmel_ssc_startup,
-                       .shutdown = atmel_ssc_shutdown,
-                       .prepare = atmel_ssc_prepare,
-                       .hw_params = atmel_ssc_hw_params,
-                       .set_fmt = atmel_ssc_set_dai_fmt,
-                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .ops = &atmel_ssc_dai_ops,
                .private_data = &ssc_info[0],
        },
 #if NUM_SSC_DEVICES == 3
@@ -736,13 +739,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .channels_max = 2,
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
-               .ops = {
-                       .startup = atmel_ssc_startup,
-                       .shutdown = atmel_ssc_shutdown,
-                       .prepare = atmel_ssc_prepare,
-                       .hw_params = atmel_ssc_hw_params,
-                       .set_fmt = atmel_ssc_set_dai_fmt,
-                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .ops = &atmel_ssc_dai_ops,
                .private_data = &ssc_info[1],
        },
        {       .name = "atmel-ssc2",
@@ -759,13 +756,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .channels_max = 2,
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
-               .ops = {
-                       .startup = atmel_ssc_startup,
-                       .shutdown = atmel_ssc_shutdown,
-                       .prepare = atmel_ssc_prepare,
-                       .hw_params = atmel_ssc_hw_params,
-                       .set_fmt = atmel_ssc_set_dai_fmt,
-                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .ops = &atmel_ssc_dai_ops,
                .private_data = &ssc_info[2],
        },
 #endif
index 43dd8cee83c64e2d87bd2574fbcb31c7cafabf9c..70657534e6b1f68ad3d9a89d4bc7e8698a4fafe5 100644 (file)
@@ -164,38 +164,38 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
         */
        switch (params_rate(params)) {
        case 48000:
-               pll_out = 12288000;
-               mclk_div = WM8510_MCLKDIV_1;
+               pll_out = 24576000;
+               mclk_div = WM8510_MCLKDIV_2;
                bclk = WM8510_BCLKDIV_8;
                break;
 
        case 44100:
-               pll_out = 11289600;
-               mclk_div = WM8510_MCLKDIV_1;
+               pll_out = 22579200;
+               mclk_div = WM8510_MCLKDIV_2;
                bclk = WM8510_BCLKDIV_8;
                break;
 
        case 22050:
-               pll_out = 11289600;
-               mclk_div = WM8510_MCLKDIV_2;
+               pll_out = 22579200;
+               mclk_div = WM8510_MCLKDIV_4;
                bclk = WM8510_BCLKDIV_8;
                break;
 
        case 16000:
-               pll_out = 12288000;
-               mclk_div = WM8510_MCLKDIV_3;
+               pll_out = 24576000;
+               mclk_div = WM8510_MCLKDIV_6;
                bclk = WM8510_BCLKDIV_8;
                break;
 
        case 11025:
-               pll_out = 11289600;
-               mclk_div = WM8510_MCLKDIV_4;
+               pll_out = 22579200;
+               mclk_div = WM8510_MCLKDIV_8;
                bclk = WM8510_BCLKDIV_8;
                break;
 
        case 8000:
-               pll_out = 12288000;
-               mclk_div = WM8510_MCLKDIV_6;
+               pll_out = 24576000;
+               mclk_div = WM8510_MCLKDIV_12;
                bclk = WM8510_BCLKDIV_8;
                break;
 
index 6ea04be911d0646a83436c986144db12ff4943d2..173a239a541c3c1611be7a372a39d1d24901e3ce 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/i2c.h>
 
 #include <linux/atmel-ssc.h>
 
@@ -45,6 +46,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
+#include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
 
@@ -52,6 +54,9 @@
 #include "atmel-pcm.h"
 #include "atmel_ssc_dai.h"
 
+#define MCLK_RATE 12000000
+
+static struct clk *mclk;
 
 static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
 {
@@ -59,11 +64,12 @@ static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
        int ret;
 
-       /* codec system clock is supplied by PCK0, set to 12MHz */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
-               12000000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
+               MCLK_RATE, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               clk_disable(mclk);
                return ret;
+       }
 
        return 0;
 }
@@ -189,6 +195,31 @@ static struct snd_soc_ops at91sam9g20ek_ops = {
        .shutdown = at91sam9g20ek_shutdown,
 };
 
+static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
+                                       enum snd_soc_bias_level level)
+{
+       static int mclk_on;
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               if (!mclk_on)
+                       ret = clk_enable(mclk);
+               if (ret == 0)
+                       mclk_on = 1;
+               break;
+
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               if (mclk_on)
+                       clk_disable(mclk);
+               mclk_on = 0;
+               break;
+       }
+
+       return ret;
+}
 
 static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Int Mic", NULL),
@@ -243,21 +274,48 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
-       .name = "WM8731",
+       .name = "AT91SAMG20-EK",
        .platform = &atmel_soc_platform,
        .dai_link = &at91sam9g20ek_dai,
        .num_links = 1,
+       .set_bias_level = at91sam9g20ek_set_bias_level,
 };
 
-static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1b,
-};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = 0x1b;
+       strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(0);
+       if (!adapter) {
+               printk(KERN_ERR "can't get i2c adapter 0\n");
+               return -ENODEV;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               printk(KERN_ERR "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               return -ENODEV;
+       }
+
+       return 0;
+}
 
 static struct snd_soc_device at91sam9g20ek_snd_devdata = {
        .card = &snd_soc_at91sam9g20ek,
        .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &at91sam9g20ek_wm8731_setup,
 };
 
 static struct platform_device *at91sam9g20ek_snd_device;
@@ -266,23 +324,56 @@ static int __init at91sam9g20ek_init(void)
 {
        struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
        struct ssc_device *ssc = NULL;
+       struct clk *pllb;
        int ret;
 
+       if (!machine_is_at91sam9g20ek())
+               return -ENODEV;
+
+       /*
+        * Codec MCLK is supplied by PCK0 - set it up.
+        */
+       mclk = clk_get(NULL, "pck0");
+       if (IS_ERR(mclk)) {
+               printk(KERN_ERR "ASoC: Failed to get MCLK\n");
+               ret = PTR_ERR(mclk);
+               goto err;
+       }
+
+       pllb = clk_get(NULL, "pllb");
+       if (IS_ERR(mclk)) {
+               printk(KERN_ERR "ASoC: Failed to get PLLB\n");
+               ret = PTR_ERR(mclk);
+               goto err_mclk;
+       }
+       ret = clk_set_parent(mclk, pllb);
+       clk_put(pllb);
+       if (ret != 0) {
+               printk(KERN_ERR "ASoC: Failed to set MCLK parent\n");
+               goto err_mclk;
+       }
+
+       clk_set_rate(mclk, MCLK_RATE);
+
        /*
         * Request SSC device
         */
        ssc = ssc_request(0);
        if (IS_ERR(ssc)) {
+               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
                ret = PTR_ERR(ssc);
                ssc = NULL;
                goto err_ssc;
        }
        ssc_p->ssc = ssc;
 
+       ret = wm8731_i2c_register();
+       if (ret != 0)
+               goto err_ssc;
+
        at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
        if (!at91sam9g20ek_snd_device) {
-               printk(KERN_DEBUG
-                               "platform device allocation failed\n");
+               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
                ret = -ENOMEM;
        }
 
@@ -292,14 +383,19 @@ static int __init at91sam9g20ek_init(void)
 
        ret = platform_device_add(at91sam9g20ek_snd_device);
        if (ret) {
-               printk(KERN_DEBUG
-                               "platform device allocation failed\n");
+               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
                platform_device_put(at91sam9g20ek_snd_device);
        }
 
        return ret;
 
 err_ssc:
+       ssc_free(ssc);
+       ssc_p->ssc = NULL;
+err_mclk:
+       clk_put(mclk);
+       mclk = NULL;
+err:
        return ret;
 }
 
@@ -317,6 +413,8 @@ static void __exit at91sam9g20ek_exit(void)
 
        platform_device_unregister(at91sam9g20ek_snd_device);
        at91sam9g20ek_snd_device = NULL;
+       clk_put(mclk);
+       mclk = NULL;
 }
 
 module_init(at91sam9g20ek_init);
index bc8d654576c017194428fc75b3720abc291f1466..30490a2591487e724c40c3b42fed27238281ac5d 100644 (file)
@@ -305,7 +305,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-struct snd_pcm_ops au1xpsc_pcm_ops = {
+static struct snd_pcm_ops au1xpsc_pcm_ops = {
        .open           = au1xpsc_pcm_open,
        .close          = au1xpsc_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
index f0e30aec7f233621a23a35f9fa8100facdc4a189..479d7bdf1865cb822cdca9677d3180e2805e4d69 100644 (file)
@@ -342,6 +342,11 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
        return 0;
 }
 
+static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+       .trigger        = au1xpsc_ac97_trigger,
+       .hw_params      = au1xpsc_ac97_hw_params,
+};
+
 struct snd_soc_dai au1xpsc_ac97_dai = {
        .name                   = "au1xpsc_ac97",
        .ac97_control           = 1,
@@ -361,10 +366,7 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
                .channels_min   = 2,
                .channels_max   = 2,
        },
-       .ops = {
-               .trigger        = au1xpsc_ac97_trigger,
-               .hw_params      = au1xpsc_ac97_hw_params,
-       },
+       .ops = &au1xpsc_ac97_dai_ops,
 };
 EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 
index f916de4400edcc358a58a33d227f9fafd0ce88af..bb589327ee32e495e706638af92022e9803b5947 100644 (file)
@@ -367,6 +367,12 @@ static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+       .trigger        = au1xpsc_i2s_trigger,
+       .hw_params      = au1xpsc_i2s_hw_params,
+       .set_fmt        = au1xpsc_i2s_set_fmt,
+};
+
 struct snd_soc_dai au1xpsc_i2s_dai = {
        .name                   = "au1xpsc_i2s",
        .probe                  = au1xpsc_i2s_probe,
@@ -385,11 +391,7 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
                .channels_min   = 2,
                .channels_max   = 8,    /* 2 without external help */
        },
-       .ops = {
-               .trigger        = au1xpsc_i2s_trigger,
-               .hw_params      = au1xpsc_i2s_hw_params,
-               .set_fmt        = au1xpsc_i2s_set_fmt,
-       },
+       .ops = &au1xpsc_i2s_dai_ops,
 };
 EXPORT_SYMBOL(au1xpsc_i2s_dai);
 
index 8067cfafa3a703ea5e0f9dacb30f4c13e882f0ff..8cfed1a5dcbea6cfd80ec1c15fb3756cc236760d 100644 (file)
@@ -297,7 +297,7 @@ static      int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
 }
 #endif
 
-struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
        .open           = bf5xx_pcm_open,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = bf5xx_pcm_hw_params,
index 3be2be60576df8bc336f7a8130cdce27404d92a6..8a935f2d17674683186fc26d48d890c835ad3f3c 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-ac97.h"
 
-#if defined(CONFIG_BF54x)
-#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, \
-               P_SPORT0_RFS, P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
-
-#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, \
-               P_SPORT1_RFS, P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
-
-#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, \
-               P_SPORT2_RFS, P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
-
-#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, \
-               P_SPORT3_RFS, P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
-#else
-#define PIN_REQ_SPORT_0 {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
-                P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
-
-#define PIN_REQ_SPORT_1 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
-                P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
-#endif
-
 static int *cmd_count;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+              P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
 static u16 sport_req[][7] = {
-               PIN_REQ_SPORT_0,
-#ifdef PIN_REQ_SPORT_1
-               PIN_REQ_SPORT_1,
+#ifdef SPORT0_TCR1
+       SPORT_REQ(0),
+#endif
+#ifdef SPORT1_TCR1
+       SPORT_REQ(1),
 #endif
-#ifdef PIN_REQ_SPORT_2
-               PIN_REQ_SPORT_2,
+#ifdef SPORT2_TCR1
+       SPORT_REQ(2),
 #endif
-#ifdef PIN_REQ_SPORT_3
-               PIN_REQ_SPORT_3,
+#ifdef SPORT3_TCR1
+       SPORT_REQ(3),
 #endif
-       };
+};
 
+#define SPORT_PARAMS(x) \
+       [x] = { \
+               .dma_rx_chan = CH_SPORT##x##_RX, \
+               .dma_tx_chan = CH_SPORT##x##_TX, \
+               .err_irq     = IRQ_SPORT##x##_ERROR, \
+               .regs        = (struct sport_register *)SPORT##x##_TCR1, \
+       }
 static struct sport_param sport_params[4] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-#ifdef PIN_REQ_SPORT_1
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       },
+#ifdef SPORT0_TCR1
+       SPORT_PARAMS(0),
 #endif
-#ifdef PIN_REQ_SPORT_2
-       {
-               .dma_rx_chan    = CH_SPORT2_RX,
-               .dma_tx_chan    = CH_SPORT2_TX,
-               .err_irq        = IRQ_SPORT2_ERROR,
-               .regs           = (struct sport_register *)SPORT2_TCR1,
-       },
+#ifdef SPORT1_TCR1
+       SPORT_PARAMS(1),
 #endif
-#ifdef PIN_REQ_SPORT_3
-       {
-               .dma_rx_chan    = CH_SPORT3_RX,
-               .dma_tx_chan    = CH_SPORT3_TX,
-               .err_irq        = IRQ_SPORT3_ERROR,
-               .regs           = (struct sport_register *)SPORT3_TCR1,
-       }
+#ifdef SPORT2_TCR1
+       SPORT_PARAMS(2),
+#endif
+#ifdef SPORT3_TCR1
+       SPORT_PARAMS(3),
 #endif
 };
 
@@ -332,11 +306,11 @@ static int bf5xx_ac97_probe(struct platform_device *pdev,
        if (cmd_count == NULL)
                return -ENOMEM;
 
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+       if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
                pr_err("Requesting Peripherals failed\n");
                ret =  -EFAULT;
                goto peripheral_err;
-               }
+       }
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        /* Request PB3 as reset pin */
@@ -383,9 +357,9 @@ sport_config_err:
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
 gpio_err:
-       peripheral_free_list(&sport_req[sport_num][0]);
+#endif
+       peripheral_free_list(sport_req[sport_num]);
 peripheral_err:
        free_page((unsigned long)cmd_count);
        cmd_count = NULL;
@@ -398,7 +372,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 {
        free_page((unsigned long)cmd_count);
        cmd_count = NULL;
-       peripheral_free_list(&sport_req[sport_num][0]);
+       peripheral_free_list(sport_req[sport_num]);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
index 7f2a5e199075421ef0ebee1097139a2671f2f6d2..edfbdc024e663d9ac6ae1048086d84334518a9cd 100644 (file)
@@ -114,7 +114,7 @@ static int snd_ad73311_configure(void)
        SSYNC();
 
        /* When TUVF is set, the data is already send out */
-       while (!(status & TUVF) && count++ < 10000) {
+       while (!(status & TUVF) && ++count < 10000) {
                udelay(1);
                status = bfin_read_SPORT_STAT();
                SSYNC();
@@ -123,7 +123,7 @@ static int snd_ad73311_configure(void)
        SSYNC();
        local_irq_enable();
 
-       if (count == 10000) {
+       if (count >= 10000) {
                printk(KERN_ERR "ad73311: failed to configure codec\n");
                return -1;
        }
index 53d290b3ea47d9e2cf974cd1b83721f7199180da..1318c4f627b7c52f9a90829b0dd10498aa6cdd1b 100644 (file)
@@ -184,7 +184,7 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        return 0 ;
 }
 
-struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
        .open           = bf5xx_pcm_open,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = bf5xx_pcm_hw_params,
index d1d95d2393feb81ea8352d52e04e00b6d59d3d1b..964824419678bfe361b77bab3ce538eb7af6bc38 100644 (file)
@@ -287,6 +287,13 @@ static int bf5xx_i2s_resume(struct platform_device *pdev,
 #define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
        SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
+       .startup        = bf5xx_i2s_startup,
+       .shutdown       = bf5xx_i2s_shutdown,
+       .hw_params      = bf5xx_i2s_hw_params,
+       .set_fmt        = bf5xx_i2s_set_dai_fmt,
+};
+
 struct snd_soc_dai bf5xx_i2s_dai = {
        .name = "bf5xx-i2s",
        .id = 0,
@@ -304,12 +311,7 @@ struct snd_soc_dai bf5xx_i2s_dai = {
                .channels_max = 2,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
-       .ops = {
-               .startup   = bf5xx_i2s_startup,
-               .shutdown  = bf5xx_i2s_shutdown,
-               .hw_params = bf5xx_i2s_hw_params,
-               .set_fmt = bf5xx_i2s_set_dai_fmt,
-       },
+       .ops = &bf5xx_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
 
index 3b99e484d555a1648abe4199e721cb5269d51988..b7953c8cf8382a05df6ef9b280b0403a7b214f77 100644 (file)
@@ -133,7 +133,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
        int i;
 
        for (i = 0; i < fragcount; ++i) {
-               desc[i].next_desc_addr  = (unsigned long)&(desc[i + 1]);
+               desc[i].next_desc_addr  = &(desc[i + 1]);
                desc[i].start_addr = (unsigned long)buf + i*fragsize;
                desc[i].cfg = cfg;
                desc[i].x_count = x_count;
@@ -143,12 +143,12 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
        }
 
        /* make circular */
-       desc[fragcount-1].next_desc_addr = (unsigned long)desc;
+       desc[fragcount-1].next_desc_addr = desc;
 
-       pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p,"
-               "next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
-               &(desc[0]), desc[0].next_desc_addr,
-               &(desc[1]), desc[1].next_desc_addr,
+       pr_debug("setup desc: desc0=%p, next0=%p, desc1=%p,"
+               "next1=%p\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
+               desc, desc[0].next_desc_addr,
+               desc+1, desc[1].next_desc_addr,
                desc[0].x_count, desc[0].y_count,
                desc[0].start_addr, desc[0].cfg);
 }
@@ -184,22 +184,20 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
        BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc);
 
        /* Maybe the dummy buffer descriptor ring is damaged */
-       sport->dummy_rx_desc->next_desc_addr = \
-                       (unsigned long)(sport->dummy_rx_desc+1);
+       sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc + 1;
 
        local_irq_save(flags);
-       desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan);
+       desc = get_dma_next_desc_ptr(sport->dma_rx_chan);
        /* Copy the descriptor which will be damaged to backup */
        temp_desc = *desc;
        desc->x_count = 0xa;
        desc->y_count = 0;
-       desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc);
+       desc->next_desc_addr = sport->dummy_rx_desc;
        local_irq_restore(flags);
        /* Waiting for dummy buffer descriptor is already hooked*/
        while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
-                       sizeof(struct dmasg)) !=
-                       (unsigned long)sport->dummy_rx_desc)
-               ;
+                       sizeof(struct dmasg)) != sport->dummy_rx_desc)
+               continue;
        sport->curr_rx_desc = sport->dummy_rx_desc;
        /* Restore the damaged descriptor */
        *desc = temp_desc;
@@ -210,14 +208,12 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
 static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
 {
        if (dummy) {
-               sport->dummy_rx_desc->next_desc_addr = \
-                               (unsigned long) sport->dummy_rx_desc;
+               sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc;
                sport->curr_rx_desc = sport->dummy_rx_desc;
        } else
                sport->curr_rx_desc = sport->dma_rx_desc;
 
-       set_dma_next_desc_addr(sport->dma_rx_chan, \
-                       (unsigned long)(sport->curr_rx_desc));
+       set_dma_next_desc_addr(sport->dma_rx_chan, sport->curr_rx_desc);
        set_dma_x_count(sport->dma_rx_chan, 0);
        set_dma_x_modify(sport->dma_rx_chan, 0);
        set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \
@@ -231,14 +227,12 @@ static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
 static inline int sport_tx_dma_start(struct sport_device *sport, int dummy)
 {
        if (dummy) {
-               sport->dummy_tx_desc->next_desc_addr = \
-                               (unsigned long) sport->dummy_tx_desc;
+               sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc;
                sport->curr_tx_desc = sport->dummy_tx_desc;
        } else
                sport->curr_tx_desc = sport->dma_tx_desc;
 
-       set_dma_next_desc_addr(sport->dma_tx_chan, \
-                       (unsigned long)(sport->curr_tx_desc));
+       set_dma_next_desc_addr(sport->dma_tx_chan, sport->curr_tx_desc);
        set_dma_x_count(sport->dma_tx_chan, 0);
        set_dma_x_modify(sport->dma_tx_chan, 0);
        set_dma_config(sport->dma_tx_chan,
@@ -261,11 +255,9 @@ int sport_rx_start(struct sport_device *sport)
                BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc);
                local_irq_save(flags);
                while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
-                       sizeof(struct dmasg)) !=
-                       (unsigned long)sport->dummy_rx_desc)
-                       ;
-               sport->dummy_rx_desc->next_desc_addr =
-                               (unsigned long)(sport->dma_rx_desc);
+                       sizeof(struct dmasg)) != sport->dummy_rx_desc)
+                       continue;
+               sport->dummy_rx_desc->next_desc_addr = sport->dma_rx_desc;
                local_irq_restore(flags);
                sport->curr_rx_desc = sport->dma_rx_desc;
        } else {
@@ -310,23 +302,21 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport)
        BUG_ON(sport->dummy_tx_desc == NULL);
        BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc);
 
-       sport->dummy_tx_desc->next_desc_addr = \
-                       (unsigned long)(sport->dummy_tx_desc+1);
+       sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc + 1;
 
        /* Shorten the time on last normal descriptor */
        local_irq_save(flags);
-       desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan);
+       desc = get_dma_next_desc_ptr(sport->dma_tx_chan);
        /* Store the descriptor which will be damaged */
        temp_desc = *desc;
        desc->x_count = 0xa;
        desc->y_count = 0;
-       desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc);
+       desc->next_desc_addr = sport->dummy_tx_desc;
        local_irq_restore(flags);
        /* Waiting for dummy buffer descriptor is already hooked*/
        while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
-                       sizeof(struct dmasg)) != \
-                       (unsigned long)sport->dummy_tx_desc)
-               ;
+                       sizeof(struct dmasg)) != sport->dummy_tx_desc)
+               continue;
        sport->curr_tx_desc = sport->dummy_tx_desc;
        /* Restore the damaged descriptor */
        *desc = temp_desc;
@@ -347,11 +337,9 @@ int sport_tx_start(struct sport_device *sport)
                /* Hook the normal buffer descriptor */
                local_irq_save(flags);
                while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
-                       sizeof(struct dmasg)) !=
-                       (unsigned long)sport->dummy_tx_desc)
-                       ;
-               sport->dummy_tx_desc->next_desc_addr =
-                               (unsigned long)(sport->dma_tx_desc);
+                       sizeof(struct dmasg)) != sport->dummy_tx_desc)
+                       continue;
+               sport->dummy_tx_desc->next_desc_addr = sport->dma_tx_desc;
                local_irq_restore(flags);
                sport->curr_tx_desc = sport->dma_tx_desc;
        } else {
@@ -536,19 +524,17 @@ static int sport_config_rx_dummy(struct sport_device *sport)
        unsigned config;
 
        pr_debug("%s entered\n", __func__);
-#if L1_DATA_A_LENGTH != 0
-       desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
-#else
-       {
+       if (L1_DATA_A_LENGTH)
+               desc = l1_data_sram_zalloc(2 * sizeof(*desc));
+       else {
                dma_addr_t addr;
                desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+               memset(desc, 0, 2 * sizeof(*desc));
        }
-#endif
        if (desc == NULL) {
                pr_err("Failed to allocate memory for dummy rx desc\n");
                return -ENOMEM;
        }
-       memset(desc, 0, 2 * sizeof(*desc));
        sport->dummy_rx_desc = desc;
        desc->start_addr = (unsigned long)sport->dummy_buf;
        config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize)
@@ -559,8 +545,8 @@ static int sport_config_rx_dummy(struct sport_device *sport)
        desc->y_count = 0;
        desc->y_modify = 0;
        memcpy(desc+1, desc, sizeof(*desc));
-       desc->next_desc_addr = (unsigned long)(desc+1);
-       desc[1].next_desc_addr = (unsigned long)desc;
+       desc->next_desc_addr = desc + 1;
+       desc[1].next_desc_addr = desc;
        return 0;
 }
 
@@ -571,19 +557,17 @@ static int sport_config_tx_dummy(struct sport_device *sport)
 
        pr_debug("%s entered\n", __func__);
 
-#if L1_DATA_A_LENGTH != 0
-       desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
-#else
-       {
+       if (L1_DATA_A_LENGTH)
+               desc = l1_data_sram_zalloc(2 * sizeof(*desc));
+       else {
                dma_addr_t addr;
                desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+               memset(desc, 0, 2 * sizeof(*desc));
        }
-#endif
        if (!desc) {
                pr_err("Failed to allocate memory for dummy tx desc\n");
                return -ENOMEM;
        }
-       memset(desc, 0, 2 * sizeof(*desc));
        sport->dummy_tx_desc = desc;
        desc->start_addr = (unsigned long)sport->dummy_buf + \
                sport->dummy_count;
@@ -595,8 +579,8 @@ static int sport_config_tx_dummy(struct sport_device *sport)
        desc->y_count = 0;
        desc->y_modify = 0;
        memcpy(desc+1, desc, sizeof(*desc));
-       desc->next_desc_addr = (unsigned long)(desc+1);
-       desc[1].next_desc_addr = (unsigned long)desc;
+       desc->next_desc_addr = desc + 1;
+       desc[1].next_desc_addr = desc;
        return 0;
 }
 
@@ -872,17 +856,15 @@ struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
        sport->wdsize = wdsize;
        sport->dummy_count = dummy_count;
 
-#if L1_DATA_A_LENGTH != 0
-       sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2);
-#else
-       sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL);
-#endif
+       if (L1_DATA_A_LENGTH)
+               sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+       else
+               sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
        if (sport->dummy_buf == NULL) {
                pr_err("Failed to allocate dummy buffer\n");
                goto __error;
        }
 
-       memset(sport->dummy_buf, 0, dummy_count * 2);
        ret = sport_config_rx_dummy(sport);
        if (ret) {
                pr_err("Failed to config rx dummy ring\n");
@@ -939,6 +921,7 @@ void sport_done(struct sport_device *sport)
                sport = NULL;
 }
 EXPORT_SYMBOL(sport_done);
+
 /*
 * It is only used to send several bytes when dma is not enabled
  * sport controller is configured but not enabled.
@@ -1029,4 +1012,3 @@ EXPORT_SYMBOL(sport_send_and_recv);
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("SPORT driver for ADI Blackfin");
 MODULE_LICENSE("GPL");
-
index d0e0d691ae51f9a8ccc128ac3dddac193b6c21fd..b6c7f7a01cb03756a321651b02f5135eccdd2a4a 100644 (file)
@@ -10,9 +10,11 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
+       select SND_SOC_L3
        select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
        select SND_SOC_AD73311 if I2C
+       select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_PCM3008
@@ -24,6 +26,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
+       select SND_SOC_WM8400 if MFD_WM8400
        select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8580 if I2C
        select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
@@ -34,6 +37,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8990 if I2C
+       select SND_SOC_WM9705 if SND_SOC_AC97_BUS
        select SND_SOC_WM9712 if SND_SOC_AC97_BUS
        select SND_SOC_WM9713 if SND_SOC_AC97_BUS
         help
@@ -58,6 +62,9 @@ config SND_SOC_AD1980
 config SND_SOC_AD73311
        tristate
 
+config SND_SOC_AK4104
+       tristate
+
 config SND_SOC_AK4535
        tristate
 
@@ -65,12 +72,6 @@ config SND_SOC_AK4535
 config SND_SOC_CS4270
        tristate
 
-# Cirrus Logic CS4270 Codec Hardware Mute Support
-# Select if you have external muting circuitry attached to your CS4270.
-config SND_SOC_CS4270_HWMUTE
-       bool
-       depends on SND_SOC_CS4270
-
 # Cirrus Logic CS4270 Codec VD = 3.3V Errata
 # Select if you are affected by the errata where the part will not function
 # if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
@@ -90,7 +91,6 @@ config SND_SOC_SSM2602
 
 config SND_SOC_TLV320AIC23
        tristate
-       depends on I2C
 
 config SND_SOC_TLV320AIC26
        tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
@@ -98,15 +98,12 @@ config SND_SOC_TLV320AIC26
 
 config SND_SOC_TLV320AIC3X
        tristate
-       depends on I2C
 
 config SND_SOC_TWL4030
        tristate
-       depends on TWL4030_CORE
 
 config SND_SOC_UDA134X
        tristate
-       select SND_SOC_L3
 
 config SND_SOC_UDA1380
         tristate
@@ -114,6 +111,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WM8350
        tristate
 
+config SND_SOC_WM8400
+       tristate
+
 config SND_SOC_WM8510
        tristate
 
@@ -144,6 +144,9 @@ config SND_SOC_WM8971
 config SND_SOC_WM8990
        tristate
 
+config SND_SOC_WM9705
+       tristate
+
 config SND_SOC_WM9712
        tristate
 
index c4ddc9aa2bbd8aaa5a35bd7ecc3a487603990a97..030d2454725f23dcf15cbfa531e3b5dcd2101caa 100644 (file)
@@ -1,6 +1,7 @@
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
+snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-l3-objs := l3.o
@@ -13,6 +14,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8350-objs := wm8350.o
+snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8580-objs := wm8580.o
 snd-soc-wm8728-objs := wm8728.o
@@ -23,12 +25,14 @@ snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
@@ -41,6 +45,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
+obj-$(CONFIG_SND_SOC_WM8400)   += snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8580)   += snd-soc-wm8580.o
 obj-$(CONFIG_SND_SOC_WM8728)   += snd-soc-wm8728.o
@@ -51,5 +56,7 @@ obj-$(CONFIG_SND_SOC_WM8900)  += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM8991)   += snd-soc-wm8991.o
+obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
index fb53e6511af25d0b0d0dd164a1b1de0a511f73c7..b0d4af145b873900509ce18239e2c85899aa9069 100644 (file)
@@ -30,7 +30,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -41,6 +41,10 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops ac97_dai_ops = {
+       .prepare        = ac97_prepare,
+};
+
 struct snd_soc_dai ac97_dai = {
        .name = "AC97 HiFi",
        .ac97_control = 1,
@@ -56,8 +60,7 @@ struct snd_soc_dai ac97_dai = {
                .channels_max = 2,
                .rates = STD_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .prepare = ac97_prepare,},
+       .ops = &ac97_dai_ops,
 };
 EXPORT_SYMBOL_GPL(ac97_dai);
 
@@ -84,10 +87,10 @@ static int ac97_soc_probe(struct platform_device *pdev)
 
        printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->codec)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (!socdev->card->codec)
                return -ENOMEM;
-       codec = socdev->codec;
+       codec = socdev->card->codec;
        mutex_init(&codec->mutex);
 
        codec->name = "AC97";
@@ -123,23 +126,21 @@ bus_err:
        snd_soc_free_pcms(socdev);
 
 err:
-       kfree(socdev->codec->reg_cache);
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
        return ret;
 }
 
 static int ac97_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (!codec)
                return 0;
 
        snd_soc_free_pcms(socdev);
-       kfree(socdev->codec->reg_cache);
-       kfree(socdev->codec);
+       kfree(socdev->card->codec);
 
        return 0;
 }
@@ -149,7 +150,7 @@ static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 
-       snd_ac97_suspend(socdev->codec->ac97);
+       snd_ac97_suspend(socdev->card->codec->ac97);
 
        return 0;
 }
@@ -158,7 +159,7 @@ static int ac97_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 
-       snd_ac97_resume(socdev->codec->ac97);
+       snd_ac97_resume(socdev->card->codec->ac97);
 
        return 0;
 }
index 73fdbb4d4a3d4702cbf6d9b3b25d59d00a287e2b..ddb3b08ac23c441dd93112295a7182881c856041 100644 (file)
@@ -93,20 +93,6 @@ SOC_ENUM("Capture Source", ad1980_cap_src),
 SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
 };
 
-/* add non dapm controls */
-static int ad1980_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) {
-               err = snd_ctl_add(codec->card, snd_soc_cnew(
-                               &ad1980_snd_ac97_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -123,7 +109,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        default:
                reg = reg >> 1;
 
-               if (reg >= (ARRAY_SIZE(ad1980_reg)))
+               if (reg >= ARRAY_SIZE(ad1980_reg))
                        return -EINVAL;
 
                return cache[reg];
@@ -137,7 +123,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 
        soc_ac97_ops.write(codec->ac97, reg, val);
        reg = reg >> 1;
-       if (reg < (ARRAY_SIZE(ad1980_reg)))
+       if (reg < ARRAY_SIZE(ad1980_reg))
                cache[reg] = val;
 
        return 0;
@@ -200,10 +186,10 @@ static int ad1980_soc_probe(struct platform_device *pdev)
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->codec == NULL)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (socdev->card->codec == NULL)
                return -ENOMEM;
-       codec = socdev->codec;
+       codec = socdev->card->codec;
        mutex_init(&codec->mutex);
 
        codec->reg_cache =
@@ -269,7 +255,8 @@ static int ad1980_soc_probe(struct platform_device *pdev)
        ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
        ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
-       ad1980_add_controls(codec);
+       snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
+                               ARRAY_SIZE(ad1980_snd_ac97_controls));
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register card\n");
@@ -288,15 +275,15 @@ codec_err:
        kfree(codec->reg_cache);
 
 cache_err:
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
        return ret;
 }
 
 static int ad1980_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec == NULL)
                return 0;
index b09289a1e55af93460f68cb6f5e76707a884a51a..e61dac5e7b8fadac8b04c1e554af3fbd1f793e64 100644 (file)
@@ -53,7 +53,7 @@ static int ad73311_soc_probe(struct platform_device *pdev)
        codec->owner = THIS_MODULE;
        codec->dai = &ad73311_dai;
        codec->num_dai = 1;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
@@ -75,15 +75,15 @@ static int ad73311_soc_probe(struct platform_device *pdev)
 register_err:
        snd_soc_free_pcms(socdev);
 pcm_err:
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
        return ret;
 }
 
 static int ad73311_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec == NULL)
                return 0;
index 507ce0c30edff59f98ec2d0e3a8d46f6f58c8ff1..569573d2d4d7a628b18c9c1a108512e11a4e9008 100644 (file)
@@ -70,7 +70,7 @@
 #define REGD_IGS(x)            (x & 0x7)
 #define REGD_RMOD              (1 << 3)
 #define REGD_OGS(x)            ((x & 0x7) << 4)
-#define REGD_MUTE              (x << 7)
+#define REGD_MUTE              (1 << 7)
 
 /* Control register E */
 #define CTRL_REG_E     (4 << 8)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
new file mode 100644 (file)
index 0000000..4d47bc4
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * AK4104 ALSA SoC (ASoC) driver
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <linux/spi/spi.h>
+#include <sound/asoundef.h>
+
+#include "ak4104.h"
+
+/* AK4104 registers addresses */
+#define AK4104_REG_CONTROL1            0x00
+#define AK4104_REG_RESERVED            0x01
+#define AK4104_REG_CONTROL2            0x02
+#define AK4104_REG_TX                  0x03
+#define AK4104_REG_CHN_STATUS(x)       ((x) + 0x04)
+#define AK4104_NUM_REGS                        10
+
+#define AK4104_REG_MASK                        0x1f
+#define AK4104_READ                    0xc0
+#define AK4104_WRITE                   0xe0
+#define AK4104_RESERVED_VAL            0x5b
+
+/* Bit masks for AK4104 registers */
+#define AK4104_CONTROL1_RSTN           (1 << 0)
+#define AK4104_CONTROL1_PW             (1 << 1)
+#define AK4104_CONTROL1_DIF0           (1 << 2)
+#define AK4104_CONTROL1_DIF1           (1 << 3)
+
+#define AK4104_CONTROL2_SEL0           (1 << 0)
+#define AK4104_CONTROL2_SEL1           (1 << 1)
+#define AK4104_CONTROL2_MODE           (1 << 2)
+
+#define AK4104_TX_TXE                  (1 << 0)
+#define AK4104_TX_V                    (1 << 1)
+
+#define DRV_NAME "ak4104"
+
+struct ak4104_private {
+       struct snd_soc_codec codec;
+       u8 reg_cache[AK4104_NUM_REGS];
+};
+
+static int ak4104_fill_cache(struct snd_soc_codec *codec)
+{
+       int i;
+       u8 *reg_cache = codec->reg_cache;
+       struct spi_device *spi = codec->control_data;
+
+       for (i = 0; i < codec->reg_cache_size; i++) {
+               int ret = spi_w8r8(spi, i | AK4104_READ);
+               if (ret < 0) {
+                       dev_err(&spi->dev, "SPI write failure\n");
+                       return ret;
+               }
+
+               reg_cache[i] = ret;
+       }
+
+       return 0;
+}
+
+static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
+                                         unsigned int reg)
+{
+       u8 *reg_cache = codec->reg_cache;
+
+       if (reg >= codec->reg_cache_size)
+               return -EINVAL;
+
+       return reg_cache[reg];
+}
+
+static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
+                           unsigned int value)
+{
+       u8 *cache = codec->reg_cache;
+       struct spi_device *spi = codec->control_data;
+
+       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 };
+               if (spi_write(spi, tmp, sizeof(tmp))) {
+                       dev_err(&spi->dev, "SPI write failed\n");
+                       return -EIO;
+               }
+
+               cache[reg] = value;
+       }
+
+       return 0;
+}
+
+static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int val = 0;
+
+       val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+       if (val < 0)
+               return val;
+
+       val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1);
+
+       /* set DAI format */
+       switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val |= AK4104_CONTROL1_DIF0;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
+               break;
+       default:
+               dev_err(codec->dev, "invalid dai format\n");
+               return -EINVAL;
+       }
+
+       /* This device can only be slave */
+       if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+               return -EINVAL;
+
+       return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+}
+
+static int ak4104_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int val = 0;
+
+       /* set the IEC958 bits: consumer mode, no copyright bit */
+       val |= IEC958_AES0_CON_NOT_COPYRIGHT;
+       ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val);
+
+       val = 0;
+
+       switch (params_rate(params)) {
+       case 44100:
+               val |= IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               val |= IEC958_AES3_CON_FS_48000;
+               break;
+       case 32000:
+               val |= IEC958_AES3_CON_FS_32000;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported sampling rate\n");
+               return -EINVAL;
+       }
+
+       return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
+}
+
+static struct snd_soc_dai_ops ak4101_dai_ops = {
+       .hw_params = ak4104_hw_params,
+       .set_fmt = ak4104_set_dai_fmt,
+};
+
+struct snd_soc_dai ak4104_dai = {
+       .name = DRV_NAME,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_32000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE  |
+                          SNDRV_PCM_FMTBIT_S24_3LE |
+                          SNDRV_PCM_FMTBIT_S24_LE
+       },
+       .ops = &ak4101_dai_ops,
+};
+
+static struct snd_soc_codec *ak4104_codec;
+
+static int ak4104_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_codec *codec;
+       struct ak4104_private *ak4104;
+       int ret, val;
+
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+       if (!ak4104) {
+               dev_err(&spi->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       codec = &ak4104->codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->dev = &spi->dev;
+       codec->name = DRV_NAME;
+       codec->owner = THIS_MODULE;
+       codec->dai = &ak4104_dai;
+       codec->num_dai = 1;
+       codec->private_data = ak4104;
+       codec->control_data = spi;
+       codec->reg_cache = ak4104->reg_cache;
+       codec->reg_cache_size = AK4104_NUM_REGS;
+
+       /* read all regs and fill the cache */
+       ret = ak4104_fill_cache(codec);
+       if (ret < 0) {
+               dev_err(&spi->dev, "failed to fill register cache\n");
+               return ret;
+       }
+
+       /* read the 'reserved' register - according to the datasheet, it
+        * should contain 0x5b. Not a good way to verify the presence of
+        * the device, but there is no hardware ID register. */
+       if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
+                                        AK4104_RESERVED_VAL) {
+               ret = -ENODEV;
+               goto error_free_codec;
+       }
+
+       /* set power-up and non-reset bits */
+       val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+       val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
+       ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+       if (ret < 0)
+               goto error_free_codec;
+
+       /* enable transmitter */
+       val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
+       val |= AK4104_TX_TXE;
+       ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
+       if (ret < 0)
+               goto error_free_codec;
+
+       ak4104_codec = codec;
+       ret = snd_soc_register_dai(&ak4104_dai);
+       if (ret < 0) {
+               dev_err(&spi->dev, "failed to register DAI\n");
+               goto error_free_codec;
+       }
+
+       spi_set_drvdata(spi, ak4104);
+       dev_info(&spi->dev, "SPI device initialized\n");
+       return 0;
+
+error_free_codec:
+       kfree(ak4104);
+       ak4104_dai.dev = NULL;
+       return ret;
+}
+
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
+{
+       int ret, val;
+       struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+
+       val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+       if (val < 0)
+               return val;
+
+       /* clear power-up and non-reset bits */
+       val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+       ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
+       if (ret < 0)
+               return ret;
+
+       ak4104_codec = NULL;
+       kfree(ak4104);
+       return 0;
+}
+
+static int ak4104_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = ak4104_codec;
+       int ret;
+
+       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
+       socdev->card->codec = codec;
+
+       /* Register PCMs */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to create pcms\n");
+               return ret;
+       }
+
+       /* Register the socdev */
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to register card\n");
+               snd_soc_free_pcms(socdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ak4104_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       snd_soc_free_pcms(socdev);
+       return 0;
+};
+
+struct snd_soc_codec_device soc_codec_device_ak4104 = {
+       .probe =        ak4104_probe,
+       .remove =       ak4104_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+
+static struct spi_driver ak4104_spi_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = ak4104_spi_probe,
+       .remove = __devexit_p(ak4104_spi_remove),
+};
+
+static int __init ak4104_init(void)
+{
+       pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n");
+       return spi_register_driver(&ak4104_spi_driver);
+}
+module_init(ak4104_init);
+
+static void __exit ak4104_exit(void)
+{
+       spi_unregister_driver(&ak4104_spi_driver);
+}
+module_exit(ak4104_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
new file mode 100644 (file)
index 0000000..eb88fe7
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _AK4104_H
+#define _AK4104_H
+
+extern struct snd_soc_dai ak4104_dai;
+extern struct snd_soc_codec_device soc_codec_device_ak4104;
+
+#endif
index 81300d8d42ca2a5f2648665fec39aef5490c0f37..1f63d387a2f49e366b0cfe95ff539615dd6a5795 100644 (file)
@@ -155,21 +155,6 @@ static const struct snd_kcontrol_new ak4535_snd_controls[] = {
        SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
 };
 
-/* add non dapm controls */
-static int ak4535_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Mono 1 Mixer */
 static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
        SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
@@ -344,7 +329,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct ak4535_priv *ak4535 = codec->private_data;
        u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
        int rate = params_rate(params), fs = 256;
@@ -436,6 +421,13 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops ak4535_dai_ops = {
+       .hw_params      = ak4535_hw_params,
+       .set_fmt        = ak4535_set_dai_fmt,
+       .digital_mute   = ak4535_mute,
+       .set_sysclk     = ak4535_set_dai_sysclk,
+};
+
 struct snd_soc_dai ak4535_dai = {
        .name = "AK4535",
        .playback = {
@@ -450,19 +442,14 @@ struct snd_soc_dai ak4535_dai = {
                .channels_max = 2,
                .rates = AK4535_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = ak4535_hw_params,
-               .set_fmt = ak4535_set_dai_fmt,
-               .digital_mute = ak4535_mute,
-               .set_sysclk = ak4535_set_dai_sysclk,
-       },
+       .ops = &ak4535_dai_ops,
 };
 EXPORT_SYMBOL_GPL(ak4535_dai);
 
 static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -471,7 +458,7 @@ static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
 static int ak4535_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        ak4535_sync(codec);
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        ak4535_set_bias_level(codec, codec->suspend_bias_level);
@@ -484,7 +471,7 @@ static int ak4535_resume(struct platform_device *pdev)
  */
 static int ak4535_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        codec->name = "AK4535";
@@ -510,7 +497,8 @@ static int ak4535_init(struct snd_soc_device *socdev)
        /* power on device */
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       ak4535_add_controls(codec);
+       snd_soc_add_controls(codec, ak4535_snd_controls,
+                               ARRAY_SIZE(ak4535_snd_controls));
        ak4535_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -537,7 +525,7 @@ static int ak4535_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = ak4535_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -636,7 +624,7 @@ static int ak4535_probe(struct platform_device *pdev)
        }
 
        codec->private_data = ak4535;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -663,7 +651,7 @@ static int ak4535_probe(struct platform_device *pdev)
 static int ak4535_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
index f1aa0c34421c76f5e63f029847a62fc1a26d954f..7fa09a387622cbff69b28b88e83819faa876d4e9 100644 (file)
@@ -3,27 +3,22 @@
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
  *
  * This is an ASoC device driver for the Cirrus Logic CS4270 codec.
  *
  * Current features/limitations:
  *
- * 1) Software mode is supported.  Stand-alone mode is automatically
- *    selected if I2C is disabled or if a CS4270 is not found on the I2C
- *    bus.  However, stand-alone mode is only partially implemented because
- *    there is no mechanism yet for this driver and the machine driver to
- *    communicate the values of the M0, M1, MCLK1, and MCLK2 pins.
- * 2) Only I2C is supported, not SPI
- * 3) Only Master mode is supported, not Slave.
- * 4) The machine driver's 'startup' function must call
- *    cs4270_set_dai_sysclk() with the value of MCLK.
- * 5) Only I2S and left-justified modes are supported
- * 6) Power management is not supported
- * 7) The only supported control is volume and hardware mute (if enabled)
+ * - Software mode is supported.  Stand-alone mode is not supported.
+ * - Only I2C is supported, not SPI
+ * - Support for master and slave mode
+ * - The machine driver's 'startup' function must call
+ *   cs4270_set_dai_sysclk() with the value of MCLK.
+ * - Only I2S and left-justified modes are supported
+ * - Power management is not supported
  */
 
 #include <linux/module.h>
 
 #include "cs4270.h"
 
-/* If I2C is defined, then we support software mode.  However, if we're
-   not compiled as module but I2C is, then we can't use I2C calls. */
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-#define USE_I2C
-#endif
-
-/* Private data for the CS4270 */
-struct cs4270_private {
-       unsigned int mclk; /* Input frequency of the MCLK pin */
-       unsigned int mode; /* The mode (I2S or left-justified) */
-};
-
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
  * interface requires data to be sent serially with the MSbit first.
@@ -60,8 +43,6 @@ struct cs4270_private {
                        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
                        SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
 
-#ifdef USE_I2C
-
 /* CS4270 registers addresses */
 #define CS4270_CHIPID  0x01    /* Chip ID */
 #define CS4270_PWRCTL  0x02    /* Power Control */
@@ -121,8 +102,22 @@ struct cs4270_private {
 #define CS4270_MUTE_DAC_A      0x01
 #define CS4270_MUTE_DAC_B      0x02
 
-/*
- * Clock Ratio Selection for Master Mode with I2C enabled
+/* Private data for the CS4270 */
+struct cs4270_private {
+       struct snd_soc_codec codec;
+       u8 reg_cache[CS4270_NUMREGS];
+       unsigned int mclk; /* Input frequency of the MCLK pin */
+       unsigned int mode; /* The mode (I2S or left-justified) */
+       unsigned int slave_mode;
+};
+
+/**
+ * struct cs4270_mode_ratios - clock ratio tables
+ * @ratio: the ratio of MCLK to the sample rate
+ * @speed_mode: the Speed Mode bits to set in the Mode Control register for
+ *              this ratio
+ * @mclk: the Ratio Select bits to set in the Mode Control register for this
+ *        ratio
  *
  * The data for this chart is taken from Table 5 of the CS4270 reference
  * manual.
@@ -131,31 +126,30 @@ struct cs4270_private {
  * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
  * rates the CS4270 currently supports.
  *
- * Each element in this array corresponds to the ratios in mclk_ratios[].
- * These two arrays need to be in sync.
- *
- * 'speed_mode' is the corresponding bit pattern to be written to the
+ * @speed_mode is the corresponding bit pattern to be written to the
  * MODE bits of the Mode Control Register
  *
- * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
+ * @mclk is the corresponding bit pattern to be wirten to the MCLK bits of
  * the Mode Control Register.
  *
  * In situations where a single ratio is represented by multiple speed
  * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
  * double-speed instead of quad-speed.  However, the CS4270 errata states
- * that Divide-By-1.5 can cause failures, so we avoid that mode where
+ * that divide-By-1.5 can cause failures, so we avoid that mode where
  * possible.
  *
- * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
- * work if VD = 3.3V.  If this effects you, select the
+ * Errata: There is an errata for the CS4270 where divide-by-1.5 does not
+ * work if Vd is 3.3V.  If this effects you, select the
  * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
  * never select any sample rates that require divide-by-1.5.
  */
-static struct {
+struct cs4270_mode_ratios {
        unsigned int ratio;
        u8 speed_mode;
        u8 mclk;
-} cs4270_mode_ratios[] = {
+};
+
+static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
        {64, CS4270_MODE_4X, CS4270_MODE_DIV1},
 #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
        {96, CS4270_MODE_4X, CS4270_MODE_DIV15},
@@ -172,34 +166,27 @@ static struct {
 /* The number of MCLK/LRCK ratios supported by the CS4270 */
 #define NUM_MCLK_RATIOS                ARRAY_SIZE(cs4270_mode_ratios)
 
-/*
- * Determine the CS4270 samples rates.
+/**
+ * cs4270_set_dai_sysclk - determine the CS4270 samples rates.
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
  *
- * 'freq' is the input frequency to MCLK.  The other parameters are ignored.
+ * This function is used to tell the codec driver what the input MCLK
+ * frequency is.
  *
  * The value of MCLK is used to determine which sample rates are supported
  * by the CS4270.  The ratio of MCLK / Fs must be equal to one of nine
- * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
+ * supported values - 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
  *
  * This function calculates the nine ratios and determines which ones match
  * a standard sample rate.  If there's a match, then it is added to the list
- * of support sample rates.
+ * of supported sample rates.
  *
  * This function must be called by the machine driver's 'startup' function,
  * otherwise the list of supported sample rates will not be available in
  * time for ALSA.
- *
- * Note that in stand-alone mode, the sample rate is determined by input
- * pins M0, M1, MDIV1, and MDIV2.  Also in stand-alone mode, divide-by-3
- * is not a programmable option.  However, divide-by-3 is not an available
- * option in stand-alone mode.  This cases two problems: a ratio of 768 is
- * not available (it requires divide-by-3) and B) ratios 192 and 384 can
- * only be selected with divide-by-1.5, but there is an errate that make
- * this selection difficult.
- *
- * In addition, there is no mechanism for communicating with the machine
- * driver what the input settings can be.  This would need to be implemented
- * for stand-alone mode to work.
  */
 static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
@@ -225,7 +212,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        rates &= ~SNDRV_PCM_RATE_KNOT;
 
        if (!rates) {
-               printk(KERN_ERR "cs4270: could not find a valid sample rate\n");
+               dev_err(codec->dev, "could not find a valid sample rate\n");
                return -EINVAL;
        }
 
@@ -240,8 +227,10 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-/*
- * Configure the codec for the selected audio format
+/**
+ * cs4270_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @format: a SND_SOC_DAIFMT_x value indicating the data format
  *
  * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
  * codec accordingly.
@@ -258,32 +247,43 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct cs4270_private *cs4270 = codec->private_data;
        int ret = 0;
 
+       /* set DAI format */
        switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
        case SND_SOC_DAIFMT_LEFT_J:
                cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
                break;
        default:
-               printk(KERN_ERR "cs4270: invalid DAI format\n");
+               dev_err(codec->dev, "invalid dai format\n");
+               ret = -EINVAL;
+       }
+
+       /* set master/slave audio interface */
+       switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               cs4270->slave_mode = 1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               cs4270->slave_mode = 0;
+               break;
+       default:
+               /* all other modes are unsupported by the hardware */
                ret = -EINVAL;
        }
 
        return ret;
 }
 
-/*
- * A list of addresses on which this CS4270 could use.  I2C addresses are
- * 7 bits.  For the CS4270, the upper four bits are always 1001, and the
- * lower three bits are determined via the AD2, AD1, and AD0 pins
- * (respectively).
- */
-static const unsigned short normal_i2c[] = {
-       0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-/*
- * Pre-fill the CS4270 register cache.
+/**
+ * cs4270_fill_cache - pre-fill the CS4270 register cache.
+ * @codec: the codec for this CS4270
+ *
+ * This function fills in the CS4270 register cache by reading the register
+ * values from the hardware.
+ *
+ * This CS4270 registers are cached to avoid excessive I2C I/O operations.
+ * After the initial read to pre-fill the cache, the CS4270 never updates
+ * the register values, so we won't have a cache coherency problem.
  *
  * We use the auto-increment feature of the CS4270 to read all registers in
  * one shot.
@@ -298,7 +298,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec)
                CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache);
 
        if (length != CS4270_NUMREGS) {
-               printk(KERN_ERR "cs4270: I2C read failure, addr=0x%x\n",
+               dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
                       i2c_client->addr);
                return -EIO;
        }
@@ -306,12 +306,17 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec)
        return 0;
 }
 
-/*
- * Read from the CS4270 register cache.
+/**
+ * cs4270_read_reg_cache - read from the CS4270 register cache.
+ * @codec: the codec for this CS4270
+ * @reg: the register to read
+ *
+ * This function returns the value for a given register.  It reads only from
+ * the register cache, not the hardware itself.
  *
  * This CS4270 registers are cached to avoid excessive I2C I/O operations.
  * After the initial read to pre-fill the cache, the CS4270 never updates
- * the register values, so we won't have a cache coherncy problem.
+ * the register values, so we won't have a cache coherency problem.
  */
 static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg)
@@ -324,8 +329,11 @@ static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
        return cache[reg - CS4270_FIRSTREG];
 }
 
-/*
- * Write to a CS4270 register via the I2C bus.
+/**
+ * cs4270_i2c_write - write to a CS4270 register via the I2C bus.
+ * @codec: the codec for this CS4270
+ * @reg: the register to write
+ * @value: the value to write to the register
  *
  * This function writes the given value to the given CS4270 register, and
  * also updates the register cache.
@@ -346,7 +354,7 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
        if (cache[reg - CS4270_FIRSTREG] != value) {
                struct i2c_client *client = codec->control_data;
                if (i2c_smbus_write_byte_data(client, reg, value)) {
-                       printk(KERN_ERR "cs4270: I2C write failed\n");
+                       dev_err(codec->dev, "i2c write failed\n");
                        return -EIO;
                }
 
@@ -357,11 +365,17 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-/*
- * Program the CS4270 with the given hardware parameters.
+/**
+ * cs4270_hw_params - program the CS4270 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
  *
- * The .ops functions are used to provide board-specific data, like
- * input frequencies, to this driver.  This function takes that information,
+ * The .ops functions are used to provide board-specific data, like input
+ * frequencies, to this driver.  This function takes that information,
  * combines it with the hardware parameters provided, and programs the
  * hardware accordingly.
  */
@@ -371,7 +385,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct cs4270_private *cs4270 = codec->private_data;
        int ret;
        unsigned int i;
@@ -391,33 +405,28 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 
        if (i == NUM_MCLK_RATIOS) {
                /* We did not find a matching ratio */
-               printk(KERN_ERR "cs4270: could not find matching ratio\n");
+               dev_err(codec->dev, "could not find matching ratio\n");
                return -EINVAL;
        }
 
-       /* Freeze and power-down the codec */
-
-       ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE |
-                           CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC |
-                           CS4270_PWRCTL_PDN);
-       if (ret < 0) {
-               printk(KERN_ERR "cs4270: I2C write failed\n");
-               return ret;
-       }
-
-       /* Program the mode control register */
+       /* Set the sample rate */
 
        reg = snd_soc_read(codec, CS4270_MODE);
        reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
-       reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk;
+       reg |= cs4270_mode_ratios[i].mclk;
+
+       if (cs4270->slave_mode)
+               reg |= CS4270_MODE_SLAVE;
+       else
+               reg |= cs4270_mode_ratios[i].speed_mode;
 
        ret = snd_soc_write(codec, CS4270_MODE, reg);
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: I2C write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
-       /* Program the format register */
+       /* Set the DAI format */
 
        reg = snd_soc_read(codec, CS4270_FORMAT);
        reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);
@@ -430,55 +439,23 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
                break;
        default:
-               printk(KERN_ERR "cs4270: unknown format\n");
+               dev_err(codec->dev, "unknown dai format\n");
                return -EINVAL;
        }
 
        ret = snd_soc_write(codec, CS4270_FORMAT, reg);
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: I2C write failed\n");
-               return ret;
-       }
-
-       /* Disable auto-mute.  This feature appears to be buggy, because in
-          some situations, auto-mute will not deactivate when it should. */
-
-       reg = snd_soc_read(codec, CS4270_MUTE);
-       reg &= ~CS4270_MUTE_AUTO;
-       ret = snd_soc_write(codec, CS4270_MUTE, reg);
-       if (ret < 0) {
-               printk(KERN_ERR "cs4270: I2C write failed\n");
-               return ret;
-       }
-
-       /* Disable automatic volume control.  It's enabled by default, and
-        * it causes volume change commands to be delayed, sometimes until
-        * after playback has started.
-        */
-
-       reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
-       reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
-       ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
-       if (ret < 0) {
-               printk(KERN_ERR "I2C write failed\n");
-               return ret;
-       }
-
-       /* Thaw and power-up the codec */
-
-       ret = snd_soc_write(codec, CS4270_PWRCTL, 0);
-       if (ret < 0) {
-               printk(KERN_ERR "cs4270: I2C write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
        return ret;
 }
 
-#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-
-/*
- * Set the CS4270 external mute
+/**
+ * cs4270_mute - enable/disable the CS4270 external mute
+ * @dai: the SOC DAI
+ * @mute: 0 = disable mute, 1 = enable mute
  *
  * This function toggles the mute bits in the MUTE register.  The CS4270's
  * mute capability is intended for external muting circuitry, so if the
@@ -493,275 +470,305 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute)
        reg6 = snd_soc_read(codec, CS4270_MUTE);
 
        if (mute)
-               reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |
-                       CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
+               reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
        else
-               reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |
-                         CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
+               reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
 
        return snd_soc_write(codec, CS4270_MUTE, reg6);
 }
 
-#endif
-
-static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
-
 /* A list of non-DAPM controls that the CS4270 supports */
 static const struct snd_kcontrol_new cs4270_snd_controls[] = {
        SOC_DOUBLE_R("Master Playback Volume",
-               CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)
-};
-
-static const struct i2c_device_id cs4270_id[] = {
-       {"cs4270", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
-
-static struct i2c_driver cs4270_i2c_driver = {
-       .driver = {
-               .name = "CS4270 I2C",
-               .owner = THIS_MODULE,
-       },
-       .id_table = cs4270_id,
-       .probe = cs4270_i2c_probe,
+               CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1),
+       SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
+       SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
+       SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
+       SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
+       SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
+       SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0)
 };
 
 /*
- * Global variable to store socdev for i2c probe function.
+ * cs4270_codec - global variable to store codec for the ASoC probe function
  *
  * If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_socdec.  This is the only way to pass the socdev structure to
- * cs4270_i2c_probe().
- *
- * The real solution to cs4270_socdev is to create a mechanism
- * that maps I2C addresses to snd_soc_device structures.  Perhaps the
- * creation of the snd_soc_device object should be moved out of
- * cs4270_probe() and into cs4270_i2c_probe(), but that would make this
- * driver dependent on I2C.  The CS4270 supports "stand-alone" mode, whereby
- * the chip is *not* connected to the I2C bus, but is instead configured via
- * input pins.
+ * cs4270_codec.  This is the only way to pass the codec structure from
+ * cs4270_i2c_probe() to cs4270_probe().  Unfortunately, there is no good
+ * way to synchronize these two functions.  cs4270_i2c_probe() can be called
+ * multiple times before cs4270_probe() is called even once.  So for now, we
+ * also only allow cs4270_i2c_probe() to be run once.  That means that we do
+ * not support more than one cs4270 device in the system, at least for now.
  */
-static struct snd_soc_device *cs4270_socdev;
+static struct snd_soc_codec *cs4270_codec;
 
-/*
- * Initialize the I2C interface of the CS4270
- *
- * This function is called for whenever the I2C subsystem finds a device
- * at a particular address.
+static struct snd_soc_dai_ops cs4270_dai_ops = {
+       .hw_params      = cs4270_hw_params,
+       .set_sysclk     = cs4270_set_dai_sysclk,
+       .set_fmt        = cs4270_set_dai_fmt,
+       .digital_mute   = cs4270_mute,
+};
+
+struct snd_soc_dai cs4270_dai = {
+       .name = "cs4270",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = 0,
+               .formats = CS4270_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = 0,
+               .formats = CS4270_FORMATS,
+       },
+       .ops = &cs4270_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs4270_dai);
+
+/**
+ * cs4270_probe - ASoC probe function
+ * @pdev: platform device
  *
- * Note: snd_soc_new_pcms() must be called before this function can be called,
- * because of snd_ctl_add().
+ * This function is called when ASoC has all the pieces it needs to
+ * instantiate a sound driver.
  */
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
+static int cs4270_probe(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = cs4270_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int i;
-       int ret = 0;
-
-       /* Probing all possible addresses has one drawback: if there are
-          multiple CS4270s on the bus, then you cannot specify which
-          socdev is matched with which CS4270.  For now, we just reject
-          this I2C device if the socdev already has one attached. */
-       if (codec->control_data)
-               return -ENODEV;
-
-       /* Note: codec_dai->codec is NULL here */
-
-       codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL);
-       if (!codec->reg_cache) {
-               printk(KERN_ERR "cs4270: could not allocate register cache\n");
-               ret = -ENOMEM;
-               goto error;
-       }
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = cs4270_codec;
+       int ret;
 
-       /* Verify that we have a CS4270 */
+       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
+       socdev->card->codec = codec;
 
-       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+       /* Register PCMs */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: failed to read I2C\n");
-               goto error;
-       }
-       /* The top four bits of the chip ID should be 1100. */
-       if ((ret & 0xF0) != 0xC0) {
-               /* The device at this address is not a CS4270 codec */
-               ret = -ENODEV;
-               goto error;
+               dev_err(codec->dev, "failed to create pcms\n");
+               return ret;
        }
 
-       printk(KERN_INFO "cs4270: found device at I2C address %X\n",
-               i2c_client->addr);
-       printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
-
-       codec->control_data = i2c_client;
-       codec->read = cs4270_read_reg_cache;
-       codec->write = cs4270_i2c_write;
-       codec->reg_cache_size = CS4270_NUMREGS;
-
-       /* The I2C interface is set up, so pre-fill our register cache */
-
-       ret = cs4270_fill_cache(codec);
+       /* Add the non-DAPM controls */
+       ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+                               ARRAY_SIZE(cs4270_snd_controls));
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: failed to fill register cache\n");
-               goto error;
+               dev_err(codec->dev, "failed to add controls\n");
+               goto error_free_pcms;
        }
 
-       /* Add the non-DAPM controls */
-
-       for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
-               struct snd_kcontrol *kctrl =
-               snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
-
-               ret = snd_ctl_add(codec->card, kctrl);
-               if (ret < 0)
-                       goto error;
+       /* And finally, register the socdev */
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to register card\n");
+               goto error_free_pcms;
        }
 
-       i2c_set_clientdata(i2c_client, codec);
-
        return 0;
 
-error:
-       codec->control_data = NULL;
-
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
-       codec->reg_cache_size = 0;
+error_free_pcms:
+       snd_soc_free_pcms(socdev);
 
        return ret;
 }
 
-#endif /* USE_I2C*/
+/**
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
+ *
+ * This function is the counterpart to cs4270_probe().
+ */
+static int cs4270_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 
-struct snd_soc_dai cs4270_dai = {
-       .name = "CS4270",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = 0,
-               .formats = CS4270_FORMATS,
-       },
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = 0,
-               .formats = CS4270_FORMATS,
-       },
+       snd_soc_free_pcms(socdev);
+
+       return 0;
 };
-EXPORT_SYMBOL_GPL(cs4270_dai);
 
-/*
- * ASoC probe function
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
  *
- * This function is called when the machine driver calls
- * platform_device_add().
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
  */
-static int cs4270_probe(struct platform_device *pdev)
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+       const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec;
-       int ret = 0;
+       struct cs4270_private *cs4270;
+       unsigned int reg;
+       int ret;
 
-       printk(KERN_INFO "CS4270 ALSA SoC Codec\n");
+       /* For now, we only support one cs4270 device in the system.  See the
+        * comment for cs4270_codec.
+        */
+       if (cs4270_codec) {
+               dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
+                      i2c_client->addr);
+               dev_err(&i2c_client->dev, "only one per board allowed\n");
+               /* Should we return something other than ENODEV here? */
+               return -ENODEV;
+       }
+
+       /* Verify that we have a CS4270 */
+
+       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+                      i2c_client->addr);
+               return ret;
+       }
+       /* The top four bits of the chip ID should be 1100. */
+       if ((ret & 0xF0) != 0xC0) {
+               dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+                      i2c_client->addr);
+               return -ENODEV;
+       }
+
+       dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+               i2c_client->addr);
+       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
 
        /* Allocate enough space for the snd_soc_codec structure
           and our private data together. */
-       codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) +
-                       sizeof(struct cs4270_private), GFP_KERNEL);
-       if (!codec) {
-               printk(KERN_ERR "cs4270: Could not allocate codec structure\n");
+       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+       if (!cs4270) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
                return -ENOMEM;
        }
+       codec = &cs4270->codec;
 
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
+       codec->dev = &i2c_client->dev;
        codec->name = "CS4270";
        codec->owner = THIS_MODULE;
        codec->dai = &cs4270_dai;
        codec->num_dai = 1;
-       codec->private_data = (void *) codec +
-               ALIGN(sizeof(struct snd_soc_codec), 4);
-
-       socdev->codec = codec;
+       codec->private_data = cs4270;
+       codec->control_data = i2c_client;
+       codec->read = cs4270_read_reg_cache;
+       codec->write = cs4270_i2c_write;
+       codec->reg_cache = cs4270->reg_cache;
+       codec->reg_cache_size = CS4270_NUMREGS;
 
-       /* Register PCMs */
+       /* The I2C interface is set up, so pre-fill our register cache */
 
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = cs4270_fill_cache(codec);
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: failed to create PCMs\n");
+               dev_err(&i2c_client->dev, "failed to fill register cache\n");
                goto error_free_codec;
        }
 
-#ifdef USE_I2C
-       cs4270_socdev = socdev;
+       /* Disable auto-mute.  This feature appears to be buggy.  In some
+        * situations, auto-mute will not deactivate when it should, so we want
+        * this feature disabled by default.  An application (e.g. alsactl) can
+        * re-enabled it by using the controls.
+        */
 
-       ret = i2c_add_driver(&cs4270_i2c_driver);
-       if (ret) {
-               printk(KERN_ERR "cs4270: failed to attach driver");
-               goto error_free_pcms;
+       reg = cs4270_read_reg_cache(codec, CS4270_MUTE);
+       reg &= ~CS4270_MUTE_AUTO;
+       ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "i2c write failed\n");
+               return ret;
        }
 
-       /* Did we find a CS4270 on the I2C bus? */
-       if (codec->control_data) {
-               /* Initialize codec ops */
-               cs4270_dai.ops.hw_params = cs4270_hw_params;
-               cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
-               cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
-#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-               cs4270_dai.ops.digital_mute = cs4270_mute;
-#endif
-       } else
-               printk(KERN_INFO "cs4270: no I2C device found, "
-                       "using stand-alone mode\n");
-#else
-       printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");
-#endif
+       /* Disable automatic volume control.  The hardware enables, and it
+        * causes volume change commands to be delayed, sometimes until after
+        * playback has started.  An application (e.g. alsactl) can
+        * re-enabled it by using the controls.
+        */
 
-       ret = snd_soc_init_card(socdev);
+       reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
+       reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
+       ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
        if (ret < 0) {
-               printk(KERN_ERR "cs4270: failed to register card\n");
-               goto error_del_driver;
+               dev_err(&i2c_client->dev, "i2c write failed\n");
+               return ret;
        }
 
-       return 0;
+       /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
+        * structure for each CS4270 device, but the machine driver needs to
+        * have a pointer to the DAI structure, so for now it must be a global
+        * variable.
+        */
+       cs4270_dai.dev = &i2c_client->dev;
 
-error_del_driver:
-#ifdef USE_I2C
-       i2c_del_driver(&cs4270_i2c_driver);
+       /* Register the DAI.  If all the other ASoC driver have already
+        * registered, then this will call our probe function, so
+        * cs4270_codec needs to be ready.
+        */
+       cs4270_codec = codec;
+       ret = snd_soc_register_dai(&cs4270_dai);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to register DAIe\n");
+               goto error_free_codec;
+       }
 
-error_free_pcms:
-#endif
-       snd_soc_free_pcms(socdev);
+       i2c_set_clientdata(i2c_client, cs4270);
+
+       return 0;
 
 error_free_codec:
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(cs4270);
+       cs4270_codec = NULL;
+       cs4270_dai.dev = NULL;
 
        return ret;
 }
 
-static int cs4270_remove(struct platform_device *pdev)
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-
-#ifdef USE_I2C
-       i2c_del_driver(&cs4270_i2c_driver);
-#endif
+       struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
 
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(cs4270);
+       cs4270_codec = NULL;
+       cs4270_dai.dev = NULL;
 
        return 0;
 }
 
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+       {"cs4270", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+/*
+ * cs4270_i2c_driver - I2C device identification
+ *
+ * This structure tells the I2C subsystem how to identify and support a
+ * given I2C device type.
+ */
+static struct i2c_driver cs4270_i2c_driver = {
+       .driver = {
+               .name = "cs4270",
+               .owner = THIS_MODULE,
+       },
+       .id_table = cs4270_id,
+       .probe = cs4270_i2c_probe,
+       .remove = cs4270_i2c_remove,
+};
+
 /*
  * ASoC codec device structure
  *
@@ -776,13 +783,15 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
 
 static int __init cs4270_init(void)
 {
-       return snd_soc_register_dai(&cs4270_dai);
+       pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
+
+       return i2c_add_driver(&cs4270_i2c_driver);
 }
 module_init(cs4270_init);
 
 static void __exit cs4270_exit(void)
 {
-       snd_soc_unregister_dai(&cs4270_dai);
+       i2c_del_driver(&cs4270_i2c_driver);
 }
 module_exit(cs4270_exit);
 
index 9a3e67e5319cccb6ff176def3bcc5f2403b78a1c..5cda9e6b5a74ae5a468f7a8e2eb9ccac6274fb13 100644 (file)
@@ -67,11 +67,11 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
 
        printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->codec)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (!socdev->card->codec)
                return -ENOMEM;
 
-       codec = socdev->codec;
+       codec = socdev->card->codec;
        mutex_init(&codec->mutex);
 
        codec->name = "PCM3008";
@@ -139,7 +139,7 @@ gpio_err:
 card_err:
        snd_soc_free_pcms(socdev);
 pcm_err:
-       kfree(socdev->codec);
+       kfree(socdev->card->codec);
 
        return ret;
 }
@@ -147,7 +147,7 @@ pcm_err:
 static int pcm3008_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct pcm3008_setup_data *setup = socdev->codec_data;
 
        if (!codec)
@@ -155,7 +155,7 @@ static int pcm3008_soc_remove(struct platform_device *pdev)
 
        pcm3008_gpio_free(setup);
        snd_soc_free_pcms(socdev);
-       kfree(socdev->codec);
+       kfree(socdev->card->codec);
 
        return 0;
 }
index cac373616768b67f8accb9ddad91fb1805bb3876..87f606c7682292af24e5f213cf7c919465116fd1 100644 (file)
@@ -151,21 +151,6 @@ SOC_ENUM("Capture Source", ssm2602_enum[0]),
 SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 };
 
-/* add non dapm controls */
-static int ssm2602_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Output Mixer */
 static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
@@ -291,7 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        u16 srate;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
        struct i2c_client *i2c = codec->control_data;
        u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -336,7 +321,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
        struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
@@ -373,7 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        /* set active */
        ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 
@@ -385,7 +370,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
        /* deactivate */
        if (!codec->active)
@@ -521,6 +506,16 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops ssm2602_dai_ops = {
+       .startup        = ssm2602_startup,
+       .prepare        = ssm2602_pcm_prepare,
+       .hw_params      = ssm2602_hw_params,
+       .shutdown       = ssm2602_shutdown,
+       .digital_mute   = ssm2602_mute,
+       .set_sysclk     = ssm2602_set_dai_sysclk,
+       .set_fmt        = ssm2602_set_dai_fmt,
+};
+
 struct snd_soc_dai ssm2602_dai = {
        .name = "SSM2602",
        .playback = {
@@ -535,22 +530,14 @@ struct snd_soc_dai ssm2602_dai = {
                .channels_max = 2,
                .rates = SSM2602_RATES,
                .formats = SSM2602_FORMATS,},
-       .ops = {
-               .startup = ssm2602_startup,
-               .prepare = ssm2602_pcm_prepare,
-               .hw_params = ssm2602_hw_params,
-               .shutdown = ssm2602_shutdown,
-               .digital_mute = ssm2602_mute,
-               .set_sysclk = ssm2602_set_dai_sysclk,
-               .set_fmt = ssm2602_set_dai_fmt,
-       }
+       .ops = &ssm2602_dai_ops,
 };
 EXPORT_SYMBOL_GPL(ssm2602_dai);
 
 static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -559,7 +546,7 @@ static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
 static int ssm2602_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -581,7 +568,7 @@ static int ssm2602_resume(struct platform_device *pdev)
  */
 static int ssm2602_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int reg, ret = 0;
 
        codec->name = "SSM2602";
@@ -622,7 +609,8 @@ static int ssm2602_init(struct snd_soc_device *socdev)
                        APANA_ENABLE_MIC_BOOST);
        ssm2602_write(codec, SSM2602_PWR, 0);
 
-       ssm2602_add_controls(codec);
+       snd_soc_add_controls(codec, ssm2602_snd_controls,
+                               ARRAY_SIZE(ssm2602_snd_controls));
        ssm2602_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -653,7 +641,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = ssm2602_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -747,7 +735,7 @@ static int ssm2602_probe(struct platform_device *pdev)
        }
 
        codec->private_data = ssm2602;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -768,7 +756,7 @@ static int ssm2602_probe(struct platform_device *pdev)
 static int ssm2602_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
index cfdea007c4cb3ca7536ca14a7527363af7b849ee..c3f4afb5d0173a581d0bcb18e8670d88c2d4d498 100644 (file)
@@ -183,24 +183,6 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
        SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
 };
 
-/* add non dapm controls */
-static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
-{
-
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&tlv320aic23_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-
-}
-
 /* PGA Mixer controls for Line and Mic switch */
 static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
        SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
@@ -423,7 +405,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 iface_reg;
        int ret;
        struct aic23 *aic23 = container_of(codec, struct aic23, codec);
@@ -471,7 +453,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* set active */
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -484,7 +466,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        /* deactivate */
@@ -598,6 +580,15 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
 #define AIC23_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
+       .prepare        = tlv320aic23_pcm_prepare,
+       .hw_params      = tlv320aic23_hw_params,
+       .shutdown       = tlv320aic23_shutdown,
+       .digital_mute   = tlv320aic23_mute,
+       .set_fmt        = tlv320aic23_set_dai_fmt,
+       .set_sysclk     = tlv320aic23_set_dai_sysclk,
+};
+
 struct snd_soc_dai tlv320aic23_dai = {
        .name = "tlv320aic23",
        .playback = {
@@ -612,14 +603,7 @@ struct snd_soc_dai tlv320aic23_dai = {
                    .channels_max = 2,
                    .rates = AIC23_RATES,
                    .formats = AIC23_FORMATS,},
-       .ops = {
-               .prepare = tlv320aic23_pcm_prepare,
-               .hw_params = tlv320aic23_hw_params,
-               .shutdown = tlv320aic23_shutdown,
-               .digital_mute = tlv320aic23_mute,
-               .set_fmt = tlv320aic23_set_dai_fmt,
-               .set_sysclk = tlv320aic23_set_dai_sysclk,
-       }
+       .ops = &tlv320aic23_dai_ops,
 };
 EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
@@ -627,7 +611,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
                               pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -638,7 +622,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
 static int tlv320aic23_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u16 reg;
 
@@ -660,7 +644,7 @@ static int tlv320aic23_resume(struct platform_device *pdev)
  */
 static int tlv320aic23_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
        u16 reg;
 
@@ -718,7 +702,8 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
 
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
 
-       tlv320aic23_add_controls(codec);
+       snd_soc_add_controls(codec, tlv320aic23_snd_controls,
+                               ARRAY_SIZE(tlv320aic23_snd_controls));
        tlv320aic23_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -746,7 +731,7 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *i2c_id)
 {
        struct snd_soc_device *socdev = tlv320aic23_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -804,7 +789,7 @@ static int tlv320aic23_probe(struct platform_device *pdev)
        if (aic23 == NULL)
                return -ENOMEM;
        codec = &aic23->codec;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -823,7 +808,7 @@ static int tlv320aic23_probe(struct platform_device *pdev)
 static int tlv320aic23_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        if (codec->control_data)
index 29f2f1a017fde8744816005584ca9b676d6fdfa5..3387d9e736ea23e23e075e0e1a7409c8deebaeab 100644 (file)
@@ -130,7 +130,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct aic26 *aic26 = codec->private_data;
        int fsref, divisor, wlen, pval, jval, dval, qval;
        u16 reg;
@@ -270,6 +270,13 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 #define AIC26_FORMATS  (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
                         SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
+static struct snd_soc_dai_ops aic26_dai_ops = {
+       .hw_params      = aic26_hw_params,
+       .digital_mute   = aic26_mute,
+       .set_sysclk     = aic26_set_sysclk,
+       .set_fmt        = aic26_set_fmt,
+};
+
 struct snd_soc_dai aic26_dai = {
        .name = "tlv320aic26",
        .playback = {
@@ -286,12 +293,7 @@ struct snd_soc_dai aic26_dai = {
                .rates = AIC26_RATES,
                .formats = AIC26_FORMATS,
        },
-       .ops = {
-               .hw_params = aic26_hw_params,
-               .digital_mute = aic26_mute,
-               .set_sysclk = aic26_set_sysclk,
-               .set_fmt = aic26_set_fmt,
-       },
+       .ops = &aic26_dai_ops,
 };
 EXPORT_SYMBOL_GPL(aic26_dai);
 
@@ -322,9 +324,8 @@ static int aic26_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec;
-       struct snd_kcontrol *kcontrol;
        struct aic26 *aic26;
-       int i, ret, err;
+       int ret, err;
 
        dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
        dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
@@ -338,7 +339,7 @@ static int aic26_probe(struct platform_device *pdev)
                return -ENODEV;
        }
        codec = &aic26->codec;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
 
        dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
                &pdev->dev, socdev->dev);
@@ -351,11 +352,9 @@ static int aic26_probe(struct platform_device *pdev)
 
        /* register controls */
        dev_dbg(&pdev->dev, "Registering controls\n");
-       for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
-               kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
-               err = snd_ctl_add(codec->card, kcontrol);
-               WARN_ON(err < 0);
-       }
+       err = snd_soc_add_controls(codec, aic26_snd_controls,
+                       ARRAY_SIZE(aic26_snd_controls));
+       WARN_ON(err < 0);
 
        /* CODEC is setup, we can register the card now */
        dev_dbg(&pdev->dev, "Registering card\n");
index aea0cb72d80a9ad96f81f43e0454231c613cffbf..ab099f482487b7e642d0f3d1372e6001673b3d27 100644 (file)
@@ -45,6 +45,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 #include "tlv320aic3x.h"
 
@@ -250,56 +251,86 @@ static const struct soc_enum aic3x_enum[] = {
        SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
 };
 
+/*
+ * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
+/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */
+static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
+/*
+ * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB.
+ * Step size is approximately 0.5 dB over most of the scale but increasing
+ * near the very low levels.
+ * Define dB scale so that it is mostly correct for range about -55 to 0 dB
+ * but having increasing dB difference below that (and where it doesn't count
+ * so much). This setting shows -50 dB (actual is -50.3 dB) for register
+ * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117.
+ */
+static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
+
 static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        /* Output */
-       SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R_TLV("PCM Playback Volume",
+                        LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
 
-       SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL,
-                    DACR1_2_RLOPM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
+                        DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
        SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL,
-                    DACR1_2_LLOPM_VOL, 0, 0x7f, 1),
-       SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
-                    0, 0x7f, 1),
-       SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL,
-                    0, 0x7f, 1),
-       SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
-                    LINE2R_2_LLOPM_VOL, 0, 0x7f, 1),
-       SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL,
-                    LINE2R_2_RLOPM_VOL, 0, 0x7f, 1),
-
-       SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL,
-                    DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
+                        DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
+                      PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
+                      PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
+                        LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
+                        LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
+                        DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL,
-                    PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1),
-       SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL,
-                    LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1),
-
-       SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL,
-                    DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
+                        PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
+                        LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
+                        DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
                     0x01, 0),
-       SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL,
-                    PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
-       SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
-                    0, 0x7f, 1),
-       SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL,
-                    0, 0x7f, 1),
-       SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
-                    LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
-
-       SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL,
-                    DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
+                        PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
+                      PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
+                      PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
+                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
+                        DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
-       SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
-                    0, 0x7f, 1),
-       SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL,
-                    0, 0x7f, 1),
-       SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
-                    LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
+       SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
+                      PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
+                      PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
+                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+                        0, 118, 1, output_stage_tlv),
 
        /*
         * Note: enable Automatic input Gain Controller with care. It can
@@ -308,28 +339,13 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
 
        /* Input */
-       SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0),
+       SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
+                        0, 119, 0, adc_tlv),
        SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
 
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
-/* add non dapm controls */
-static int aic3x_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&aic3x_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -746,7 +762,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct aic3x_priv *aic3x = codec->private_data;
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -1072,6 +1088,13 @@ EXPORT_SYMBOL_GPL(aic3x_button_pressed);
 #define AIC3X_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops aic3x_dai_ops = {
+       .hw_params      = aic3x_hw_params,
+       .digital_mute   = aic3x_mute,
+       .set_sysclk     = aic3x_set_dai_sysclk,
+       .set_fmt        = aic3x_set_dai_fmt,
+};
+
 struct snd_soc_dai aic3x_dai = {
        .name = "tlv320aic3x",
        .playback = {
@@ -1086,19 +1109,14 @@ struct snd_soc_dai aic3x_dai = {
                .channels_max = 2,
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
-       .ops = {
-               .hw_params = aic3x_hw_params,
-               .digital_mute = aic3x_mute,
-               .set_sysclk = aic3x_set_dai_sysclk,
-               .set_fmt = aic3x_set_dai_fmt,
-       }
+       .ops = &aic3x_dai_ops,
 };
 EXPORT_SYMBOL_GPL(aic3x_dai);
 
 static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1108,7 +1126,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
 static int aic3x_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u8 *cache = codec->reg_cache;
@@ -1131,7 +1149,7 @@ static int aic3x_resume(struct platform_device *pdev)
  */
 static int aic3x_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct aic3x_setup_data *setup = socdev->codec_data;
        int reg, ret = 0;
 
@@ -1227,7 +1245,8 @@ static int aic3x_init(struct snd_soc_device *socdev)
        aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
        aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4);
 
-       aic3x_add_controls(codec);
+       snd_soc_add_controls(codec, aic3x_snd_controls,
+                               ARRAY_SIZE(aic3x_snd_controls));
        aic3x_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -1261,7 +1280,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = aic3x_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -1366,7 +1385,7 @@ static int aic3x_probe(struct platform_device *pdev)
        }
 
        codec->private_data = aic3x;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1392,7 +1411,7 @@ static int aic3x_probe(struct platform_device *pdev)
 static int aic3x_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* power down chip */
        if (codec->control_data)
index ea370a4f86d5a2c74d97b176d977a55947ab120e..97738e2ece042220df2c9c81b3c7d3961d32b52a 100644 (file)
@@ -42,7 +42,7 @@
  */
 static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x00, /* this register not used         */
-       0x93, /* REG_CODEC_MODE         (0x1)   */
+       0x91, /* REG_CODEC_MODE         (0x1)   */
        0xc3, /* REG_OPTION             (0x2)   */
        0x00, /* REG_UNKNOWN            (0x3)   */
        0x00, /* REG_MICBIAS_CTL        (0x4)   */
@@ -117,6 +117,13 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x00, /* REG_MISC_SET_2         (0x49)  */
 };
 
+/* codec private data */
+struct twl4030_priv {
+       unsigned int bypass_state;
+       unsigned int codec_powered;
+       unsigned int codec_muted;
+};
+
 /*
  * read twl4030 register cache
  */
@@ -125,6 +132,9 @@ static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
 {
        u8 *cache = codec->reg_cache;
 
+       if (reg >= TWL4030_CACHEREGNUM)
+               return -EIO;
+
        return cache[reg];
 }
 
@@ -151,26 +161,22 @@ static int twl4030_write(struct snd_soc_codec *codec,
        return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
 }
 
-static void twl4030_clear_codecpdz(struct snd_soc_codec *codec)
+static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
 {
+       struct twl4030_priv *twl4030 = codec->private_data;
        u8 mode;
 
-       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
-       twl4030_write(codec, TWL4030_REG_CODEC_MODE,
-               mode & ~TWL4030_CODECPDZ);
-
-       /* REVISIT: this delay is present in TI sample drivers */
-       /* but there seems to be no TRM requirement for it     */
-       udelay(10);
-}
-
-static void twl4030_set_codecpdz(struct snd_soc_codec *codec)
-{
-       u8 mode;
+       if (enable == twl4030->codec_powered)
+               return;
 
        mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
-       twl4030_write(codec, TWL4030_REG_CODEC_MODE,
-               mode | TWL4030_CODECPDZ);
+       if (enable)
+               mode |= TWL4030_CODECPDZ;
+       else
+               mode &= ~TWL4030_CODECPDZ;
+
+       twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+       twl4030->codec_powered = enable;
 
        /* REVISIT: this delay is present in TI sample drivers */
        /* but there seems to be no TRM requirement for it     */
@@ -182,7 +188,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
        int i;
 
        /* clear CODECPDZ prior to setting register defaults */
-       twl4030_clear_codecpdz(codec);
+       twl4030_codec_enable(codec, 0);
 
        /* set all audio section registers to reasonable defaults */
        for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
@@ -190,6 +196,122 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 
 }
 
+static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute)
+{
+       struct twl4030_priv *twl4030 = codec->private_data;
+       u8 reg_val;
+
+       if (mute == twl4030->codec_muted)
+               return;
+
+       if (mute) {
+               /* Bypass the reg_cache and mute the volumes
+                * Headset mute is done in it's own event handler
+                * Things to mute:  Earpiece, PreDrivL/R, CarkitL/R
+                */
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL);
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       reg_val & (~TWL4030_EAR_GAIN),
+                                       TWL4030_REG_EAR_CTL);
+
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL);
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       reg_val & (~TWL4030_PREDL_GAIN),
+                                       TWL4030_REG_PREDL_CTL);
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL);
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       reg_val & (~TWL4030_PREDR_GAIN),
+                                       TWL4030_REG_PREDL_CTL);
+
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL);
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       reg_val & (~TWL4030_PRECKL_GAIN),
+                                       TWL4030_REG_PRECKL_CTL);
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL);
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       reg_val & (~TWL4030_PRECKL_GAIN),
+                                       TWL4030_REG_PRECKR_CTL);
+
+               /* Disable PLL */
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
+               reg_val &= ~TWL4030_APLL_EN;
+               twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
+       } else {
+               /* Restore the volumes
+                * Headset mute is done in it's own event handler
+                * Things to restore:  Earpiece, PreDrivL/R, CarkitL/R
+                */
+               twl4030_write(codec, TWL4030_REG_EAR_CTL,
+                       twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL));
+
+               twl4030_write(codec, TWL4030_REG_PREDL_CTL,
+                       twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL));
+               twl4030_write(codec, TWL4030_REG_PREDR_CTL,
+                       twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL));
+
+               twl4030_write(codec, TWL4030_REG_PRECKL_CTL,
+                       twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL));
+               twl4030_write(codec, TWL4030_REG_PRECKR_CTL,
+                       twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL));
+
+               /* Enable PLL */
+               reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
+               reg_val |= TWL4030_APLL_EN;
+               twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
+       }
+
+       twl4030->codec_muted = mute;
+}
+
+static void twl4030_power_up(struct snd_soc_codec *codec)
+{
+       struct twl4030_priv *twl4030 = codec->private_data;
+       u8 anamicl, regmisc1, byte;
+       int i = 0;
+
+       if (twl4030->codec_powered)
+               return;
+
+       /* set CODECPDZ to turn on codec */
+       twl4030_codec_enable(codec, 1);
+
+       /* initiate offset cancellation */
+       anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+       twl4030_write(codec, TWL4030_REG_ANAMICL,
+               anamicl | TWL4030_CNCL_OFFSET_START);
+
+       /* wait for offset cancellation to complete */
+       do {
+               /* this takes a little while, so don't slam i2c */
+               udelay(2000);
+               twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+                                   TWL4030_REG_ANAMICL);
+       } while ((i++ < 100) &&
+                ((byte & TWL4030_CNCL_OFFSET_START) ==
+                 TWL4030_CNCL_OFFSET_START));
+
+       /* Make sure that the reg_cache has the same value as the HW */
+       twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
+
+       /* anti-pop when changing analog gain */
+       regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+       twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+               regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
+
+       /* toggle CODECPDZ as per TRM */
+       twl4030_codec_enable(codec, 0);
+       twl4030_codec_enable(codec, 1);
+}
+
+/*
+ * Unconditional power down
+ */
+static void twl4030_power_down(struct snd_soc_codec *codec)
+{
+       /* power down */
+       twl4030_codec_enable(codec, 0);
+}
+
 /* Earpiece */
 static const char *twl4030_earpiece_texts[] =
                {"Off", "DACL1", "DACL2", "DACR1"};
@@ -366,6 +488,41 @@ static const struct soc_enum twl4030_micpathtx2_enum =
 static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
 SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
 
+/* Analog bypass for AudioR1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr1_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl1_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioR2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR2_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);
+
+/* Digital bypass gain, 0 mutes the bypass */
+static const unsigned int twl4030_dapm_dbypass_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1),
+       4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
+};
+
+/* Digital bypass left (TX1L -> RX2L) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control =
+       SOC_DAPM_SINGLE_TLV("Volume",
+                       TWL4030_REG_ATX2ARXPGA, 3, 7, 0,
+                       twl4030_dapm_dbypass_tlv);
+
+/* Digital bypass right (TX1R -> RX2R) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control =
+       SOC_DAPM_SINGLE_TLV("Volume",
+                       TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
+                       twl4030_dapm_dbypass_tlv);
+
 static int micpath_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
@@ -420,6 +577,79 @@ static int handsfree_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int headsetl_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       unsigned char hs_gain, hs_pop;
+
+       /* Save the current volume */
+       hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
+       hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Do the anti-pop/bias ramp enable according to the TRM */
+               hs_pop |= TWL4030_VMID_EN;
+               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               /* Is this needed? Can we just use whatever gain here? */
+               twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET,
+                               (hs_gain & (~0x0f)) | 0x0a);
+               hs_pop |= TWL4030_RAMP_EN;
+               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+
+               /* Restore the original volume */
+               twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Do the anti-pop/bias ramp disable according to the TRM */
+               hs_pop &= ~TWL4030_RAMP_EN;
+               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               /* Bypass the reg_cache to mute the headset */
+               twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+                                       hs_gain & (~0x0f),
+                                       TWL4030_REG_HS_GAIN_SET);
+               hs_pop &= ~TWL4030_VMID_EN;
+               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               break;
+       }
+       return 0;
+}
+
+static int bypass_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct soc_mixer_control *m =
+               (struct soc_mixer_control *)w->kcontrols->private_value;
+       struct twl4030_priv *twl4030 = w->codec->private_data;
+       unsigned char reg;
+
+       reg = twl4030_read_reg_cache(w->codec, m->reg);
+
+       if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
+               /* Analog bypass */
+               if (reg & (1 << m->shift))
+                       twl4030->bypass_state |=
+                               (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
+               else
+                       twl4030->bypass_state &=
+                               ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
+       } else {
+               /* Digital bypass */
+               if (reg & (0x7 << m->shift))
+                       twl4030->bypass_state |= (1 << (m->shift ? 5 : 4));
+               else
+                       twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4));
+       }
+
+       if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
+               if (twl4030->bypass_state)
+                       twl4030_codec_mute(w->codec, 0);
+               else
+                       twl4030_codec_mute(w->codec, 1);
+       }
+       return 0;
+}
+
 /*
  * Some of the gain controls in TWL (mostly those which are associated with
  * the outputs) are implemented in an interesting way:
@@ -614,6 +844,17 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
  */
 static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
 
+static const char *twl4030_rampdelay_texts[] = {
+       "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
+       "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
+       "3495/2581/1748 ms"
+};
+
+static const struct soc_enum twl4030_rampdelay_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2,
+                       ARRAY_SIZE(twl4030_rampdelay_texts),
+                       twl4030_rampdelay_texts);
+
 static const struct snd_kcontrol_new twl4030_snd_controls[] = {
        /* Common playback gain controls */
        SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
@@ -668,23 +909,9 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
 
        SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
                0, 3, 5, 0, input_gain_tlv),
-};
-
-/* add non dapm controls */
-static int twl4030_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&twl4030_snd_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
 
-       return 0;
-}
+       SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
+};
 
 static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        /* Left channel inputs */
@@ -714,13 +941,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
 
        /* DACs */
        SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback",
-                       TWL4030_REG_AVDAC_CTL, 0, 0),
+                       SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback",
-                       TWL4030_REG_AVDAC_CTL, 1, 0),
+                       SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback",
-                       TWL4030_REG_AVDAC_CTL, 2, 0),
+                       SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback",
-                       TWL4030_REG_AVDAC_CTL, 3, 0),
+                       SND_SOC_NOPM, 0, 0),
 
        /* Analog PGAs */
        SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL,
@@ -732,6 +959,37 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL,
                        0, 0, NULL, 0),
 
+       /* Analog bypasses */
+       SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassr1_control, bypass_event,
+                       SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassl1_control,
+                       bypass_event, SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassr2_control,
+                       bypass_event, SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_abypassl2_control,
+                       bypass_event, SND_SOC_DAPM_POST_REG),
+
+       /* Digital bypasses */
+       SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_dbypassl_control, bypass_event,
+                       SND_SOC_DAPM_POST_REG),
+       SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_dbypassr_control, bypass_event,
+                       SND_SOC_DAPM_POST_REG),
+
+       SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+                       0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+                       1, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+                       2, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+                       3, 0, NULL, 0),
+
        /* Output MUX controls */
        /* Earpiece */
        SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0,
@@ -742,8 +1000,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0,
                &twl4030_dapm_predriver_control),
        /* HeadsetL/R */
-       SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_hsol_control),
+       SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
+               &twl4030_dapm_hsol_control, headsetl_event,
+               SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0,
                &twl4030_dapm_hsor_control),
        /* CarkitL/R */
@@ -782,16 +1041,16 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
                SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
                SND_SOC_DAPM_POST_REG),
 
-       /* Analog input muxes with power switch for the physical ADCL/R */
+       /* Analog input muxes with switch for the capture amplifiers */
        SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route",
-               TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control),
+               TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control),
        SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route",
-               TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control),
+               TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control),
 
-       SND_SOC_DAPM_PGA("Analog Left Amplifier",
-               TWL4030_REG_ANAMICL, 4, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Analog Right Amplifier",
-               TWL4030_REG_ANAMICR, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ADC Physical Left",
+               TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ADC Physical Right",
+               TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0),
 
        SND_SOC_DAPM_PGA("Digimic0 Enable",
                TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0),
@@ -801,13 +1060,19 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
        SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
        SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0),
+
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
-       {"ARXL1_APGA", NULL, "DAC Left1"},
-       {"ARXR1_APGA", NULL, "DAC Right1"},
-       {"ARXL2_APGA", NULL, "DAC Left2"},
-       {"ARXR2_APGA", NULL, "DAC Right2"},
+       {"Analog L1 Playback Mixer", NULL, "DAC Left1"},
+       {"Analog R1 Playback Mixer", NULL, "DAC Right1"},
+       {"Analog L2 Playback Mixer", NULL, "DAC Left2"},
+       {"Analog R2 Playback Mixer", NULL, "DAC Right2"},
+
+       {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"},
+       {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"},
+       {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"},
+       {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"},
 
        /* Internal playback routings */
        /* Earpiece */
@@ -865,23 +1130,23 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Analog Right Capture Route", "Sub mic", "SUBMIC"},
        {"Analog Right Capture Route", "AUXR", "AUXR"},
 
-       {"Analog Left Amplifier", NULL, "Analog Left Capture Route"},
-       {"Analog Right Amplifier", NULL, "Analog Right Capture Route"},
+       {"ADC Physical Left", NULL, "Analog Left Capture Route"},
+       {"ADC Physical Right", NULL, "Analog Right Capture Route"},
 
        {"Digimic0 Enable", NULL, "DIGIMIC0"},
        {"Digimic1 Enable", NULL, "DIGIMIC1"},
 
        /* TX1 Left capture path */
-       {"TX1 Capture Route", "Analog", "Analog Left Amplifier"},
+       {"TX1 Capture Route", "Analog", "ADC Physical Left"},
        {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
        /* TX1 Right capture path */
-       {"TX1 Capture Route", "Analog", "Analog Right Amplifier"},
+       {"TX1 Capture Route", "Analog", "ADC Physical Right"},
        {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
        /* TX2 Left capture path */
-       {"TX2 Capture Route", "Analog", "Analog Left Amplifier"},
+       {"TX2 Capture Route", "Analog", "ADC Physical Left"},
        {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
        /* TX2 Right capture path */
-       {"TX2 Capture Route", "Analog", "Analog Right Amplifier"},
+       {"TX2 Capture Route", "Analog", "ADC Physical Right"},
        {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
 
        {"ADC Virtual Left1", NULL, "TX1 Capture Route"},
@@ -889,6 +1154,24 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ADC Virtual Left2", NULL, "TX2 Capture Route"},
        {"ADC Virtual Right2", NULL, "TX2 Capture Route"},
 
+       /* Analog bypass routes */
+       {"Right1 Analog Loopback", "Switch", "Analog Right Capture Route"},
+       {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"},
+       {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"},
+       {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"},
+
+       {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
+       {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
+       {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
+       {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},
+
+       /* Digital bypass routes */
+       {"Right Digital Loopback", "Volume", "TX1 Capture Route"},
+       {"Left Digital Loopback", "Volume", "TX1 Capture Route"},
+
+       {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"},
+       {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"},
+
 };
 
 static int twl4030_add_widgets(struct snd_soc_codec *codec)
@@ -902,82 +1185,28 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec)
        return 0;
 }
 
-static void twl4030_power_up(struct snd_soc_codec *codec)
-{
-       u8 anamicl, regmisc1, byte, popn;
-       int i = 0;
-
-       /* set CODECPDZ to turn on codec */
-       twl4030_set_codecpdz(codec);
-
-       /* initiate offset cancellation */
-       anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
-       twl4030_write(codec, TWL4030_REG_ANAMICL,
-               anamicl | TWL4030_CNCL_OFFSET_START);
-
-
-       /* wait for offset cancellation to complete */
-       do {
-               /* this takes a little while, so don't slam i2c */
-               udelay(2000);
-               twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
-                                   TWL4030_REG_ANAMICL);
-       } while ((i++ < 100) &&
-                ((byte & TWL4030_CNCL_OFFSET_START) ==
-                 TWL4030_CNCL_OFFSET_START));
-
-       /* anti-pop when changing analog gain */
-       regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
-       twl4030_write(codec, TWL4030_REG_MISC_SET_1,
-               regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
-
-       /* toggle CODECPDZ as per TRM */
-       twl4030_clear_codecpdz(codec);
-       twl4030_set_codecpdz(codec);
-
-       /* program anti-pop with bias ramp delay */
-       popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
-       popn &= TWL4030_RAMP_DELAY;
-       popn |= TWL4030_RAMP_DELAY_645MS;
-       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-       popn |= TWL4030_VMID_EN;
-       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
-       /* enable anti-pop ramp */
-       popn |= TWL4030_RAMP_EN;
-       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-}
-
-static void twl4030_power_down(struct snd_soc_codec *codec)
-{
-       u8 popn;
-
-       /* disable anti-pop ramp */
-       popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
-       popn &= ~TWL4030_RAMP_EN;
-       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
-       /* disable bias out */
-       popn &= ~TWL4030_VMID_EN;
-       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
-       /* power down */
-       twl4030_clear_codecpdz(codec);
-}
-
 static int twl4030_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
+       struct twl4030_priv *twl4030 = codec->private_data;
+
        switch (level) {
        case SND_SOC_BIAS_ON:
-               twl4030_power_up(codec);
+               twl4030_codec_mute(codec, 0);
                break;
        case SND_SOC_BIAS_PREPARE:
-               /* TODO: develop a twl4030_prepare function */
+               twl4030_power_up(codec);
+               if (twl4030->bypass_state)
+                       twl4030_codec_mute(codec, 0);
+               else
+                       twl4030_codec_mute(codec, 1);
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* TODO: develop a twl4030_standby function */
-               twl4030_power_down(codec);
+               twl4030_power_up(codec);
+               if (twl4030->bypass_state)
+                       twl4030_codec_mute(codec, 0);
+               else
+                       twl4030_codec_mute(codec, 1);
                break;
        case SND_SOC_BIAS_OFF:
                twl4030_power_down(codec);
@@ -994,10 +1223,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u8 mode, old_mode, format, old_format;
 
-
        /* bit rate */
        old_mode = twl4030_read_reg_cache(codec,
                        TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
@@ -1039,8 +1267,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 
        if (mode != old_mode) {
                /* change rate and set CODECPDZ */
+               twl4030_codec_enable(codec, 0);
                twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
-               twl4030_set_codecpdz(codec);
+               twl4030_codec_enable(codec, 1);
        }
 
        /* sample size */
@@ -1063,13 +1292,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        if (format != old_format) {
 
                /* clear CODECPDZ before changing format (codec requirement) */
-               twl4030_clear_codecpdz(codec);
+               twl4030_codec_enable(codec, 0);
 
                /* change format */
                twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
 
                /* set CODECPDZ afterwards */
-               twl4030_set_codecpdz(codec);
+               twl4030_codec_enable(codec, 1);
        }
        return 0;
 }
@@ -1139,13 +1368,13 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
        if (format != old_format) {
 
                /* clear CODECPDZ before changing format (codec requirement) */
-               twl4030_clear_codecpdz(codec);
+               twl4030_codec_enable(codec, 0);
 
                /* change format */
                twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
 
                /* set CODECPDZ afterwards */
-               twl4030_set_codecpdz(codec);
+               twl4030_codec_enable(codec, 1);
        }
 
        return 0;
@@ -1154,6 +1383,12 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
 #define TWL4030_RATES   (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
 
+static struct snd_soc_dai_ops twl4030_dai_ops = {
+       .hw_params      = twl4030_hw_params,
+       .set_sysclk     = twl4030_set_dai_sysclk,
+       .set_fmt        = twl4030_set_dai_fmt,
+};
+
 struct snd_soc_dai twl4030_dai = {
        .name = "twl4030",
        .playback = {
@@ -1168,18 +1403,14 @@ struct snd_soc_dai twl4030_dai = {
                .channels_max = 2,
                .rates = TWL4030_RATES,
                .formats = TWL4030_FORMATS,},
-       .ops = {
-               .hw_params = twl4030_hw_params,
-               .set_sysclk = twl4030_set_dai_sysclk,
-               .set_fmt = twl4030_set_dai_fmt,
-       }
+       .ops = &twl4030_dai_ops,
 };
 EXPORT_SYMBOL_GPL(twl4030_dai);
 
 static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1189,7 +1420,7 @@ static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
 static int twl4030_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        twl4030_set_bias_level(codec, codec->suspend_bias_level);
@@ -1203,7 +1434,7 @@ static int twl4030_resume(struct platform_device *pdev)
 
 static int twl4030_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        printk(KERN_INFO "TWL4030 Audio Codec init \n");
@@ -1233,7 +1464,8 @@ static int twl4030_init(struct snd_soc_device *socdev)
        /* power on device */
        twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       twl4030_add_controls(codec);
+       snd_soc_add_controls(codec, twl4030_snd_controls,
+                               ARRAY_SIZE(twl4030_snd_controls));
        twl4030_add_widgets(codec);
 
        ret = snd_soc_init_card(socdev);
@@ -1258,12 +1490,20 @@ static int twl4030_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec;
+       struct twl4030_priv *twl4030;
 
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
        if (codec == NULL)
                return -ENOMEM;
 
-       socdev->codec = codec;
+       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+       if (twl4030 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = twl4030;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1277,11 +1517,13 @@ static int twl4030_probe(struct platform_device *pdev)
 static int twl4030_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        printk(KERN_INFO "TWL4030 Audio Codec remove\n");
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
+       kfree(codec->private_data);
        kfree(codec);
 
        return 0;
index 442e5a82861736d71ac801ffcbcc57ca7560ef15..33dbb144dad1d8a4858726949691008a63c589a3 100644 (file)
 #define TWL4030_CLK256FS_EN            0x02
 #define TWL4030_AIF_EN                 0x01
 
+/* EAR_CTL (0x21) */
+#define TWL4030_EAR_GAIN               0x30
+
 /* HS_GAIN_SET (0x23) Fields */
 
 #define TWL4030_HSR_GAIN               0x0C
 #define TWL4030_RAMP_DELAY_2581MS      0x1C
 #define TWL4030_RAMP_EN                        0x02
 
+/* PREDL_CTL (0x25) */
+#define TWL4030_PREDL_GAIN             0x30
+
+/* PREDR_CTL (0x26) */
+#define TWL4030_PREDR_GAIN             0x30
+
+/* PRECKL_CTL (0x27) */
+#define TWL4030_PRECKL_GAIN            0x30
+
+/* PRECKR_CTL (0x28) */
+#define TWL4030_PRECKR_GAIN            0x30
+
 /* HFL_CTL (0x29, 0x2A) Fields */
 #define TWL4030_HF_CTL_HB_EN           0x04
 #define TWL4030_HF_CTL_LOOP_EN         0x08
index a2c5064a774b12b1f65d16e92f88366f9facc26e..ddefb8f80145bb1830253cde7277f3bf6ae50818 100644 (file)
@@ -173,7 +173,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct uda134x_priv *uda134x = codec->private_data;
        struct snd_pcm_runtime *master_runtime;
 
@@ -206,7 +206,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct uda134x_priv *uda134x = codec->private_data;
 
        if (uda134x->master_substream == substream)
@@ -221,7 +221,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct uda134x_priv *uda134x = codec->private_data;
        u8 hw_params;
 
@@ -431,38 +431,14 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
 };
 
-static int uda134x_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i, n;
-       const struct snd_kcontrol_new *ctrls;
-       struct uda134x_platform_data *pd = codec->control_data;
-
-       switch (pd->model) {
-       case UDA134X_UDA1340:
-       case UDA134X_UDA1344:
-               n = ARRAY_SIZE(uda1340_snd_controls);
-               ctrls = uda1340_snd_controls;
-               break;
-       case UDA134X_UDA1341:
-               n = ARRAY_SIZE(uda1341_snd_controls);
-               ctrls = uda1341_snd_controls;
-               break;
-       default:
-               printk(KERN_ERR "%s unkown codec type: %d",
-                      __func__, pd->model);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < n; i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&ctrls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
+static struct snd_soc_dai_ops uda134x_dai_ops = {
+       .startup        = uda134x_startup,
+       .shutdown       = uda134x_shutdown,
+       .hw_params      = uda134x_hw_params,
+       .digital_mute   = uda134x_mute,
+       .set_sysclk     = uda134x_set_dai_sysclk,
+       .set_fmt        = uda134x_set_dai_fmt,
+};
 
 struct snd_soc_dai uda134x_dai = {
        .name = "UDA134X",
@@ -483,14 +459,7 @@ struct snd_soc_dai uda134x_dai = {
                .formats = UDA134X_FORMATS,
        },
        /* pcm operations */
-       .ops = {
-               .startup = uda134x_startup,
-               .shutdown = uda134x_shutdown,
-               .hw_params = uda134x_hw_params,
-               .digital_mute = uda134x_mute,
-               .set_sysclk = uda134x_set_dai_sysclk,
-               .set_fmt = uda134x_set_dai_fmt,
-       }
+       .ops = &uda134x_dai_ops,
 };
 EXPORT_SYMBOL(uda134x_dai);
 
@@ -525,11 +494,11 @@ static int uda134x_soc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->codec == NULL)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (socdev->card->codec == NULL)
                return ret;
 
-       codec = socdev->codec;
+       codec = socdev->card->codec;
 
        uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
        if (uda134x == NULL)
@@ -572,7 +541,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       ret = uda134x_add_controls(codec);
+       switch (pd->model) {
+       case UDA134X_UDA1340:
+       case UDA134X_UDA1344:
+               ret = snd_soc_add_controls(codec, uda1340_snd_controls,
+                                       ARRAY_SIZE(uda1340_snd_controls));
+       break;
+       case UDA134X_UDA1341:
+               ret = snd_soc_add_controls(codec, uda1341_snd_controls,
+                                       ARRAY_SIZE(uda1341_snd_controls));
+       break;
+       default:
+               printk(KERN_ERR "%s unkown codec type: %d",
+                       __func__, pd->model);
+       return -EINVAL;
+       }
+
        if (ret < 0) {
                printk(KERN_ERR "UDA134X: failed to register controls\n");
                goto pcm_err;
@@ -602,7 +586,7 @@ priv_err:
 static int uda134x_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -622,7 +606,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev,
                                                pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -632,7 +616,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev,
 static int uda134x_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
index e6bf0844fbf3e4dd770b293bf01673f1be78c86d..5b21594e0e58283ee30d3ee6ea209d8636929aef 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/ioctl.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
@@ -35,7 +36,8 @@
 
 #include "uda1380.h"
 
-#define UDA1380_VERSION "0.6"
+static struct work_struct uda1380_work;
+static struct snd_soc_codec *uda1380_codec;
 
 /*
  * uda1380 register cache
@@ -52,6 +54,8 @@ static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = {
        0x0000, 0x8000, 0x0002, 0x0000,
 };
 
+static unsigned long uda1380_cache_dirty;
+
 /*
  * read uda1380 register cache
  */
@@ -73,8 +77,11 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
        u16 reg, unsigned int value)
 {
        u16 *cache = codec->reg_cache;
+
        if (reg >= UDA1380_CACHEREGNUM)
                return;
+       if ((reg >= 0x10) && (cache[reg] != value))
+               set_bit(reg - 0x10, &uda1380_cache_dirty);
        cache[reg] = value;
 }
 
@@ -113,6 +120,8 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
                                        (data[0]<<8) | data[1]);
                        return -EIO;
                }
+               if (reg >= 0x10)
+                       clear_bit(reg - 0x10, &uda1380_cache_dirty);
                return 0;
        } else
                return -EIO;
@@ -120,6 +129,20 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
 
 #define uda1380_reset(c)       uda1380_write(c, UDA1380_RESET, 0)
 
+static void uda1380_flush_work(struct work_struct *work)
+{
+       int bit, reg;
+
+       for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
+               reg = 0x10 + bit;
+               pr_debug("uda1380: flush reg %x val %x:\n", reg,
+                               uda1380_read_reg_cache(uda1380_codec, reg));
+               uda1380_write(uda1380_codec, reg,
+                               uda1380_read_reg_cache(uda1380_codec, reg));
+               clear_bit(bit, &uda1380_cache_dirty);
+       }
+}
+
 /* declarations of ALSA reg_elem_REAL controls */
 static const char *uda1380_deemp[] = {
        "None",
@@ -254,7 +277,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = {
        SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0),   /* DA_POL_INV */
        SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum),                          /* SEL_NS */
        SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum),             /* MIX_POS, MIX */
-       SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0),                   /* SILENCE, force DAC output to silence */
        SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0),          /* SDET_ON */
        SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum),                /* SD_VALUE */
        SOC_ENUM("Oversampling Input", uda1380_os_enum),                        /* OS */
@@ -271,21 +293,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = {
        SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0),
 };
 
-/* add non dapm controls */
-static int uda1380_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Input mux */
 static const struct snd_kcontrol_new uda1380_input_mux_control =
        SOC_DAPM_ENUM("Route", uda1380_input_sel_enum);
@@ -371,7 +378,7 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -381,61 +388,107 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai,
        iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
        iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
 
-       /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                iface |= R01_SFORI_I2S | R01_SFORO_I2S;
                break;
        case SND_SOC_DAIFMT_LSB:
-               iface |= R01_SFORI_LSB16 | R01_SFORO_I2S;
+               iface |= R01_SFORI_LSB16 | R01_SFORO_LSB16;
                break;
        case SND_SOC_DAIFMT_MSB:
-               iface |= R01_SFORI_MSB | R01_SFORO_I2S;
+               iface |= R01_SFORI_MSB | R01_SFORO_MSB;
        }
 
-       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
-               iface |= R01_SIM;
+       /* DATAI is slave only, so in single-link mode, this has to be slave */
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+               return -EINVAL;
 
        uda1380_write(codec, UDA1380_IFACE, iface);
 
        return 0;
 }
 
-/*
- * Flush reg cache
- * We can only write the interpolator and decimator registers
- * when the DAI is being clocked by the CPU DAI. It's up to the
- * machine and cpu DAI driver to do this before we are called.
- */
-static int uda1380_pcm_prepare(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
+static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int reg, reg_start, reg_end, clk;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               reg_start = UDA1380_MVOL;
-               reg_end = UDA1380_MIXER;
-       } else {
-               reg_start = UDA1380_DEC;
-               reg_end = UDA1380_AGC;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int iface;
+
+       /* set up DAI based upon fmt */
+       iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+       iface &= ~R01_SFORI_MASK;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= R01_SFORI_I2S;
+               break;
+       case SND_SOC_DAIFMT_LSB:
+               iface |= R01_SFORI_LSB16;
+               break;
+       case SND_SOC_DAIFMT_MSB:
+               iface |= R01_SFORI_MSB;
        }
 
-       /* FIXME disable DAC_CLK */
-       clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
-       uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK);
+       /* DATAI is slave only, so this has to be slave */
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+               return -EINVAL;
+
+       uda1380_write(codec, UDA1380_IFACE, iface);
+
+       return 0;
+}
+
+static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int iface;
+
+       /* set up DAI based upon fmt */
+       iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+       iface &= ~(R01_SIM | R01_SFORO_MASK);
 
-       for (reg = reg_start; reg <= reg_end; reg++) {
-               pr_debug("uda1380: flush reg %x val %x:", reg,
-                               uda1380_read_reg_cache(codec, reg));
-               uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg));
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= R01_SFORO_I2S;
+               break;
+       case SND_SOC_DAIFMT_LSB:
+               iface |= R01_SFORO_LSB16;
+               break;
+       case SND_SOC_DAIFMT_MSB:
+               iface |= R01_SFORO_MSB;
        }
 
-       /* FIXME enable DAC_CLK */
-       uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK);
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
+               iface |= R01_SIM;
 
+       uda1380_write(codec, UDA1380_IFACE, iface);
+
+       return 0;
+}
+
+static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
+               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               uda1380_write_reg_cache(codec, UDA1380_MIXER,
+                                       mixer & ~R14_SILENCE);
+               schedule_work(&uda1380_work);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               uda1380_write_reg_cache(codec, UDA1380_MIXER,
+                                       mixer | R14_SILENCE);
+               schedule_work(&uda1380_work);
+               break;
+       }
        return 0;
 }
 
@@ -445,7 +498,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* set WSPLL power and divider if running from this clock */
@@ -484,7 +537,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* shut down WSPLL power if running from this clock */
@@ -501,24 +554,6 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
        uda1380_write(codec, UDA1380_CLK, clk);
 }
 
-static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute)
-{
-       struct snd_soc_codec *codec = codec_dai->codec;
-       u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM;
-
-       /* FIXME: mute(codec,0) is called when the magician clock is already
-        * set to WSPLL, but for some unknown reason writing to interpolator
-        * registers works only when clocked by SYSCLK */
-       u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
-       uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk);
-       if (mute)
-               uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM);
-       else
-               uda1380_write(codec, UDA1380_DEEMP, mute_reg);
-       uda1380_write(codec, UDA1380_CLK, clk);
-       return 0;
-}
-
 static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
@@ -544,6 +579,27 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops uda1380_dai_ops = {
+       .hw_params      = uda1380_pcm_hw_params,
+       .shutdown       = uda1380_pcm_shutdown,
+       .trigger        = uda1380_trigger,
+       .set_fmt        = uda1380_set_dai_fmt_both,
+};
+
+static struct snd_soc_dai_ops uda1380_dai_ops_playback = {
+       .hw_params      = uda1380_pcm_hw_params,
+       .shutdown       = uda1380_pcm_shutdown,
+       .trigger        = uda1380_trigger,
+       .set_fmt        = uda1380_set_dai_fmt_playback,
+};
+
+static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
+       .hw_params      = uda1380_pcm_hw_params,
+       .shutdown       = uda1380_pcm_shutdown,
+       .trigger        = uda1380_trigger,
+       .set_fmt        = uda1380_set_dai_fmt_capture,
+};
+
 struct snd_soc_dai uda1380_dai[] = {
 {
        .name = "UDA1380",
@@ -559,13 +615,7 @@ struct snd_soc_dai uda1380_dai[] = {
                .channels_max = 2,
                .rates = UDA1380_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = uda1380_pcm_hw_params,
-               .shutdown = uda1380_pcm_shutdown,
-               .prepare = uda1380_pcm_prepare,
-               .digital_mute = uda1380_mute,
-               .set_fmt = uda1380_set_dai_fmt,
-       },
+       .ops = &uda1380_dai_ops,
 },
 { /* playback only - dual interface */
        .name = "UDA1380",
@@ -576,13 +626,7 @@ struct snd_soc_dai uda1380_dai[] = {
                .rates = UDA1380_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .ops = {
-               .hw_params = uda1380_pcm_hw_params,
-               .shutdown = uda1380_pcm_shutdown,
-               .prepare = uda1380_pcm_prepare,
-               .digital_mute = uda1380_mute,
-               .set_fmt = uda1380_set_dai_fmt,
-       },
+       .ops = &uda1380_dai_ops_playback,
 },
 { /* capture only - dual interface*/
        .name = "UDA1380",
@@ -593,12 +637,7 @@ struct snd_soc_dai uda1380_dai[] = {
                .rates = UDA1380_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .ops = {
-               .hw_params = uda1380_pcm_hw_params,
-               .shutdown = uda1380_pcm_shutdown,
-               .prepare = uda1380_pcm_prepare,
-               .set_fmt = uda1380_set_dai_fmt,
-       },
+       .ops = &uda1380_dai_ops_capture,
 },
 };
 EXPORT_SYMBOL_GPL(uda1380_dai);
@@ -606,7 +645,7 @@ EXPORT_SYMBOL_GPL(uda1380_dai);
 static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -615,7 +654,7 @@ static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
 static int uda1380_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -637,7 +676,7 @@ static int uda1380_resume(struct platform_device *pdev)
  */
 static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        codec->name = "UDA1380";
@@ -655,6 +694,9 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
        codec->reg_cache_step = 1;
        uda1380_reset(codec);
 
+       uda1380_codec = codec;
+       INIT_WORK(&uda1380_work, uda1380_flush_work);
+
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
@@ -675,7 +717,8 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
        }
 
        /* uda1380 init */
-       uda1380_add_controls(codec);
+       snd_soc_add_controls(codec, uda1380_snd_controls,
+                               ARRAY_SIZE(uda1380_snd_controls));
        uda1380_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -702,7 +745,7 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
 {
        struct snd_soc_device *socdev = uda1380_socdev;
        struct uda1380_setup_data *setup = socdev->codec_data;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -786,14 +829,12 @@ static int uda1380_probe(struct platform_device *pdev)
        struct snd_soc_codec *codec;
        int ret;
 
-       pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
-
        setup = socdev->codec_data;
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
        if (codec == NULL)
                return -ENOMEM;
 
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -817,7 +858,7 @@ static int uda1380_probe(struct platform_device *pdev)
 static int uda1380_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
index 35d99750c383cd48a17603e290d5dce70b7064c7..3b1d0993bed947fa815c559b0cd8db1aa144f24f 100644 (file)
@@ -51,10 +51,17 @@ struct wm8350_output {
        u16 mute;
 };
 
+struct wm8350_jack_data {
+       struct snd_soc_jack *jack;
+       int report;
+};
+
 struct wm8350_data {
        struct snd_soc_codec codec;
        struct wm8350_output out1;
        struct wm8350_output out2;
+       struct wm8350_jack_data hpl;
+       struct wm8350_jack_data hpr;
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
@@ -775,21 +782,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Beep", NULL, "IN3R PGA"},
 };
 
-static int wm8350_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8350_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 static int wm8350_add_widgets(struct snd_soc_codec *codec)
 {
        int ret;
@@ -1309,7 +1301,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
 static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1318,7 +1310,7 @@ static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8350_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1328,6 +1320,95 @@ static int wm8350_resume(struct platform_device *pdev)
        return 0;
 }
 
+static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+       struct wm8350_data *priv = data;
+       u16 reg;
+       int report;
+       int mask;
+       struct wm8350_jack_data *jack = NULL;
+
+       switch (irq) {
+       case WM8350_IRQ_CODEC_JCK_DET_L:
+               jack = &priv->hpl;
+               mask = WM8350_JACK_L_LVL;
+               break;
+
+       case WM8350_IRQ_CODEC_JCK_DET_R:
+               jack = &priv->hpr;
+               mask = WM8350_JACK_R_LVL;
+               break;
+
+       default:
+               BUG();
+       }
+
+       if (!jack->jack) {
+               dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
+               return;
+       }
+
+       /* Debounce */
+       msleep(200);
+
+       reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
+       if (reg & mask)
+               report = jack->report;
+       else
+               report = 0;
+
+       snd_soc_jack_report(jack->jack, report, jack->report);
+}
+
+/**
+ * wm8350_hp_jack_detect - Enable headphone jack detection.
+ *
+ * @codec:  WM8350 codec
+ * @which:  left or right jack detect signal
+ * @jack:   jack to report detection events on
+ * @report: value to report
+ *
+ * Enables the headphone jack detection of the WM8350.
+ */
+int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+                         struct snd_soc_jack *jack, int report)
+{
+       struct wm8350_data *priv = codec->private_data;
+       struct wm8350 *wm8350 = codec->control_data;
+       int irq;
+       int ena;
+
+       switch (which) {
+       case WM8350_JDL:
+               priv->hpl.jack = jack;
+               priv->hpl.report = report;
+               irq = WM8350_IRQ_CODEC_JCK_DET_L;
+               ena = WM8350_JDL_ENA;
+               break;
+
+       case WM8350_JDR:
+               priv->hpr.jack = jack;
+               priv->hpr.report = report;
+               irq = WM8350_IRQ_CODEC_JCK_DET_R;
+               ena = WM8350_JDR_ENA;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+       wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
+
+       /* Sync status */
+       wm8350_hp_jack_handler(wm8350, irq, priv);
+
+       wm8350_unmask_irq(wm8350, irq);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect);
+
 static struct snd_soc_codec *wm8350_codec;
 
 static int wm8350_probe(struct platform_device *pdev)
@@ -1342,8 +1423,8 @@ static int wm8350_probe(struct platform_device *pdev)
 
        BUG_ON(!wm8350_codec);
 
-       socdev->codec = wm8350_codec;
-       codec = socdev->codec;
+       socdev->card->codec = wm8350_codec;
+       codec = socdev->card->codec;
        wm8350 = codec->control_data;
        priv = codec->private_data;
 
@@ -1381,13 +1462,21 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
                        WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
 
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
+                           wm8350_hp_jack_handler, priv);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
+                           wm8350_hp_jack_handler, priv);
+
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to create pcms\n");
                return ret;
        }
 
-       wm8350_add_controls(codec);
+       snd_soc_add_controls(codec, wm8350_snd_controls,
+                               ARRAY_SIZE(wm8350_snd_controls));
        wm8350_add_widgets(codec);
 
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1409,10 +1498,23 @@ card_err:
 static int wm8350_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350_data *priv = codec->private_data;
        int ret;
 
+       wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
+                         WM8350_JDL_ENA | WM8350_JDR_ENA);
+       wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+
+       priv->hpl.jack = NULL;
+       priv->hpr.jack = NULL;
+
        /* cancel any work waiting to be queued. */
        ret = cancel_delayed_work(&codec->delayed_work);
 
@@ -1436,6 +1538,16 @@ static int wm8350_remove(struct platform_device *pdev)
                        SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+        .hw_params     = wm8350_pcm_hw_params,
+        .digital_mute  = wm8350_mute,
+        .trigger       = wm8350_pcm_trigger,
+        .set_fmt       = wm8350_set_dai_fmt,
+        .set_sysclk    = wm8350_set_dai_sysclk,
+        .set_pll       = wm8350_set_fll,
+        .set_clkdiv    = wm8350_set_clkdiv,
+};
+
 struct snd_soc_dai wm8350_dai = {
        .name = "WM8350",
        .playback = {
@@ -1452,15 +1564,7 @@ struct snd_soc_dai wm8350_dai = {
                 .rates = WM8350_RATES,
                 .formats = WM8350_FORMATS,
         },
-       .ops = {
-                .hw_params = wm8350_pcm_hw_params,
-                .digital_mute = wm8350_mute,
-                .trigger = wm8350_pcm_trigger,
-                .set_fmt = wm8350_set_dai_fmt,
-                .set_sysclk = wm8350_set_dai_sysclk,
-                .set_pll = wm8350_set_fll,
-                .set_clkdiv = wm8350_set_clkdiv,
-        },
+       .ops = &wm8350_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8350_dai);
 
@@ -1472,7 +1576,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8350 = {
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
 
-static int wm8350_codec_probe(struct platform_device *pdev)
+static __devinit int wm8350_codec_probe(struct platform_device *pdev)
 {
        struct wm8350 *wm8350 = platform_get_drvdata(pdev);
        struct wm8350_data *priv;
index cc2887aa6c38ff0508e9a90d79c6489e1f31927e..d11bd9288cf9170761e735e2ff4094c52353a437 100644 (file)
 extern struct snd_soc_dai wm8350_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8350;
 
+enum wm8350_jack {
+       WM8350_JDL = 1,
+       WM8350_JDR = 2,
+};
+
+int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+                         struct snd_soc_jack *jack, int report);
+
 #endif
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
new file mode 100644 (file)
index 0000000..510efa6
--- /dev/null
@@ -0,0 +1,1582 @@
+/*
+ * wm8400.c  --  WM8400 ALSA Soc Audio driver
+ *
+ * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/wm8400-audio.h>
+#include <linux/mfd/wm8400-private.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8400.h"
+
+/* Fake register for internal state */
+#define WM8400_INTDRIVBITS      (WM8400_REGISTER_COUNT + 1)
+#define WM8400_INMIXL_PWR                      0
+#define WM8400_AINLMUX_PWR                     1
+#define WM8400_INMIXR_PWR                      2
+#define WM8400_AINRMUX_PWR                     3
+
+static struct regulator_bulk_data power[] = {
+       {
+               .supply = "I2S1VDD",
+       },
+       {
+               .supply = "I2S2VDD",
+       },
+       {
+               .supply = "DCVDD",
+       },
+       {
+               .supply = "AVDD",
+       },
+       {
+               .supply = "FLLVDD",
+       },
+       {
+               .supply = "HPVDD",
+       },
+       {
+               .supply = "SPKVDD",
+       },
+};
+
+/* codec private data */
+struct wm8400_priv {
+       struct snd_soc_codec codec;
+       struct wm8400 *wm8400;
+       u16 fake_register;
+       unsigned int sysclk;
+       unsigned int pcmclk;
+       struct work_struct work;
+       int fll_in, fll_out;
+};
+
+static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
+                                      unsigned int reg)
+{
+       struct wm8400_priv *wm8400 = codec->private_data;
+
+       if (reg == WM8400_INTDRIVBITS)
+               return wm8400->fake_register;
+       else
+               return wm8400_reg_read(wm8400->wm8400, reg);
+}
+
+/*
+ * write to the wm8400 register space
+ */
+static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       struct wm8400_priv *wm8400 = codec->private_data;
+
+       if (reg == WM8400_INTDRIVBITS) {
+               wm8400->fake_register = value;
+               return 0;
+       } else
+               return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value);
+}
+
+static void wm8400_codec_reset(struct snd_soc_codec *codec)
+{
+       struct wm8400_priv *wm8400 = codec->private_data;
+
+       wm8400_reset_codec_reg_cache(wm8400->wm8400);
+}
+
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+
+static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+
+static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0);
+
+static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+
+static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+
+static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+
+static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+
+static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+
+static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+        struct snd_ctl_elem_value *ucontrol)
+{
+        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
+        int ret;
+        u16 val;
+
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+        if (ret < 0)
+                return ret;
+
+        /* now hit the volume update bits (always bit 8) */
+        val = wm8400_read(codec, reg);
+        return wm8400_write(codec, reg, val | 0x0100);
+}
+
+#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+               SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+
+static const char *wm8400_digital_sidetone[] =
+       {"None", "Left ADC", "Right ADC", "Reserved"};
+
+static const struct soc_enum wm8400_left_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
+               WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
+
+static const struct soc_enum wm8400_right_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
+               WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
+
+static const char *wm8400_adcmode[] =
+       {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static const struct soc_enum wm8400_right_adcmode_enum =
+SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
+
+static const struct snd_kcontrol_new wm8400_snd_controls[] = {
+/* INMIXL */
+SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT,
+          1, 0),
+SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT,
+          1, 0),
+/* INMIXR */
+SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT,
+          1, 0),
+SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT,
+          1, 0),
+
+/* LOMIX */
+SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3,
+       WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+       WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+       WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5,
+       WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+       WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+       WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* ROMIX */
+SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4,
+       WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+       WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+       WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6,
+       WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+       WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+       WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* LOUT */
+WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME,
+       WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0),
+
+/* ROUT */
+WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME,
+       WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0),
+
+/* LOPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME,
+       WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME,
+       WM8400_LOPGAZC_SHIFT, 1, 0),
+
+/* ROPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME,
+       WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME,
+       WM8400_ROPGAZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_LONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_LOPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_LOATTN_SHIFT, 1, 0),
+SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_RONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_ROPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+       WM8400_ROATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME,
+       WM8400_OUT3MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+       WM8400_OUT3ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME,
+       WM8400_OUT4MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+       WM8400_OUT4ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1,
+       WM8400_CDMODE_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME,
+       WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0),
+SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3,
+       WM8400_DCGAIN_SHIFT, 6, 0),
+SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3,
+       WM8400_ACGAIN_SHIFT, 6, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+       WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT,
+       127, 0, out_dac_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+       WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT,
+       127, 0, out_dac_tlv),
+
+SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum),
+SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum),
+
+SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+       WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+       WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+
+SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL,
+       WM8400_ADC_HPF_ENA_SHIFT, 1, 0),
+
+SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+       WM8400_LEFT_ADC_DIGITAL_VOLUME,
+       WM8400_ADCL_VOL_SHIFT,
+       WM8400_ADCL_VOL_MASK,
+       0,
+       in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+       WM8400_RIGHT_ADC_DIGITAL_VOLUME,
+       WM8400_ADCR_VOL_SHIFT,
+       WM8400_ADCR_VOL_MASK,
+       0,
+       in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+       WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8400_LIN12VOL_SHIFT,
+       WM8400_LIN12VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8400_LI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8400_LI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+       WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8400_LIN34VOL_SHIFT,
+       WM8400_LIN34VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8400_LI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8400_LI34MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+       WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8400_RIN12VOL_SHIFT,
+       WM8400_RIN12VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8400_RI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8400_RI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+       WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8400_RIN34VOL_SHIFT,
+       WM8400_RIN34VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8400_RI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8400_RI34MUTE_SHIFT, 1, 0),
+
+};
+
+/* add non dapm controls */
+static int wm8400_add_controls(struct snd_soc_codec *codec)
+{
+       return snd_soc_add_controls(codec, wm8400_snd_controls,
+                               ARRAY_SIZE(wm8400_snd_controls));
+}
+
+/*
+ * _DAPM_ Controls
+ */
+
+static int inmixer_event (struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       u16 reg, fakepower;
+
+       reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+       fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+
+       if (fakepower & ((1 << WM8400_INMIXL_PWR) |
+               (1 << WM8400_AINLMUX_PWR))) {
+               reg |= WM8400_AINL_ENA;
+       } else {
+               reg &= ~WM8400_AINL_ENA;
+       }
+
+       if (fakepower & ((1 << WM8400_INMIXR_PWR) |
+               (1 << WM8400_AINRMUX_PWR))) {
+               reg |= WM8400_AINR_ENA;
+       } else {
+               reg &= ~WM8400_AINL_ENA;
+       }
+       wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+
+       return 0;
+}
+
+static int outmixer_event (struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol * kcontrol, int event)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       u32 reg_shift = mc->shift;
+       int ret = 0;
+       u16 reg;
+
+       switch (reg_shift) {
+       case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
+               reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+               if (reg & WM8400_LDLO) {
+                       printk(KERN_WARNING
+                       "Cannot set as Output Mixer 1 LDLO Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
+               reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+               if (reg & WM8400_RDRO) {
+                       printk(KERN_WARNING
+                       "Cannot set as Output Mixer 2 RDRO Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
+               reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+               if (reg & WM8400_LDSPK) {
+                       printk(KERN_WARNING
+                       "Cannot set as Speaker Mixer LDSPK Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
+               reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+               if (reg & WM8400_RDSPK) {
+                       printk(KERN_WARNING
+                       "Cannot set as Speaker Mixer RDSPK Set\n");
+                       ret = -1;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+/* INMIX dB values */
+static const unsigned int in_mix_tlv[] = {
+       TLV_DB_RANGE_HEAD(1),
+       0,7, TLV_DB_LINEAR_ITEM(-1200, 600),
+};
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3,
+       WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT,
+       7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+               1, 0),
+SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+               1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4,
+       WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT,
+       7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+       1, 0),
+SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+       1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8400_ainlmux[] =
+       {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static const struct soc_enum wm8400_ainlmux_enum =
+SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
+       ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8400_ainrmux[] =
+       {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static const struct soc_enum wm8400_ainrmux_enum =
+SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
+       ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = {
+SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT,
+                       WM8400_LR4BVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT,
+                       WM8400_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = {
+SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LRBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LLBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LRI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LLI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LR12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LL12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1,
+       WM8400_LDLO_SHIFT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = {
+SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RLBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RRBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RLI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RRI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RL12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RR12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2,
+       WM8400_RDRO_SHIFT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = {
+SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+       WM8400_LLOPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1,
+       WM8400_LROPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1,
+       WM8400_LOPLON_SHIFT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = {
+SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1,
+       WM8400_LR12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1,
+       WM8400_LL12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+       WM8400_LLOPGALOP_SHIFT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = {
+SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+       WM8400_RROPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2,
+       WM8400_RLOPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2,
+       WM8400_ROPRON_SHIFT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = {
+SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2,
+       WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2,
+       WM8400_RR12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+       WM8400_RROPGAROP_SHIFT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = {
+SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+       WM8400_LI4O3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER,
+       WM8400_LPGAO3_SHIFT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = {
+SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER,
+       WM8400_RPGAO4_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+       WM8400_RI4O4_SHIFT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = {
+SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+       WM8400_LI2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER,
+       WM8400_LB2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+       WM8400_LOPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER,
+       WM8400_LDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER,
+       WM8400_RDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+       WM8400_ROPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER,
+       WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+       WM8400_RI2SPK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = {
+/* Input Side */
+/* Input Lines */
+SND_SOC_DAPM_INPUT("LIN1"),
+SND_SOC_DAPM_INPUT("LIN2"),
+SND_SOC_DAPM_INPUT("LIN3"),
+SND_SOC_DAPM_INPUT("LIN4/RXN"),
+SND_SOC_DAPM_INPUT("RIN3"),
+SND_SOC_DAPM_INPUT("RIN4/RXP"),
+SND_SOC_DAPM_INPUT("RIN1"),
+SND_SOC_DAPM_INPUT("RIN2"),
+SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+/* DACs */
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2,
+       WM8400_ADCL_ENA_SHIFT, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2,
+       WM8400_ADCR_ENA_SHIFT, 0),
+
+/* Input PGAs */
+SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+                  WM8400_LIN12_ENA_SHIFT,
+                  0, &wm8400_dapm_lin12_pga_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)),
+SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+                  WM8400_LIN34_ENA_SHIFT,
+                  0, &wm8400_dapm_lin34_pga_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+                  WM8400_RIN12_ENA_SHIFT,
+                  0, &wm8400_dapm_rin12_pga_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+                  WM8400_RIN34_ENA_SHIFT,
+                  0, &wm8400_dapm_rin34_pga_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
+
+/* INMIXL */
+SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0,
+       &wm8400_dapm_inmixl_controls[0],
+       ARRAY_SIZE(wm8400_dapm_inmixl_controls),
+       inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINLMUX */
+SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0,
+       &wm8400_dapm_ainlmux_controls, inmixer_event,
+       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* INMIXR */
+SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0,
+       &wm8400_dapm_inmixr_controls[0],
+       ARRAY_SIZE(wm8400_dapm_inmixr_controls),
+       inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINRMUX */
+SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0,
+       &wm8400_dapm_ainrmux_controls, inmixer_event,
+       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* Output Side */
+/* DACs */
+SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3,
+       WM8400_DACL_ENA_SHIFT, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3,
+       WM8400_DACR_ENA_SHIFT, 0),
+
+/* LOMIX */
+SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3,
+                    WM8400_LOMIX_ENA_SHIFT,
+                    0, &wm8400_dapm_lomix_controls[0],
+                    ARRAY_SIZE(wm8400_dapm_lomix_controls),
+                    outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LONMIX */
+SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT,
+                  0, &wm8400_dapm_lonmix_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_lonmix_controls)),
+
+/* LOPMIX */
+SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT,
+                  0, &wm8400_dapm_lopmix_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_lopmix_controls)),
+
+/* OUT3MIX */
+SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT,
+                  0, &wm8400_dapm_out3mix_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_out3mix_controls)),
+
+/* SPKMIX */
+SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT,
+                    0, &wm8400_dapm_spkmix_controls[0],
+                    ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event,
+                    SND_SOC_DAPM_PRE_REG),
+
+/* OUT4MIX */
+SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT,
+       0, &wm8400_dapm_out4mix_controls[0],
+       ARRAY_SIZE(wm8400_dapm_out4mix_controls)),
+
+/* ROPMIX */
+SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT,
+                  0, &wm8400_dapm_ropmix_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_ropmix_controls)),
+
+/* RONMIX */
+SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT,
+                  0, &wm8400_dapm_ronmix_controls[0],
+                  ARRAY_SIZE(wm8400_dapm_ronmix_controls)),
+
+/* ROMIX */
+SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3,
+                    WM8400_ROMIX_ENA_SHIFT,
+                    0, &wm8400_dapm_romix_controls[0],
+                    ARRAY_SIZE(wm8400_dapm_romix_controls),
+                    outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LOUT PGA */
+SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT,
+                0, NULL, 0),
+
+/* ROUT PGA */
+SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT,
+                0, NULL, 0),
+
+/* LOPGA */
+SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0,
+       NULL, 0),
+
+/* ROPGA */
+SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0,
+       NULL, 0),
+
+/* MICBIAS */
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1,
+       WM8400_MIC1BIAS_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Make DACs turn on when playing even if not mixed into any outputs */
+       {"Internal DAC Sink", NULL, "Left DAC"},
+       {"Internal DAC Sink", NULL, "Right DAC"},
+
+       /* Make ADCs turn on when recording
+        * even if not mixed from any inputs */
+       {"Left ADC", NULL, "Internal ADC Source"},
+       {"Right ADC", NULL, "Internal ADC Source"},
+
+       /* Input Side */
+       /* LIN12 PGA */
+       {"LIN12 PGA", "LIN1 Switch", "LIN1"},
+       {"LIN12 PGA", "LIN2 Switch", "LIN2"},
+       /* LIN34 PGA */
+       {"LIN34 PGA", "LIN3 Switch", "LIN3"},
+       {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
+       /* INMIXL */
+       {"INMIXL", "Record Left Volume", "LOMIX"},
+       {"INMIXL", "LIN2 Volume", "LIN2"},
+       {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+       {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+       /* AILNMUX */
+       {"AILNMUX", "INMIXL Mix", "INMIXL"},
+       {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
+       {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
+       {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"},
+       {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"},
+       /* ADC */
+       {"Left ADC", NULL, "AILNMUX"},
+
+       /* RIN12 PGA */
+       {"RIN12 PGA", "RIN1 Switch", "RIN1"},
+       {"RIN12 PGA", "RIN2 Switch", "RIN2"},
+       /* RIN34 PGA */
+       {"RIN34 PGA", "RIN3 Switch", "RIN3"},
+       {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
+       /* INMIXL */
+       {"INMIXR", "Record Right Volume", "ROMIX"},
+       {"INMIXR", "RIN2 Volume", "RIN2"},
+       {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+       {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+       /* AIRNMUX */
+       {"AIRNMUX", "INMIXR Mix", "INMIXR"},
+       {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
+       {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
+       {"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"},
+       {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"},
+       /* ADC */
+       {"Right ADC", NULL, "AIRNMUX"},
+
+       /* LOMIX */
+       {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+       {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+       {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+       {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+       {"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"},
+       {"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"},
+       {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+       /* ROMIX */
+       {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+       {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+       {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+       {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+       {"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"},
+       {"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"},
+       {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+       /* SPKMIX */
+       {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+       {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+       {"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"},
+       {"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"},
+       {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+       {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+       {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+       {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+       /* LONMIX */
+       {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+       {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+       {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+       /* LOPMIX */
+       {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+       {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+       {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+       /* OUT3MIX */
+       {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"},
+       {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+       /* OUT4MIX */
+       {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+       {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
+
+       /* RONMIX */
+       {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+       {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+       {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+       /* ROPMIX */
+       {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+       {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+       {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+       /* Out Mixer PGAs */
+       {"LOPGA", NULL, "LOMIX"},
+       {"ROPGA", NULL, "ROMIX"},
+
+       {"LOUT PGA", NULL, "LOMIX"},
+       {"ROUT PGA", NULL, "ROMIX"},
+
+       /* Output Pins */
+       {"LON", NULL, "LONMIX"},
+       {"LOP", NULL, "LOPMIX"},
+       {"OUT3", NULL, "OUT3MIX"},
+       {"LOUT", NULL, "LOUT PGA"},
+       {"SPKN", NULL, "SPKMIX"},
+       {"ROUT", NULL, "ROUT PGA"},
+       {"OUT4", NULL, "OUT4MIX"},
+       {"ROP", NULL, "ROPMIX"},
+       {"RON", NULL, "RONMIX"},
+};
+
+static int wm8400_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets,
+                                 ARRAY_SIZE(wm8400_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+/*
+ * Clock after FLL and dividers
+ */
+static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8400_priv *wm8400 = codec->private_data;
+
+       wm8400->sysclk = freq;
+       return 0;
+}
+
+struct fll_factors {
+       u16 n;
+       u16 k;
+       u16 outdiv;
+       u16 fratio;
+       u16 freq_ref;
+};
+
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
+                      unsigned int Fref, unsigned int Fout)
+{
+       u64 Kpart;
+       unsigned int K, Nmod, target;
+
+       factors->outdiv = 2;
+       while (Fout * factors->outdiv <  90000000 ||
+              Fout * factors->outdiv > 100000000) {
+               factors->outdiv *= 2;
+               if (factors->outdiv > 32) {
+                       dev_err(wm8400->wm8400->dev,
+                               "Unsupported FLL output frequency %dHz\n",
+                               Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * factors->outdiv;
+       factors->outdiv = factors->outdiv >> 2;
+
+       if (Fref < 48000)
+               factors->freq_ref = 1;
+       else
+               factors->freq_ref = 0;
+
+       if (Fref < 1000000)
+               factors->fratio = 9;
+       else
+               factors->fratio = 0;
+
+       /* Ensure we have a fractional part */
+       do {
+               if (Fref < 1000000)
+                       factors->fratio--;
+               else
+                       factors->fratio++;
+
+               if (factors->fratio < 1 || factors->fratio > 8) {
+                       dev_err(wm8400->wm8400->dev,
+                               "Unable to calculate FRATIO\n");
+                       return -EINVAL;
+               }
+
+               factors->n = target / (Fref * factors->fratio);
+               Nmod = target % (Fref * factors->fratio);
+       } while (Nmod == 0);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, (Fref * factors->fratio));
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       factors->k = K / 10;
+
+       dev_dbg(wm8400->wm8400->dev,
+               "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
+               Fref, Fout,
+               factors->n, factors->k, factors->fratio, factors->outdiv);
+
+       return 0;
+}
+
+static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+                             unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8400_priv *wm8400 = codec->private_data;
+       struct fll_factors factors;
+       int ret;
+       u16 reg;
+
+       if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
+               return 0;
+
+       if (freq_out != 0) {
+               ret = fll_factors(wm8400, &factors, freq_in, freq_out);
+               if (ret != 0)
+                       return ret;
+       }
+
+       wm8400->fll_out = freq_out;
+       wm8400->fll_in = freq_in;
+
+       /* We *must* disable the FLL before any changes */
+       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+       reg &= ~WM8400_FLL_ENA;
+       wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+
+       reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+       reg &= ~WM8400_FLL_OSC_ENA;
+       wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+
+       if (freq_out == 0)
+               return 0;
+
+       reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
+       reg |= WM8400_FLL_FRAC | factors.fratio;
+       reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
+       wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+
+       wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+       wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+
+       reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+       reg &= WM8400_FLL_OUTDIV_MASK;
+       reg |= factors.outdiv;
+       wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+
+       return 0;
+}
+
+/*
+ * Sets ADC and Voice DAC format.
+ */
+static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 audio1, audio3;
+
+       audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+       audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               audio3 &= ~WM8400_AIF_MSTR1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               audio3 |= WM8400_AIF_MSTR1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       audio1 &= ~WM8400_AIF_FMT_MASK;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               audio1 |= WM8400_AIF_FMT_I2S;
+               audio1 &= ~WM8400_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               audio1 |= WM8400_AIF_FMT_RIGHTJ;
+               audio1 &= ~WM8400_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               audio1 |= WM8400_AIF_FMT_LEFTJ;
+               audio1 &= ~WM8400_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               audio1 |= WM8400_AIF_FMT_DSP;
+               audio1 &= ~WM8400_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+       wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+       return 0;
+}
+
+static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+               int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       switch (div_id) {
+       case WM8400_MCLK_DIV:
+               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+                       ~WM8400_MCLK_DIV_MASK;
+               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               break;
+       case WM8400_DACCLK_DIV:
+               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+                       ~WM8400_DAC_CLKDIV_MASK;
+               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               break;
+       case WM8400_ADCCLK_DIV:
+               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+                       ~WM8400_ADC_CLKDIV_MASK;
+               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               break;
+       case WM8400_BCLK_DIV:
+               reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+                       ~WM8400_BCLK_DIV_MASK;
+               wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8400_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+
+       audio1 &= ~WM8400_AIF_WL_MASK;
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               audio1 |= WM8400_AIF_WL_20BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               audio1 |= WM8400_AIF_WL_24BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               audio1 |= WM8400_AIF_WL_32BITS;
+               break;
+       }
+
+       wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+       return 0;
+}
+
+static int wm8400_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+
+       if (mute)
+               wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+       else
+               wm8400_write(codec, WM8400_DAC_CTRL, val);
+
+       return 0;
+}
+
+/* TODO: set bias for best performance at standby */
+static int wm8400_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8400_priv *wm8400 = codec->private_data;
+       u16 val;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID=2*50k */
+               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+                       ~WM8400_VMID_MODE_MASK;
+               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(power),
+                                                   &power[0]);
+                       if (ret != 0) {
+                               dev_err(wm8400->wm8400->dev,
+                                       "Failed to enable regulators: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+                                    WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
+
+                       /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                                    WM8400_BUFDCOPEN | WM8400_POBCTRL);
+
+                       msleep(50);
+
+                       /* Enable VREF & VMID at 2x50k */
+                       val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+                       val |= 0x2 | WM8400_VREF_ENA;
+                       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+                       /* Enable BUFIOEN */
+                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                                    WM8400_BUFDCOPEN | WM8400_POBCTRL |
+                                    WM8400_BUFIOEN);
+
+                       /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+               }
+
+               /* VMID=2*300k */
+               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+                       ~WM8400_VMID_MODE_MASK;
+               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Enable POBCTRL and SOFT_ST */
+               wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                       WM8400_POBCTRL | WM8400_BUFIOEN);
+
+               /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+               wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                       WM8400_BUFDCOPEN | WM8400_POBCTRL |
+                       WM8400_BUFIOEN);
+
+               /* mute DAC */
+               val = wm8400_read(codec, WM8400_DAC_CTRL);
+               wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+
+               /* Enable any disabled outputs */
+               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+               val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
+                       WM8400_OUT4_ENA | WM8400_LOUT_ENA |
+                       WM8400_ROUT_ENA;
+               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+               /* Disable VMID */
+               val &= ~WM8400_VMID_MODE_MASK;
+               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+               msleep(300);
+
+               /* Enable all output discharge bits */
+               wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+                       WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
+                       WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
+                       WM8400_DIS_ROUT);
+
+               /* Disable VREF */
+               val &= ~WM8400_VREF_ENA;
+               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+               /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+               wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+
+               ret = regulator_bulk_disable(ARRAY_SIZE(power),
+                                            &power[0]);
+               if (ret != 0)
+                       return ret;
+
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8400_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8400_dai_ops = {
+       .hw_params = wm8400_hw_params,
+       .digital_mute = wm8400_mute,
+       .set_fmt = wm8400_set_dai_fmt,
+       .set_clkdiv = wm8400_set_dai_clkdiv,
+       .set_sysclk = wm8400_set_dai_sysclk,
+       .set_pll = wm8400_set_dai_pll,
+};
+
+/*
+ * The WM8400 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+struct snd_soc_dai wm8400_dai = {
+/* ADC/DAC on primary */
+       .name = "WM8400 ADC/DAC Primary",
+       .id = 1,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8400_RATES,
+               .formats = WM8400_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8400_RATES,
+               .formats = WM8400_FORMATS,
+       },
+       .ops = &wm8400_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8400_dai);
+
+static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8400_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+static struct snd_soc_codec *wm8400_codec;
+
+static int wm8400_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret;
+
+       if (!wm8400_codec) {
+               dev_err(&pdev->dev, "wm8400 not yet discovered\n");
+               return -ENODEV;
+       }
+       codec = wm8400_codec;
+
+       socdev->card->codec = codec;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       wm8400_add_controls(codec);
+       wm8400_add_widgets(codec);
+
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       return ret;
+}
+
+/* power down chip */
+static int wm8400_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8400 = {
+       .probe =        wm8400_probe,
+       .remove =       wm8400_remove,
+       .suspend =      wm8400_suspend,
+       .resume =       wm8400_resume,
+};
+
+static void wm8400_probe_deferred(struct work_struct *work)
+{
+       struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
+                                               work);
+       struct snd_soc_codec *codec = &priv->codec;
+       int ret;
+
+       /* charge output caps */
+       wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* We're done, tell the subsystem. */
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(priv->wm8400->dev,
+                       "Failed to register codec: %d\n", ret);
+               goto err;
+       }
+
+       ret = snd_soc_register_dai(&wm8400_dai);
+       if (ret != 0) {
+               dev_err(priv->wm8400->dev,
+                       "Failed to register DAI: %d\n", ret);
+               goto err_codec;
+       }
+
+       return;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int wm8400_codec_probe(struct platform_device *dev)
+{
+       struct wm8400_priv *priv;
+       int ret;
+       u16 reg;
+       struct snd_soc_codec *codec;
+
+       priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       codec = &priv->codec;
+       codec->private_data = priv;
+       codec->control_data = dev->dev.driver_data;
+       priv->wm8400 = dev->dev.driver_data;
+
+       ret = regulator_bulk_get(priv->wm8400->dev,
+                                ARRAY_SIZE(power), &power[0]);
+       if (ret != 0) {
+               dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+               goto err;
+       }
+
+       codec->dev = &dev->dev;
+       wm8400_dai.dev = &dev->dev;
+
+       codec->name = "WM8400";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8400_read;
+       codec->write = wm8400_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8400_set_bias_level;
+       codec->dai = &wm8400_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8400_REGISTER_COUNT;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       INIT_WORK(&priv->work, wm8400_probe_deferred);
+
+       wm8400_codec_reset(codec);
+
+       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+
+       /* Latch volume update bits */
+       reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+       wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+                    reg & WM8400_IPVU);
+       reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+       wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+                    reg & WM8400_IPVU);
+
+       wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+       wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+       wm8400_codec = codec;
+
+       if (!schedule_work(&priv->work)) {
+               ret = -EINVAL;
+               goto err_regulator;
+       }
+
+       return 0;
+
+err_regulator:
+       wm8400_codec = NULL;
+       regulator_bulk_free(ARRAY_SIZE(power), power);
+err:
+       kfree(priv);
+       return ret;
+}
+
+static int __exit wm8400_codec_remove(struct platform_device *dev)
+{
+       struct wm8400_priv *priv = wm8400_codec->private_data;
+       u16 reg;
+
+       snd_soc_unregister_dai(&wm8400_dai);
+       snd_soc_unregister_codec(wm8400_codec);
+
+       reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
+       wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+                    reg & (~WM8400_CODEC_ENA));
+
+       regulator_bulk_free(ARRAY_SIZE(power), power);
+       kfree(priv);
+
+       wm8400_codec = NULL;
+
+       return 0;
+}
+
+static struct platform_driver wm8400_codec_driver = {
+       .driver = {
+               .name = "wm8400-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8400_codec_probe,
+       .remove = __exit_p(wm8400_codec_remove),
+};
+
+static int __init wm8400_codec_init(void)
+{
+       return platform_driver_register(&wm8400_codec_driver);
+}
+module_init(wm8400_codec_init);
+
+static void __exit wm8400_codec_exit(void)
+{
+       platform_driver_unregister(&wm8400_codec_driver);
+}
+module_exit(wm8400_codec_exit);
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+
+MODULE_DESCRIPTION("ASoC WM8400 driver");
+MODULE_AUTHOR("Mark Brown");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-codec");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
new file mode 100644 (file)
index 0000000..79c5934
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * wm8400.h  --  audio driver for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _WM8400_CODEC_H
+#define _WM8400_CODEC_H
+
+#define WM8400_MCLK_DIV 0
+#define WM8400_DACCLK_DIV 1
+#define WM8400_ADCCLK_DIV 2
+#define WM8400_BCLK_DIV 3
+
+#define WM8400_MCLK_DIV_1 0x400
+#define WM8400_MCLK_DIV_2 0x800
+
+#define WM8400_DAC_CLKDIV_1    0x00
+#define WM8400_DAC_CLKDIV_1_5  0x04
+#define WM8400_DAC_CLKDIV_2    0x08
+#define WM8400_DAC_CLKDIV_3    0x0c
+#define WM8400_DAC_CLKDIV_4    0x10
+#define WM8400_DAC_CLKDIV_5_5  0x14
+#define WM8400_DAC_CLKDIV_6    0x18
+
+#define WM8400_ADC_CLKDIV_1    0x00
+#define WM8400_ADC_CLKDIV_1_5  0x20
+#define WM8400_ADC_CLKDIV_2    0x40
+#define WM8400_ADC_CLKDIV_3    0x60
+#define WM8400_ADC_CLKDIV_4    0x80
+#define WM8400_ADC_CLKDIV_5_5  0xa0
+#define WM8400_ADC_CLKDIV_6    0xc0
+
+
+#define WM8400_BCLK_DIV_1                       (0x0 << 1)
+#define WM8400_BCLK_DIV_1_5                     (0x1 << 1)
+#define WM8400_BCLK_DIV_2                       (0x2 << 1)
+#define WM8400_BCLK_DIV_3                       (0x3 << 1)
+#define WM8400_BCLK_DIV_4                       (0x4 << 1)
+#define WM8400_BCLK_DIV_5_5                     (0x5 << 1)
+#define WM8400_BCLK_DIV_6                       (0x6 << 1)
+#define WM8400_BCLK_DIV_8                       (0x7 << 1)
+#define WM8400_BCLK_DIV_11                      (0x8 << 1)
+#define WM8400_BCLK_DIV_12                      (0x9 << 1)
+#define WM8400_BCLK_DIV_16                      (0xA << 1)
+#define WM8400_BCLK_DIV_22                      (0xB << 1)
+#define WM8400_BCLK_DIV_24                      (0xC << 1)
+#define WM8400_BCLK_DIV_32                      (0xD << 1)
+#define WM8400_BCLK_DIV_44                      (0xE << 1)
+#define WM8400_BCLK_DIV_48                      (0xF << 1)
+
+extern struct snd_soc_dai wm8400_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8400;
+
+#endif
index 40f8238df7174d65b6c306fbd23e51d505a85d1c..6a4cea09c45dbe624ba2941442c68e3fdb5971c2 100644 (file)
@@ -171,22 +171,6 @@ SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST,  8, 1, 0),
 SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1),
 };
 
-/* add non dapm controls */
-static int wm8510_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8510_snd_controls[i], codec,
-                                       NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Speaker Output Mixer */
 static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0),
@@ -352,7 +336,7 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
                return 0;
        }
 
-       pll_factors(freq_out*8, freq_in);
+       pll_factors(freq_out*4, freq_in);
 
        wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
        wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
@@ -383,7 +367,7 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                wm8510_write(codec, WM8510_GPIO, reg | div);
                break;
        case WM8510_MCLKDIV:
-               reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f;
+               reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
                wm8510_write(codec, WM8510_CLOCK, reg | div);
                break;
        case WM8510_ADCCLK:
@@ -468,7 +452,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
        u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
 
@@ -570,6 +554,14 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops wm8510_dai_ops = {
+       .hw_params      = wm8510_pcm_hw_params,
+       .digital_mute   = wm8510_mute,
+       .set_fmt        = wm8510_set_dai_fmt,
+       .set_clkdiv     = wm8510_set_dai_clkdiv,
+       .set_pll        = wm8510_set_dai_pll,
+};
+
 struct snd_soc_dai wm8510_dai = {
        .name = "WM8510 HiFi",
        .playback = {
@@ -584,20 +576,14 @@ struct snd_soc_dai wm8510_dai = {
                .channels_max = 2,
                .rates = WM8510_RATES,
                .formats = WM8510_FORMATS,},
-       .ops = {
-               .hw_params = wm8510_pcm_hw_params,
-               .digital_mute = wm8510_mute,
-               .set_fmt = wm8510_set_dai_fmt,
-               .set_clkdiv = wm8510_set_dai_clkdiv,
-               .set_pll = wm8510_set_dai_pll,
-       },
+       .ops = &wm8510_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8510_dai);
 
 static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -606,7 +592,7 @@ static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8510_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -628,7 +614,7 @@ static int wm8510_resume(struct platform_device *pdev)
  */
 static int wm8510_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        codec->name = "WM8510";
@@ -656,7 +642,8 @@ static int wm8510_init(struct snd_soc_device *socdev)
        /* power on device */
        codec->bias_level = SND_SOC_BIAS_OFF;
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       wm8510_add_controls(codec);
+       snd_soc_add_controls(codec, wm8510_snd_controls,
+                               ARRAY_SIZE(wm8510_snd_controls));
        wm8510_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -685,7 +672,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -766,7 +753,7 @@ err_driver:
 static int __devinit wm8510_spi_probe(struct spi_device *spi)
 {
        struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        codec->control_data = spi;
@@ -832,7 +819,7 @@ static int wm8510_probe(struct platform_device *pdev)
        if (codec == NULL)
                return -ENOMEM;
 
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -862,7 +849,7 @@ static int wm8510_probe(struct platform_device *pdev)
 static int wm8510_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
index d004e5845298d2b8e6f4871629b75c78702e8724..442ea6f160fc0eaefcd1c55b247cd88acbe02d27 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8580.c  --  WM8580 ALSA Soc Audio driver
  *
- * Copyright 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008, 2009 Wolfson Microelectronics PLC.
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
 
 #include "wm8580.h"
 
-#define WM8580_VERSION "0.1"
-
-struct pll_state {
-       unsigned int in;
-       unsigned int out;
-};
-
-/* codec private data */
-struct wm8580_priv {
-       struct pll_state a;
-       struct pll_state b;
-};
-
 /* WM8580 register space */
 #define WM8580_PLLA1                         0x00
 #define WM8580_PLLA2                         0x01
@@ -102,6 +89,8 @@ struct wm8580_priv {
 #define WM8580_READBACK                      0x34
 #define WM8580_RESET                         0x35
 
+#define WM8580_MAX_REGISTER                  0x35
+
 /* PLLB4 (register 7h) */
 #define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
 #define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
@@ -193,6 +182,20 @@ static const u16 wm8580_reg[] = {
        0x0000, 0x0000 /*R53*/
 };
 
+struct pll_state {
+       unsigned int in;
+       unsigned int out;
+};
+
+/* codec private data */
+struct wm8580_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8580_MAX_REGISTER + 1];
+       struct pll_state a;
+       struct pll_state b;
+};
+
+
 /*
  * read wm8580 register cache
  */
@@ -200,7 +203,7 @@ static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+       BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
        return cache[reg];
 }
 
@@ -223,7 +226,7 @@ static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
 {
        u8 data[2];
 
-       BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+       BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
 
        /* Registers are 9 bits wide */
        value &= 0x1ff;
@@ -330,20 +333,6 @@ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
 SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
 };
 
-/* Add non-DAPM controls */
-static int wm8580_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8580_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
 static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
 SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
 SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
@@ -553,7 +542,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id);
 
        paifb &= ~WM8580_AIF_LENGTH_MASK;
@@ -771,8 +760,22 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
+               break;
+
        case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Power up and get individual control of the DACs */
+                       reg = wm8580_read(codec, WM8580_PWRDN1);
+                       reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
+                       wm8580_write(codec, WM8580_PWRDN1, reg);
+
+                       /* Make VMID high impedence */
+                       reg = wm8580_read(codec,  WM8580_ADC_CONTROL1);
+                       reg &= ~0x100;
+                       wm8580_write(codec, WM8580_ADC_CONTROL1, reg);
+               }
                break;
+
        case SND_SOC_BIAS_OFF:
                reg = wm8580_read(codec, WM8580_PWRDN1);
                wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
@@ -785,6 +788,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
 #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+       .hw_params      = wm8580_paif_hw_params,
+       .set_fmt        = wm8580_set_paif_dai_fmt,
+       .set_clkdiv     = wm8580_set_dai_clkdiv,
+       .set_pll        = wm8580_set_dai_pll,
+       .digital_mute   = wm8580_digital_mute,
+};
+
+static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+       .hw_params      = wm8580_paif_hw_params,
+       .set_fmt        = wm8580_set_paif_dai_fmt,
+       .set_clkdiv     = wm8580_set_dai_clkdiv,
+       .set_pll        = wm8580_set_dai_pll,
+};
+
 struct snd_soc_dai wm8580_dai[] = {
        {
                .name = "WM8580 PAIFRX",
@@ -796,13 +814,7 @@ struct snd_soc_dai wm8580_dai[] = {
                        .rates = SNDRV_PCM_RATE_8000_192000,
                        .formats = WM8580_FORMATS,
                },
-               .ops = {
-                        .hw_params = wm8580_paif_hw_params,
-                        .set_fmt = wm8580_set_paif_dai_fmt,
-                        .set_clkdiv = wm8580_set_dai_clkdiv,
-                        .set_pll = wm8580_set_dai_pll,
-                        .digital_mute = wm8580_digital_mute,
-                },
+               .ops = &wm8580_dai_ops_playback,
        },
        {
                .name = "WM8580 PAIFTX",
@@ -814,109 +826,168 @@ struct snd_soc_dai wm8580_dai[] = {
                        .rates = SNDRV_PCM_RATE_8000_192000,
                        .formats = WM8580_FORMATS,
                },
-               .ops = {
-                        .hw_params = wm8580_paif_hw_params,
-                        .set_fmt = wm8580_set_paif_dai_fmt,
-                        .set_clkdiv = wm8580_set_dai_clkdiv,
-                        .set_pll = wm8580_set_dai_pll,
-                },
+               .ops = &wm8580_dai_ops_capture,
        },
 };
 EXPORT_SYMBOL_GPL(wm8580_dai);
 
-/*
- * initialise the WM8580 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8580_init(struct snd_soc_device *socdev)
+static struct snd_soc_codec *wm8580_codec;
+
+static int wm8580_probe(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
        int ret = 0;
 
-       codec->name = "WM8580";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8580_read_reg_cache;
-       codec->write = wm8580_write;
-       codec->set_bias_level = wm8580_set_bias_level;
-       codec->dai = wm8580_dai;
-       codec->num_dai = ARRAY_SIZE(wm8580_dai);
-       codec->reg_cache_size = ARRAY_SIZE(wm8580_reg);
-       codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg),
-                                  GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
-
-       /* Get the codec into a known state */
-       wm8580_write(codec, WM8580_RESET, 0);
-
-       /* Power up and get individual control of the DACs */
-       wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) &
-                    ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD));
+       if (wm8580_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
 
-       /* Make VMID high impedence */
-       wm8580_write(codec, WM8580_ADC_CONTROL1,
-                    wm8580_read(codec,  WM8580_ADC_CONTROL1) & ~0x100);
+       socdev->card->codec = wm8580_codec;
+       codec = wm8580_codec;
 
        /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
-                              SNDRV_DEFAULT_STR1);
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
-               printk(KERN_ERR "wm8580: failed to create pcms\n");
+               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
                goto pcm_err;
        }
 
-       wm8580_add_controls(codec);
+       snd_soc_add_controls(codec, wm8580_snd_controls,
+                            ARRAY_SIZE(wm8580_snd_controls));
        wm8580_add_widgets(codec);
-
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
-               printk(KERN_ERR "wm8580: failed to register card\n");
+               dev_err(codec->dev, "failed to register card: %d\n", ret);
                goto card_err;
        }
+
        return ret;
 
 card_err:
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 pcm_err:
-       kfree(codec->reg_cache);
        return ret;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8580_socdev;
+/* power down chip */
+static int wm8580_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       return 0;
+}
 
-/*
- * WM8580 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
+struct snd_soc_codec_device soc_codec_dev_wm8580 = {
+       .probe =        wm8580_probe,
+       .remove =       wm8580_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
+
+static int wm8580_register(struct wm8580_priv *wm8580)
+{
+       int ret, i;
+       struct snd_soc_codec *codec = &wm8580->codec;
+
+       if (wm8580_codec) {
+               dev_err(codec->dev, "Another WM8580 is registered\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
 
+       codec->private_data = wm8580;
+       codec->name = "WM8580";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8580_read_reg_cache;
+       codec->write = wm8580_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8580_set_bias_level;
+       codec->dai = wm8580_dai;
+       codec->num_dai = ARRAY_SIZE(wm8580_dai);
+       codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
+       codec->reg_cache = &wm8580->reg_cache;
+
+       memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+
+       /* Get the codec into a known state */
+       ret = wm8580_write(codec, WM8580_RESET, 0);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
+               wm8580_dai[i].dev = codec->dev;
+
+       wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       wm8580_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto err;
+       }
+
+       ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               goto err_codec;
+       }
+
+       return 0;
+
+err_codec:
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(wm8580);
+       return ret;
+}
+
+static void wm8580_unregister(struct wm8580_priv *wm8580)
+{
+       wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+       snd_soc_unregister_codec(&wm8580->codec);
+       kfree(wm8580);
+       wm8580_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8580_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8580_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int ret;
+       struct wm8580_priv *wm8580;
+       struct snd_soc_codec *codec;
 
-       i2c_set_clientdata(i2c, codec);
+       wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
+       if (wm8580 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8580->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(i2c, wm8580);
        codec->control_data = i2c;
 
-       ret = wm8580_init(socdev);
-       if (ret < 0)
-               dev_err(&i2c->dev, "failed to initialise WM8580\n");
-       return ret;
+       codec->dev = &i2c->dev;
+
+       return wm8580_register(wm8580);
 }
 
 static int wm8580_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
+       wm8580_unregister(wm8580);
        return 0;
 }
 
@@ -928,129 +999,35 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
 
 static struct i2c_driver wm8580_i2c_driver = {
        .driver = {
-               .name = "WM8580 I2C Codec",
+               .name = "wm8580",
                .owner = THIS_MODULE,
        },
        .probe =    wm8580_i2c_probe,
        .remove =   wm8580_i2c_remove,
        .id_table = wm8580_i2c_id,
 };
+#endif
 
-static int wm8580_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8580_setup_data *setup)
+static int __init wm8580_modinit(void)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
        int ret;
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8580_i2c_driver);
        if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8580", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
+               pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
        }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8580_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int wm8580_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8580_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct wm8580_priv *wm8580;
-       int ret = 0;
-
-       pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
-       if (wm8580 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       codec->private_data = wm8580;
-       socdev->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8580_socdev = socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = wm8580_add_i2c_device(pdev, setup);
-       }
-#else
-               /* Add other interfaces here */
-#endif
-       return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
-
-       if (codec->control_data)
-               wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
-       i2c_del_driver(&wm8580_i2c_driver);
-#endif
-       kfree(codec->private_data);
-       kfree(codec);
-
        return 0;
 }
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
-       .probe =        wm8580_probe,
-       .remove =       wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int __init wm8580_modinit(void)
-{
-       return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-}
 module_init(wm8580_modinit);
 
 static void __exit wm8580_exit(void)
 {
-       snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8580_i2c_driver);
+#endif
 }
 module_exit(wm8580_exit);
 
index 09e4422f6f2fbfeda01f4d068b5eb13532a69a84..0dfb5ddde6a2a700fe4aacb878ae9def6af73777 100644 (file)
 #define WM8580_CLKSRC_OSC  4
 #define WM8580_CLKSRC_NONE 5
 
-struct wm8580_setup_data {
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
 #define WM8580_DAI_PAIFRX 0
 #define WM8580_DAI_PAIFTX 1
 
index 80b11983e1373802639f1f4a37ca25c2c2d4dfc6..e7ff2121ede9b7b4781eecf9ead866db3afbd289 100644 (file)
@@ -47,7 +47,7 @@ static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+       BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
        return cache[reg];
 }
 
@@ -55,7 +55,7 @@ static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
        u16 reg, unsigned int value)
 {
        u16 *cache = codec->reg_cache;
-       BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+       BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
        cache[reg] = value;
 }
 
@@ -92,21 +92,6 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
 SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
 };
 
-static int wm8728_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8728_snd_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /*
  * DAPM controls.
  */
@@ -152,7 +137,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL);
 
        dac &= ~0x18;
@@ -259,6 +244,12 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8728_dai_ops = {
+       .hw_params      = wm8728_hw_params,
+       .digital_mute   = wm8728_mute,
+       .set_fmt        = wm8728_set_dai_fmt,
+};
+
 struct snd_soc_dai wm8728_dai = {
        .name = "WM8728",
        .playback = {
@@ -268,18 +259,14 @@ struct snd_soc_dai wm8728_dai = {
                .rates = WM8728_RATES,
                .formats = WM8728_FORMATS,
        },
-       .ops = {
-                .hw_params = wm8728_hw_params,
-                .digital_mute = wm8728_mute,
-                .set_fmt = wm8728_set_dai_fmt,
-       }
+       .ops = &wm8728_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8728_dai);
 
 static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -289,7 +276,7 @@ static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8728_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8728_set_bias_level(codec, codec->suspend_bias_level);
 
@@ -302,7 +289,7 @@ static int wm8728_resume(struct platform_device *pdev)
  */
 static int wm8728_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        codec->name = "WM8728";
@@ -330,7 +317,8 @@ static int wm8728_init(struct snd_soc_device *socdev)
        /* power on device */
        wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8728_add_controls(codec);
+       snd_soc_add_controls(codec, wm8728_snd_controls,
+                               ARRAY_SIZE(wm8728_snd_controls));
        wm8728_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -363,7 +351,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -444,7 +432,7 @@ err_driver:
 static int __devinit wm8728_spi_probe(struct spi_device *spi)
 {
        struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        codec->control_data = spi;
@@ -508,7 +496,7 @@ static int wm8728_probe(struct platform_device *pdev)
        if (codec == NULL)
                return -ENOMEM;
 
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -541,7 +529,7 @@ static int wm8728_probe(struct platform_device *pdev)
 static int wm8728_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
index c444b9f2701ed7625baa550cc0030bf35d6d6712..e043e3f60008b46579e4ae97e411a0df1790e15b 100644 (file)
 
 #include "wm8731.h"
 
-#define WM8731_VERSION "0.13"
-
+static struct snd_soc_codec *wm8731_codec;
 struct snd_soc_codec_device soc_codec_dev_wm8731;
 
 /* codec private data */
 struct wm8731_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
 };
 
+#ifdef CONFIG_SPI_MASTER
+static int wm8731_spi_write(struct spi_device *spi, const char *data, int len);
+#endif
+
 /*
  * wm8731 register cache
  * We can't read the WM8731 register space when we are
@@ -129,22 +134,6 @@ SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
 SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
 };
 
-/* add non dapm controls */
-static int wm8731_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8731_snd_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* Output Mixer */
 static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
@@ -269,7 +258,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8731_priv *wm8731 = codec->private_data;
        u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
        int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -299,7 +288,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* set active */
        wm8731_write(codec, WM8731_ACTIVE, 0x0001);
@@ -312,7 +301,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* deactivate */
        if (!codec->active) {
@@ -414,21 +403,19 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int wm8731_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
+       u16 reg;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               /* vref/mid, osc on, dac unmute */
-               wm8731_write(codec, WM8731_PWR, reg);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* everything off except vref/vmid, */
+               /* Clear PWROFF, gate CLKOUT, everything else as-is */
+               reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
                wm8731_write(codec, WM8731_PWR, reg | 0x0040);
                break;
        case SND_SOC_BIAS_OFF:
-               /* everything off, dac mute, inactive */
                wm8731_write(codec, WM8731_ACTIVE, 0x0);
                wm8731_write(codec, WM8731_PWR, 0xffff);
                break;
@@ -446,6 +433,15 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8731_dai_ops = {
+       .prepare        = wm8731_pcm_prepare,
+       .hw_params      = wm8731_hw_params,
+       .shutdown       = wm8731_shutdown,
+       .digital_mute   = wm8731_mute,
+       .set_sysclk     = wm8731_set_dai_sysclk,
+       .set_fmt        = wm8731_set_dai_fmt,
+};
+
 struct snd_soc_dai wm8731_dai = {
        .name = "WM8731",
        .playback = {
@@ -460,21 +456,14 @@ struct snd_soc_dai wm8731_dai = {
                .channels_max = 2,
                .rates = WM8731_RATES,
                .formats = WM8731_FORMATS,},
-       .ops = {
-               .prepare = wm8731_pcm_prepare,
-               .hw_params = wm8731_hw_params,
-               .shutdown = wm8731_shutdown,
-               .digital_mute = wm8731_mute,
-               .set_sysclk = wm8731_set_dai_sysclk,
-               .set_fmt = wm8731_set_dai_fmt,
-       }
+       .ops = &wm8731_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8731_dai);
 
 static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8731_write(codec, WM8731_ACTIVE, 0x0);
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -484,7 +473,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8731_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -500,54 +489,33 @@ static int wm8731_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the WM8731 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8731_init(struct snd_soc_device *socdev)
+static int wm8731_probe(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
-       int reg, ret = 0;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
 
-       codec->name = "WM8731";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8731_read_reg_cache;
-       codec->write = wm8731_write;
-       codec->set_bias_level = wm8731_set_bias_level;
-       codec->dai = &wm8731_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8731_reg);
-       codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       if (wm8731_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
 
-       wm8731_reset(codec);
+       socdev->card->codec = wm8731_codec;
+       codec = wm8731_codec;
 
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if (ret < 0) {
-               printk(KERN_ERR "wm8731: failed to create pcms\n");
+               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
                goto pcm_err;
        }
 
-       /* power on device */
-       wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* set the update bits */
-       reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
-       wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
-       reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
-       wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
-       reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
-       wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
-       reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
-       wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
-
-       wm8731_add_controls(codec);
+       snd_soc_add_controls(codec, wm8731_snd_controls,
+                            ARRAY_SIZE(wm8731_snd_controls));
        wm8731_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
-               printk(KERN_ERR "wm8731: failed to register card\n");
+               dev_err(codec->dev, "failed to register card: %d\n", ret);
                goto card_err;
        }
 
@@ -557,133 +525,109 @@ card_err:
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 pcm_err:
-       kfree(codec->reg_cache);
        return ret;
 }
 
-static struct snd_soc_device *wm8731_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8731 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-
-static int wm8731_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+/* power down chip */
+static int wm8731_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = wm8731_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int ret;
-
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
-
-       ret = wm8731_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise WM8731\n");
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 
-       return ret;
-}
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
 
-static int wm8731_i2c_remove(struct i2c_client *client)
-{
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
        return 0;
 }
 
-static const struct i2c_device_id wm8731_i2c_id[] = {
-       { "wm8731", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
-
-static struct i2c_driver wm8731_i2c_driver = {
-       .driver = {
-               .name = "WM8731 I2C Codec",
-               .owner = THIS_MODULE,
-       },
-       .probe =    wm8731_i2c_probe,
-       .remove =   wm8731_i2c_remove,
-       .id_table = wm8731_i2c_id,
+struct snd_soc_codec_device soc_codec_dev_wm8731 = {
+       .probe =        wm8731_probe,
+       .remove =       wm8731_remove,
+       .suspend =      wm8731_suspend,
+       .resume =       wm8731_resume,
 };
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 
-static int wm8731_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8731_setup_data *setup)
+static int wm8731_register(struct wm8731_priv *wm8731)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
        int ret;
+       struct snd_soc_codec *codec = &wm8731->codec;
+       u16 reg;
 
-       ret = i2c_add_driver(&wm8731_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
+       if (wm8731_codec) {
+               dev_err(codec->dev, "Another WM8731 is registered\n");
+               return -EINVAL;
        }
 
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
 
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
+       codec->private_data = wm8731;
+       codec->name = "WM8731";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8731_read_reg_cache;
+       codec->write = wm8731_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8731_set_bias_level;
+       codec->dai = &wm8731_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8731_CACHEREGNUM;
+       codec->reg_cache = &wm8731->reg_cache;
 
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
+       memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
+
+       ret = wm8731_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
-       return 0;
+       wm8731_dai.dev = codec->dev;
 
-err_driver:
-       i2c_del_driver(&wm8731_i2c_driver);
-       return -ENODEV;
-}
-#endif
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8731_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8731_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int ret;
+       /* Latch the update bits */
+       reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
+       wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
+       reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
+       wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
+       reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
+       wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
+       reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
+       wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
 
-       codec->control_data = spi;
+       /* Disable bypass path by default */
+       reg = wm8731_read_reg_cache(codec, WM8731_APANA);
+       wm8731_write(codec, WM8731_APANA, reg & ~0x4);
 
-       ret = wm8731_init(socdev);
-       if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8731\n");
+       wm8731_codec = codec;
 
-       return ret;
-}
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8731_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
 
-static int __devexit wm8731_spi_remove(struct spi_device *spi)
-{
        return 0;
 }
 
-static struct spi_driver wm8731_spi_driver = {
-       .driver = {
-               .name   = "wm8731",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
-       },
-       .probe          = wm8731_spi_probe,
-       .remove         = __devexit_p(wm8731_spi_remove),
-};
+static void wm8731_unregister(struct wm8731_priv *wm8731)
+{
+       wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8731_dai);
+       snd_soc_unregister_codec(&wm8731->codec);
+       kfree(wm8731);
+       wm8731_codec = NULL;
+}
 
+#if defined(CONFIG_SPI_MASTER)
 static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
 {
        struct spi_transfer t;
@@ -707,101 +651,121 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
 
        return len;
 }
-#endif /* CONFIG_SPI_MASTER */
 
-static int wm8731_probe(struct platform_device *pdev)
+static int __devinit wm8731_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8731_setup_data *setup;
        struct snd_soc_codec *codec;
        struct wm8731_priv *wm8731;
-       int ret = 0;
-
-       pr_info("WM8731 Audio Codec %s", WM8731_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
 
        wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
-       if (wm8731 == NULL) {
-               kfree(codec);
+       if (wm8731 == NULL)
                return -ENOMEM;
-       }
 
-       codec->private_data = wm8731;
-       socdev->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
+       codec = &wm8731->codec;
+       codec->control_data = spi;
+       codec->hw_write = (hw_write_t)wm8731_spi_write;
+       codec->dev = &spi->dev;
 
-       wm8731_socdev = socdev;
-       ret = -ENODEV;
+       spi->dev.driver_data = wm8731;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = wm8731_add_i2c_device(pdev, setup);
-       }
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               codec->hw_write = (hw_write_t)wm8731_spi_write;
-               ret = spi_register_driver(&wm8731_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
-       }
-#endif
-
-       if (ret != 0) {
-               kfree(codec->private_data);
-               kfree(codec);
-       }
-       return ret;
+       return wm8731_register(wm8731);
 }
 
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
+static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct wm8731_priv *wm8731 = spi->dev.driver_data;
 
-       if (codec->control_data)
-               wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       wm8731_unregister(wm8731);
+
+       return 0;
+}
+
+static struct spi_driver wm8731_spi_driver = {
+       .driver = {
+               .name   = "wm8731",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8731_spi_probe,
+       .remove         = __devexit_p(wm8731_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
-       i2c_del_driver(&wm8731_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&wm8731_spi_driver);
-#endif
-       kfree(codec->private_data);
-       kfree(codec);
+static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8731_priv *wm8731;
+       struct snd_soc_codec *codec;
+
+       wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+       if (wm8731 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8731->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
 
+       i2c_set_clientdata(i2c, wm8731);
+       codec->control_data = i2c;
+
+       codec->dev = &i2c->dev;
+
+       return wm8731_register(wm8731);
+}
+
+static __devexit int wm8731_i2c_remove(struct i2c_client *client)
+{
+       struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
+       wm8731_unregister(wm8731);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
-       .probe =        wm8731_probe,
-       .remove =       wm8731_remove,
-       .suspend =      wm8731_suspend,
-       .resume =       wm8731_resume,
+static const struct i2c_device_id wm8731_i2c_id[] = {
+       { "wm8731", 0 },
+       { }
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
+MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
+
+static struct i2c_driver wm8731_i2c_driver = {
+       .driver = {
+               .name = "WM8731 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8731_i2c_probe,
+       .remove =   __devexit_p(wm8731_i2c_remove),
+       .id_table = wm8731_i2c_id,
+};
+#endif
 
 static int __init wm8731_modinit(void)
 {
-       return snd_soc_register_dai(&wm8731_dai);
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8731_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8731_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
 }
 module_init(wm8731_modinit);
 
 static void __exit wm8731_exit(void)
 {
-       snd_soc_unregister_dai(&wm8731_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8731_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8731_spi_driver);
+#endif
 }
 module_exit(wm8731_exit);
 
index 95190e9c0c145f32c2a0e9a1bd681d86e84e4181..cd7b806e8ad0b745db1116f40b1682733f8d1780 100644 (file)
 #define WM8731_SYSCLK  0
 #define WM8731_DAI             0
 
-struct wm8731_setup_data {
-       int            spi;
-       int            i2c_bus;
-       unsigned short i2c_address;
-};
-
 extern struct snd_soc_dai wm8731_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8731;
 
index 5997fa68e0d58f08c1fb5af468e953bbb2a64ded..b64509b01a49645f847d91fbcf1f051e1248f53b 100644 (file)
@@ -231,21 +231,6 @@ SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
 
 };
 
-/* add non dapm controls */
-static int wm8750_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8750_snd_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /*
  * DAPM Controls
  */
@@ -619,7 +604,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8750_priv *wm8750 = codec->private_data;
        u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3;
        u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0;
@@ -694,6 +679,13 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
 #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8750_dai_ops = {
+       .hw_params      = wm8750_pcm_hw_params,
+       .digital_mute   = wm8750_mute,
+       .set_fmt        = wm8750_set_dai_fmt,
+       .set_sysclk     = wm8750_set_dai_sysclk,
+};
+
 struct snd_soc_dai wm8750_dai = {
        .name = "WM8750",
        .playback = {
@@ -708,12 +700,7 @@ struct snd_soc_dai wm8750_dai = {
                .channels_max = 2,
                .rates = WM8750_RATES,
                .formats = WM8750_FORMATS,},
-       .ops = {
-               .hw_params = wm8750_pcm_hw_params,
-               .digital_mute = wm8750_mute,
-               .set_fmt = wm8750_set_dai_fmt,
-               .set_sysclk = wm8750_set_dai_sysclk,
-       },
+       .ops = &wm8750_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8750_dai);
 
@@ -727,7 +714,7 @@ static void wm8750_work(struct work_struct *work)
 static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -736,7 +723,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8750_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -769,7 +756,7 @@ static int wm8750_resume(struct platform_device *pdev)
  */
 static int wm8750_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int reg, ret = 0;
 
        codec->name = "WM8750";
@@ -816,7 +803,8 @@ static int wm8750_init(struct snd_soc_device *socdev)
        reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
        wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
 
-       wm8750_add_controls(codec);
+       snd_soc_add_controls(codec, wm8750_snd_controls,
+                               ARRAY_SIZE(wm8750_snd_controls));
        wm8750_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -850,7 +838,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8750_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -931,7 +919,7 @@ err_driver:
 static int __devinit wm8750_spi_probe(struct spi_device *spi)
 {
        struct snd_soc_device *socdev = wm8750_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        codec->control_data = spi;
@@ -1003,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev)
        }
 
        codec->private_data = wm8750;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1057,7 +1045,7 @@ static int run_delayed_work(struct delayed_work *dwork)
 static int wm8750_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
index 77620ab9875618f9217e8a6479b61478300c5ecf..a6e8f3f7f052ee4dc45b8ef4540f4cf31c9f411e 100644 (file)
@@ -51,8 +51,6 @@
 
 #include "wm8753.h"
 
-#define WM8753_VERSION "0.16"
-
 static int caps_charge = 2000;
 module_param(caps_charge, int, 0);
 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
@@ -60,12 +58,6 @@ MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
 static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
        unsigned int mode);
 
-/* codec private data */
-struct wm8753_priv {
-       unsigned int sysclk;
-       unsigned int pcmclk;
-};
-
 /*
  * wm8753 register cache
  * We can't read the WM8753 register space when we
@@ -90,6 +82,14 @@ static const u16 wm8753_reg[] = {
        0x0000, 0x0000
 };
 
+/* codec private data */
+struct wm8753_priv {
+       unsigned int sysclk;
+       unsigned int pcmclk;
+       struct snd_soc_codec codec;
+       u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+};
+
 /*
  * read wm8753 register cache
  */
@@ -97,7 +97,7 @@ static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1))
+       if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
                return -1;
        return cache[reg - 1];
 }
@@ -109,7 +109,7 @@ static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg, unsigned int value)
 {
        u16 *cache = codec->reg_cache;
-       if (reg < 1 || reg > 0x3f)
+       if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
                return;
        cache[reg - 1] = value;
 }
@@ -339,21 +339,6 @@ SOC_ENUM("ADC Data Select", wm8753_enum[27]),
 SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
 };
 
-/* add non dapm controls */
-static int wm8753_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8753_snd_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /*
  * _DAPM_ Controls
  */
@@ -927,7 +912,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8753_priv *wm8753 = codec->private_data;
        u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,7 +1146,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8753_priv *wm8753 = codec->private_data;
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
        u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1316,6 +1301,51 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
  * 3. Voice disabled - HIFI over HIFI
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+       .hw_params      = wm8753_i2s_hw_params,
+       .digital_mute   = wm8753_mute,
+       .set_fmt        = wm8753_mode1h_set_dai_fmt,
+       .set_clkdiv     = wm8753_set_dai_clkdiv,
+       .set_pll        = wm8753_set_dai_pll,
+       .set_sysclk     = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+       .hw_params      = wm8753_pcm_hw_params,
+       .digital_mute   = wm8753_mute,
+       .set_fmt        = wm8753_mode1v_set_dai_fmt,
+       .set_clkdiv     = wm8753_set_dai_clkdiv,
+       .set_pll        = wm8753_set_dai_pll,
+       .set_sysclk     = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+       .hw_params      = wm8753_pcm_hw_params,
+       .digital_mute   = wm8753_mute,
+       .set_fmt        = wm8753_mode2_set_dai_fmt,
+       .set_clkdiv     = wm8753_set_dai_clkdiv,
+       .set_pll        = wm8753_set_dai_pll,
+       .set_sysclk     = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3        = {
+       .hw_params      = wm8753_i2s_hw_params,
+       .digital_mute   = wm8753_mute,
+       .set_fmt        = wm8753_mode3_4_set_dai_fmt,
+       .set_clkdiv     = wm8753_set_dai_clkdiv,
+       .set_pll        = wm8753_set_dai_pll,
+       .set_sysclk     = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4        = {
+       .hw_params      = wm8753_i2s_hw_params,
+       .digital_mute   = wm8753_mute,
+       .set_fmt        = wm8753_mode3_4_set_dai_fmt,
+       .set_clkdiv     = wm8753_set_dai_clkdiv,
+       .set_pll        = wm8753_set_dai_pll,
+       .set_sysclk     = wm8753_set_dai_sysclk,
+};
+
 static const struct snd_soc_dai wm8753_all_dai[] = {
 /* DAI HiFi mode 1 */
 {      .name = "WM8753 HiFi",
@@ -1332,14 +1362,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
                .channels_max = 2,
                .rates = WM8753_RATES,
                .formats = WM8753_FORMATS},
-       .ops = {
-               .hw_params = wm8753_i2s_hw_params,
-               .digital_mute = wm8753_mute,
-               .set_fmt = wm8753_mode1h_set_dai_fmt,
-               .set_clkdiv = wm8753_set_dai_clkdiv,
-               .set_pll = wm8753_set_dai_pll,
-               .set_sysclk = wm8753_set_dai_sysclk,
-       },
+       .ops = &wm8753_dai_ops_hifi_mode1,
 },
 /* DAI Voice mode 1 */
 {      .name = "WM8753 Voice",
@@ -1356,14 +1379,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
                .channels_max = 2,
                .rates = WM8753_RATES,
                .formats = WM8753_FORMATS,},
-       .ops = {
-               .hw_params = wm8753_pcm_hw_params,
-               .digital_mute = wm8753_mute,
-               .set_fmt = wm8753_mode1v_set_dai_fmt,
-               .set_clkdiv = wm8753_set_dai_clkdiv,
-               .set_pll = wm8753_set_dai_pll,
-               .set_sysclk = wm8753_set_dai_sysclk,
-       },
+       .ops = &wm8753_dai_ops_voice_mode1,
 },
 /* DAI HiFi mode 2 - dummy */
 {      .name = "WM8753 HiFi",
@@ -1384,14 +1400,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
                .channels_max = 2,
                .rates = WM8753_RATES,
                .formats = WM8753_FORMATS,},
-       .ops = {
-               .hw_params = wm8753_pcm_hw_params,
-               .digital_mute = wm8753_mute,
-               .set_fmt = wm8753_mode2_set_dai_fmt,
-               .set_clkdiv = wm8753_set_dai_clkdiv,
-               .set_pll = wm8753_set_dai_pll,
-               .set_sysclk = wm8753_set_dai_sysclk,
-       },
+       .ops = &wm8753_dai_ops_voice_mode2,
 },
 /* DAI HiFi mode 3 */
 {      .name = "WM8753 HiFi",
@@ -1408,14 +1417,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
                .channels_max = 2,
                .rates = WM8753_RATES,
                .formats = WM8753_FORMATS,},
-       .ops = {
-               .hw_params = wm8753_i2s_hw_params,
-               .digital_mute = wm8753_mute,
-               .set_fmt = wm8753_mode3_4_set_dai_fmt,
-               .set_clkdiv = wm8753_set_dai_clkdiv,
-               .set_pll = wm8753_set_dai_pll,
-               .set_sysclk = wm8753_set_dai_sysclk,
-       },
+       .ops = &wm8753_dai_ops_hifi_mode3,
 },
 /* DAI Voice mode 3 - dummy */
 {      .name = "WM8753 Voice",
@@ -1436,14 +1438,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
                .channels_max = 2,
                .rates = WM8753_RATES,
                .formats = WM8753_FORMATS,},
-       .ops = {
-               .hw_params = wm8753_i2s_hw_params,
-               .digital_mute = wm8753_mute,
-               .set_fmt = wm8753_mode3_4_set_dai_fmt,
-               .set_clkdiv = wm8753_set_dai_clkdiv,
-               .set_pll = wm8753_set_dai_pll,
-               .set_sysclk = wm8753_set_dai_sysclk,
-       },
+       .ops = &wm8753_dai_ops_hifi_mode4,
 },
 /* DAI Voice mode 4 - dummy */
 {      .name = "WM8753 Voice",
@@ -1466,30 +1461,35 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
        if (mode < 4) {
                int playback_active, capture_active, codec_active, pop_wait;
                void *private_data;
+               struct list_head list;
 
                playback_active = wm8753_dai[0].playback.active;
                capture_active = wm8753_dai[0].capture.active;
                codec_active = wm8753_dai[0].active;
                private_data = wm8753_dai[0].private_data;
                pop_wait = wm8753_dai[0].pop_wait;
+               list = wm8753_dai[0].list;
                wm8753_dai[0] = wm8753_all_dai[mode << 1];
                wm8753_dai[0].playback.active = playback_active;
                wm8753_dai[0].capture.active = capture_active;
                wm8753_dai[0].active = codec_active;
                wm8753_dai[0].private_data = private_data;
                wm8753_dai[0].pop_wait = pop_wait;
+               wm8753_dai[0].list = list;
 
                playback_active = wm8753_dai[1].playback.active;
                capture_active = wm8753_dai[1].capture.active;
                codec_active = wm8753_dai[1].active;
                private_data = wm8753_dai[1].private_data;
                pop_wait = wm8753_dai[1].pop_wait;
+               list = wm8753_dai[1].list;
                wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
                wm8753_dai[1].playback.active = playback_active;
                wm8753_dai[1].capture.active = capture_active;
                wm8753_dai[1].active = codec_active;
                wm8753_dai[1].private_data = private_data;
                wm8753_dai[1].pop_wait = pop_wait;
+               wm8753_dai[1].list = list;
        }
        wm8753_dai[0].codec = codec;
        wm8753_dai[1].codec = codec;
@@ -1505,7 +1505,7 @@ static void wm8753_work(struct work_struct *work)
 static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* we only need to suspend if we are a valid card */
        if (!codec->card)
@@ -1518,7 +1518,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8753_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1531,6 +1531,11 @@ static int wm8753_resume(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
                if (i + 1 == WM8753_RESET)
                        continue;
+
+               /* No point in writing hardware default values back */
+               if (cache[i] == wm8753_reg[i])
+                       continue;
+
                data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
@@ -1549,44 +1554,129 @@ static int wm8753_resume(struct platform_device *pdev)
        return 0;
 }
 
+static struct snd_soc_codec *wm8753_codec;
+
+static int wm8753_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (!wm8753_codec) {
+               dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
+               return -EINVAL;
+       }
+
+       socdev->card->codec = wm8753_codec;
+       codec = wm8753_codec;
+
+       wm8753_set_dai_mode(codec, 0);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8753: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       snd_soc_add_controls(codec, wm8753_snd_controls,
+                            ARRAY_SIZE(wm8753_snd_controls));
+       wm8753_add_widgets(codec);
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8753: failed to register card\n");
+               goto card_err;
+       }
+
+       return 0;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+pcm_err:
+       return ret;
+}
+
 /*
- * initialise the WM8753 driver
- * register the mixer and dsp interfaces with the kernel
+ * This function forces any delayed work to be queued and run.
  */
-static int wm8753_init(struct snd_soc_device *socdev)
+static int run_delayed_work(struct delayed_work *dwork)
+{
+       int ret;
+
+       /* cancel any work waiting to be queued. */
+       ret = cancel_delayed_work(dwork);
+
+       /* if there was any work waiting then we run it now and
+        * wait for it's completion */
+       if (ret) {
+               schedule_delayed_work(dwork, 0);
+               flush_scheduled_work();
+       }
+       return ret;
+}
+
+/* power down chip */
+static int wm8753_remove(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
-       int reg, ret = 0;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8753 = {
+       .probe =        wm8753_probe,
+       .remove =       wm8753_remove,
+       .suspend =      wm8753_suspend,
+       .resume =       wm8753_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+
+static int wm8753_register(struct wm8753_priv *wm8753)
+{
+       int ret, i;
+       struct snd_soc_codec *codec = &wm8753->codec;
+       u16 reg;
+
+       if (wm8753_codec) {
+               dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
 
        codec->name = "WM8753";
        codec->owner = THIS_MODULE;
        codec->read = wm8753_read_reg_cache;
        codec->write = wm8753_write;
+       codec->bias_level = SND_SOC_BIAS_STANDBY;
        codec->set_bias_level = wm8753_set_bias_level;
        codec->dai = wm8753_dai;
        codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8753_reg);
-       codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
-
-       wm8753_set_dai_mode(codec, 0);
+       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache);
+       codec->reg_cache = &wm8753->reg_cache;
+       codec->private_data = wm8753;
 
-       wm8753_reset(codec);
+       memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache));
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8753_reset(codec);
        if (ret < 0) {
-               printk(KERN_ERR "wm8753: failed to create pcms\n");
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err;
        }
 
        /* charge output caps */
        wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
        schedule_delayed_work(&codec->delayed_work,
-               msecs_to_jiffies(caps_charge));
+                             msecs_to_jiffies(caps_charge));
 
        /* set the update bits */
        reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
@@ -1610,59 +1700,70 @@ static int wm8753_init(struct snd_soc_device *socdev)
        reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
        wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
 
-       wm8753_add_controls(codec);
-       wm8753_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8753: failed to register card\n");
-               goto card_err;
+       wm8753_codec = codec;
+
+       for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
+               wm8753_dai[i].dev = codec->dev;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               goto err;
        }
 
-       return ret;
+       ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+               goto err_codec;
+       }
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-pcm_err:
-       kfree(codec->reg_cache);
+       return 0;
+
+err_codec:
+       run_delayed_work(&codec->delayed_work);
+       snd_soc_unregister_codec(codec);
+err:
+       kfree(wm8753);
        return ret;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8753_socdev;
+static void wm8753_unregister(struct wm8753_priv *wm8753)
+{
+       wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
+       run_delayed_work(&wm8753->codec.delayed_work);
+       snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
+       snd_soc_unregister_codec(&wm8753->codec);
+       kfree(wm8753);
+       wm8753_codec = NULL;
+}
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-/*
- * WM8753 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-
 static int wm8753_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8753_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int ret;
+       struct snd_soc_codec *codec;
+       struct wm8753_priv *wm8753;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
+       if (wm8753 == NULL)
+               return -ENOMEM;
 
-       ret = wm8753_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise WM8753\n");
+        codec = &wm8753->codec;
+        codec->hw_write = (hw_write_t)i2c_master_send;
+        codec->control_data = i2c;
+        i2c_set_clientdata(i2c, wm8753);
 
-       return ret;
+        codec->dev = &i2c->dev;
+
+       return wm8753_register(wm8753);
 }
 
 static int wm8753_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
-       return 0;
+        struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
+        wm8753_unregister(wm8753);
+        return 0;
 }
 
 static const struct i2c_device_id wm8753_i2c_id[] = {
@@ -1673,86 +1774,16 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
 
 static struct i2c_driver wm8753_i2c_driver = {
        .driver = {
-               .name = "WM8753 I2C Codec",
+               .name = "wm8753",
                .owner = THIS_MODULE,
        },
        .probe =    wm8753_i2c_probe,
        .remove =   wm8753_i2c_remove,
        .id_table = wm8753_i2c_id,
 };
-
-static int wm8753_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8753_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&wm8753_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8753", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8753_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
 #if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8753_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
-       int ret;
-
-       codec->control_data = spi;
-
-       ret = wm8753_init(socdev);
-       if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8753\n");
-
-       return ret;
-}
-
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
-static struct spi_driver wm8753_spi_driver = {
-       .driver = {
-               .name   = "wm8753",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
-       },
-       .probe          = wm8753_spi_probe,
-       .remove         = __devexit_p(wm8753_spi_remove),
-};
-
 static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
 {
        struct spi_transfer t;
@@ -1776,120 +1807,69 @@ static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
 
        return len;
 }
-#endif
 
-
-static int wm8753_probe(struct platform_device *pdev)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8753_setup_data *setup;
        struct snd_soc_codec *codec;
        struct wm8753_priv *wm8753;
-       int ret = 0;
-
-       pr_info("WM8753 Audio Codec %s", WM8753_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
 
        wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
-       if (wm8753 == NULL) {
-               kfree(codec);
+       if (wm8753 == NULL)
                return -ENOMEM;
-       }
 
-       codec->private_data = wm8753;
-       socdev->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8753_socdev = socdev;
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
+       codec = &wm8753->codec;
+       codec->control_data = spi;
+       codec->hw_write = (hw_write_t)wm8753_spi_write;
+       codec->dev = &spi->dev;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = wm8753_add_i2c_device(pdev, setup);
-       }
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               codec->hw_write = (hw_write_t)wm8753_spi_write;
-               ret = spi_register_driver(&wm8753_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
-       }
-#endif
+       spi->dev.driver_data = wm8753;
 
-       if (ret != 0) {
-               kfree(codec->private_data);
-               kfree(codec);
-       }
-       return ret;
+       return wm8753_register(wm8753);
 }
 
-/*
- * This function forces any delayed work to be queued and run.
- */
-static int run_delayed_work(struct delayed_work *dwork)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
-       int ret;
-
-       /* cancel any work waiting to be queued. */
-       ret = cancel_delayed_work(dwork);
-
-       /* if there was any work waiting then we run it now and
-        * wait for it's completion */
-       if (ret) {
-               schedule_delayed_work(dwork, 0);
-               flush_scheduled_work();
-       }
-       return ret;
+       struct wm8753_priv *wm8753 = spi->dev.driver_data;
+       wm8753_unregister(wm8753);
+       return 0;
 }
 
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+static struct spi_driver wm8753_spi_driver = {
+       .driver = {
+               .name   = "wm8753",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8753_spi_probe,
+       .remove         = __devexit_p(wm8753_spi_remove),
+};
+#endif
 
-       if (codec->control_data)
-               wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       run_delayed_work(&codec->delayed_work);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+static int __init wm8753_modinit(void)
+{
+       int ret;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
-       i2c_del_driver(&wm8753_i2c_driver);
+       ret = i2c_add_driver(&wm8753_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
 #endif
 #if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&wm8753_spi_driver);
+       ret = spi_register_driver(&wm8753_spi_driver);
+       if (ret != 0)
+               pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
 #endif
-       kfree(codec->private_data);
-       kfree(codec);
-
        return 0;
 }
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
-       .probe =        wm8753_probe,
-       .remove =       wm8753_remove,
-       .suspend =      wm8753_suspend,
-       .resume =       wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
-
-static int __init wm8753_modinit(void)
-{
-       return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
-}
 module_init(wm8753_modinit);
 
 static void __exit wm8753_exit(void)
 {
-       snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8753_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8753_spi_driver);
+#endif
 }
 module_exit(wm8753_exit);
 
index f55704ce931b44e135b8038967eaebf751dbf632..57b2ba244040dea6a26e806c57401cd22a27ebf3 100644 (file)
 #define WM8753_BIASCTL         0x3d
 #define WM8753_ADCTL2          0x3f
 
-struct wm8753_setup_data {
-       int spi;
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
 #define WM8753_PLL1                    0
 #define WM8753_PLL2                    1
 
index 6767de10ded0a64ff008e7c1d039d42569b9a4e4..46c5ea1ff921aea8c3f6be8fd13ed7bd8de1f897 100644 (file)
@@ -517,22 +517,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
 
 };
 
-/* add non dapm controls */
-static int wm8900_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8900_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
 SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
 
@@ -736,7 +720,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1104,6 +1088,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
         SNDRV_PCM_FORMAT_S24_LE)
 
+static struct snd_soc_dai_ops wm8900_dai_ops = {
+       .hw_params      = wm8900_hw_params,
+       .set_clkdiv     = wm8900_set_dai_clkdiv,
+       .set_pll        = wm8900_set_dai_pll,
+       .set_fmt        = wm8900_set_dai_fmt,
+       .digital_mute   = wm8900_digital_mute,
+};
+
 struct snd_soc_dai wm8900_dai = {
        .name = "WM8900 HiFi",
        .playback = {
@@ -1120,13 +1112,7 @@ struct snd_soc_dai wm8900_dai = {
                .rates = WM8900_RATES,
                .formats = WM8900_PCM_FORMATS,
         },
-       .ops = {
-               .hw_params = wm8900_hw_params,
-                .set_clkdiv = wm8900_set_dai_clkdiv,
-                .set_pll = wm8900_set_dai_pll,
-                .set_fmt = wm8900_set_dai_fmt,
-                .digital_mute = wm8900_digital_mute,
-        },
+       .ops = &wm8900_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8900_dai);
 
@@ -1226,7 +1212,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
 static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = codec->private_data;
        int fll_out = wm8900->fll_out;
        int fll_in  = wm8900->fll_in;
@@ -1250,7 +1236,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8900_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = codec->private_data;
        u16 *cache;
        int i, ret;
@@ -1288,8 +1274,8 @@ static int wm8900_resume(struct platform_device *pdev)
 
 static struct snd_soc_codec *wm8900_codec;
 
-static int wm8900_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8900_priv *wm8900;
        struct snd_soc_codec *codec;
@@ -1388,7 +1374,7 @@ err:
        return ret;
 }
 
-static int wm8900_i2c_remove(struct i2c_client *client)
+static __devexit int wm8900_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_dai(&wm8900_dai);
        snd_soc_unregister_codec(wm8900_codec);
@@ -1414,7 +1400,7 @@ static struct i2c_driver wm8900_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe = wm8900_i2c_probe,
-       .remove = wm8900_i2c_remove,
+       .remove = __devexit_p(wm8900_i2c_remove),
        .id_table = wm8900_i2c_id,
 };
 
@@ -1430,7 +1416,7 @@ static int wm8900_probe(struct platform_device *pdev)
        }
 
        codec = wm8900_codec;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
 
        /* Register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -1439,7 +1425,8 @@ static int wm8900_probe(struct platform_device *pdev)
                goto pcm_err;
        }
 
-       wm8900_add_controls(codec);
+       snd_soc_add_controls(codec, wm8900_snd_controls,
+                               ARRAY_SIZE(wm8900_snd_controls));
        wm8900_add_widgets(codec);
 
        ret = snd_soc_init_card(socdev);
index bde74546db4a7050ee28e1617dc190390822fcc1..8cf571f1a803d3ae7b1b1e561aedb01470cc19dd 100644 (file)
@@ -744,21 +744,6 @@ SOC_DOUBLE_R_TLV("Speaker Volume",
                 0, 63, 0, out_tlv),
 };
 
-static int wm8903_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm8903_snd_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 static const struct snd_kcontrol_new linput_mode_mux =
        SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
 
@@ -1276,7 +1261,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8903_priv *wm8903 = codec->private_data;
        struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
@@ -1318,7 +1303,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8903_priv *wm8903 = codec->private_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1338,7 +1323,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8903_priv *wm8903 = codec->private_data;
        struct i2c_client *i2c = codec->control_data;
        int fs = params_rate(params);
@@ -1512,6 +1497,15 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                        SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8903_dai_ops = {
+       .startup        = wm8903_startup,
+       .shutdown       = wm8903_shutdown,
+       .hw_params      = wm8903_hw_params,
+       .digital_mute   = wm8903_digital_mute,
+       .set_fmt        = wm8903_set_dai_fmt,
+       .set_sysclk     = wm8903_set_dai_sysclk,
+};
+
 struct snd_soc_dai wm8903_dai = {
        .name = "WM8903",
        .playback = {
@@ -1528,21 +1522,14 @@ struct snd_soc_dai wm8903_dai = {
                 .rates = WM8903_CAPTURE_RATES,
                 .formats = WM8903_FORMATS,
         },
-       .ops = {
-                .startup = wm8903_startup,
-                .shutdown = wm8903_shutdown,
-                .hw_params = wm8903_hw_params,
-                .digital_mute = wm8903_digital_mute,
-                .set_fmt = wm8903_set_dai_fmt,
-                .set_sysclk = wm8903_set_dai_sysclk
-       }
+       .ops = &wm8903_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8903_dai);
 
 static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1552,7 +1539,7 @@ static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8903_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct i2c_client *i2c = codec->control_data;
        int i;
        u16 *reg_cache = codec->reg_cache;
@@ -1577,8 +1564,8 @@ static int wm8903_resume(struct platform_device *pdev)
 
 static struct snd_soc_codec *wm8903_codec;
 
-static int wm8903_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8903_priv *wm8903;
        struct snd_soc_codec *codec;
@@ -1684,7 +1671,7 @@ err:
        return ret;
 }
 
-static int wm8903_i2c_remove(struct i2c_client *client)
+static __devexit int wm8903_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
 
@@ -1714,7 +1701,7 @@ static struct i2c_driver wm8903_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe    = wm8903_i2c_probe,
-       .remove   = wm8903_i2c_remove,
+       .remove   = __devexit_p(wm8903_i2c_remove),
        .id_table = wm8903_i2c_id,
 };
 
@@ -1728,7 +1715,7 @@ static int wm8903_probe(struct platform_device *pdev)
                goto err;
        }
 
-       socdev->codec = wm8903_codec;
+       socdev->card->codec = wm8903_codec;
 
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -1737,8 +1724,9 @@ static int wm8903_probe(struct platform_device *pdev)
                goto err;
        }
 
-       wm8903_add_controls(socdev->codec);
-       wm8903_add_widgets(socdev->codec);
+       snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
+                               ARRAY_SIZE(wm8903_snd_controls));
+       wm8903_add_widgets(socdev->card->codec);
 
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -1759,7 +1747,7 @@ err:
 static int wm8903_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
index 88ead7f8dd98007cf4b909a06b30679ff65721d3..032dca22dbd3dce34746a3e3bc65717c051c7501 100644 (file)
@@ -195,21 +195,6 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = {
        SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
 };
 
-/* add non-DAPM controls */
-static int wm8971_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8971_snd_controls[i],
-                                            codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /*
  * DAPM Controls
  */
@@ -546,7 +531,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8971_priv *wm8971 = codec->private_data;
        u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
        u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
@@ -619,6 +604,13 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
 #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
+static struct snd_soc_dai_ops wm8971_dai_ops = {
+       .hw_params      = wm8971_pcm_hw_params,
+       .digital_mute   = wm8971_mute,
+       .set_fmt        = wm8971_set_dai_fmt,
+       .set_sysclk     = wm8971_set_dai_sysclk,
+};
+
 struct snd_soc_dai wm8971_dai = {
        .name = "WM8971",
        .playback = {
@@ -633,12 +625,7 @@ struct snd_soc_dai wm8971_dai = {
                .channels_max = 2,
                .rates = WM8971_RATES,
                .formats = WM8971_FORMATS,},
-       .ops = {
-               .hw_params = wm8971_pcm_hw_params,
-               .digital_mute = wm8971_mute,
-               .set_fmt = wm8971_set_dai_fmt,
-               .set_sysclk = wm8971_set_dai_sysclk,
-       },
+       .ops = &wm8971_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8971_dai);
 
@@ -652,7 +639,7 @@ static void wm8971_work(struct work_struct *work)
 static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -661,7 +648,7 @@ static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8971_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -692,7 +679,7 @@ static int wm8971_resume(struct platform_device *pdev)
 
 static int wm8971_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int reg, ret = 0;
 
        codec->name = "WM8971";
@@ -745,7 +732,8 @@ static int wm8971_init(struct snd_soc_device *socdev)
        reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
        wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
 
-       wm8971_add_controls(codec);
+       snd_soc_add_controls(codec, wm8971_snd_controls,
+                               ARRAY_SIZE(wm8971_snd_controls));
        wm8971_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -772,7 +760,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8971_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -873,7 +861,7 @@ static int wm8971_probe(struct platform_device *pdev)
        }
 
        codec->private_data = wm8971;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -908,7 +896,7 @@ static int wm8971_probe(struct platform_device *pdev)
 static int wm8971_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
index a5731faa150c4fdc6b838e5fc11f9cd801861c70..c518c3e5aa3f8e10409dc16da5b9640610060c17 100644 (file)
@@ -115,7 +115,7 @@ static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
+       BUG_ON(reg >= ARRAY_SIZE(wm8990_reg));
        return cache[reg];
 }
 
@@ -128,7 +128,7 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
        u16 *cache = codec->reg_cache;
 
        /* Reset register and reserved registers are uncached */
-       if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1)
+       if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg))
                return;
 
        cache[reg] = value;
@@ -418,21 +418,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
 
 };
 
-/* add non dapm controls */
-static int wm8990_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8990_snd_controls[i], codec,
-                                       NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /*
  * _DAPM_ Controls
  */
@@ -1178,7 +1163,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1347,6 +1332,15 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
+static struct snd_soc_dai_ops wm8990_dai_ops = {
+       .hw_params      = wm8990_hw_params,
+       .digital_mute   = wm8990_mute,
+       .set_fmt        = wm8990_set_dai_fmt,
+       .set_clkdiv     = wm8990_set_dai_clkdiv,
+       .set_pll        = wm8990_set_dai_pll,
+       .set_sysclk     = wm8990_set_dai_sysclk,
+};
+
 struct snd_soc_dai wm8990_dai = {
 /* ADC/DAC on primary */
        .name = "WM8990 ADC/DAC Primary",
@@ -1363,21 +1357,14 @@ struct snd_soc_dai wm8990_dai = {
                .channels_max = 2,
                .rates = WM8990_RATES,
                .formats = WM8990_FORMATS,},
-       .ops = {
-               .hw_params = wm8990_hw_params,
-               .digital_mute = wm8990_mute,
-               .set_fmt = wm8990_set_dai_fmt,
-               .set_clkdiv = wm8990_set_dai_clkdiv,
-               .set_pll = wm8990_set_dai_pll,
-               .set_sysclk = wm8990_set_dai_sysclk,
-       },
+       .ops = &wm8990_dai_ops,
 };
 EXPORT_SYMBOL_GPL(wm8990_dai);
 
 static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        /* we only need to suspend if we are a valid card */
        if (!codec->card)
@@ -1390,7 +1377,7 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
 static int wm8990_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1418,7 +1405,7 @@ static int wm8990_resume(struct platform_device *pdev)
  */
 static int wm8990_init(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
        int ret = 0;
 
@@ -1461,7 +1448,8 @@ static int wm8990_init(struct snd_soc_device *socdev)
        wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
        wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-       wm8990_add_controls(codec);
+       snd_soc_add_controls(codec, wm8990_snd_controls,
+                               ARRAY_SIZE(wm8990_snd_controls));
        wm8990_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -1495,7 +1483,7 @@ static int wm8990_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8990_socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret;
 
        i2c_set_clientdata(i2c, codec);
@@ -1594,7 +1582,7 @@ static int wm8990_probe(struct platform_device *pdev)
        }
 
        codec->private_data = wm8990;
-       socdev->codec = codec;
+       socdev->card->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1620,7 +1608,7 @@ static int wm8990_probe(struct platform_device *pdev)
 static int wm8990_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec->control_data)
                wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
new file mode 100644 (file)
index 0000000..3265817
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * wm9705.c  --  ALSA Soc WM9705 codec support
+ *
+ * Copyright 2008 Ian Molton <spyro@f2s.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; Version 2 of the  License only.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "wm9705.h"
+
+/*
+ * WM9705 register cache
+ */
+static const u16 wm9705_reg[] = {
+       0x6150, 0x8000, 0x8000, 0x8000, /* 0x0  */
+       0x0000, 0x8000, 0x8008, 0x8008, /* 0x8  */
+       0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */
+       0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */
+       0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */
+       0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */
+       0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */
+       0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */
+       0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */
+       0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */
+};
+
+static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = {
+       SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+       SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+       SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+       SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+       SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+       SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+       SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+       SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+       SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1),
+       SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1),
+       SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1),
+       SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1),
+       SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1),
+       SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0),
+       SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0),
+       SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+};
+
+static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};
+static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",
+       "Line", "Stereo Mix", "Mono Mix", "Phone"};
+
+static const struct soc_enum wm9705_enum_mic =
+       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic);
+static const struct soc_enum wm9705_enum_rec_l =
+       SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel);
+static const struct soc_enum wm9705_enum_rec_r =
+       SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel);
+
+/* Headphone Mixer */
+static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1),
+       SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1),
+       SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1),
+       SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1),
+       SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1),
+};
+
+/* Mic source */
+static const struct snd_kcontrol_new wm9705_mic_src_controls =
+       SOC_DAPM_ENUM("Route", wm9705_enum_mic);
+
+/* Capture source */
+static const struct snd_kcontrol_new wm9705_capture_selectl_controls =
+       SOC_DAPM_ENUM("Route", wm9705_enum_rec_l);
+static const struct snd_kcontrol_new wm9705_capture_selectr_controls =
+       SOC_DAPM_ENUM("Route", wm9705_enum_rec_r);
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0,
+               &wm9705_mic_src_controls),
+       SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,
+               &wm9705_capture_selectl_controls),
+       SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,
+               &wm9705_capture_selectr_controls),
+       SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+               SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+               SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0,
+               &wm9705_hp_mixer_controls[0],
+               ARRAY_SIZE(wm9705_hp_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+       SND_SOC_DAPM_OUTPUT("MONOOUT"),
+       SND_SOC_DAPM_INPUT("PHONE"),
+       SND_SOC_DAPM_INPUT("LINEINL"),
+       SND_SOC_DAPM_INPUT("LINEINR"),
+       SND_SOC_DAPM_INPUT("CDINL"),
+       SND_SOC_DAPM_INPUT("CDINR"),
+       SND_SOC_DAPM_INPUT("PCBEEP"),
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+/* Audio map
+ * WM9705 has no switches to disable the route from the inputs to the HP mixer
+ * so in order to prevent active inputs from forcing the audio outputs to be
+ * constantly enabled, we use the mutes on those inputs to simulate such
+ * controls.
+ */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* HP mixer */
+       {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
+       {"HP Mixer", "CD Playback Switch", "CD PGA"},
+       {"HP Mixer", "Mic Playback Switch", "Mic PGA"},
+       {"HP Mixer", "Phone Playback Switch", "Phone PGA"},
+       {"HP Mixer", "Line Playback Switch", "Line PGA"},
+       {"HP Mixer", NULL, "Left DAC"},
+       {"HP Mixer", NULL, "Right DAC"},
+
+       /* mono mixer */
+       {"Mono Mixer", NULL, "HP Mixer"},
+
+       /* outputs */
+       {"Headphone PGA", NULL, "HP Mixer"},
+       {"HPOUTL", NULL, "Headphone PGA"},
+       {"HPOUTR", NULL, "Headphone PGA"},
+       {"Line out PGA", NULL, "HP Mixer"},
+       {"LOUT", NULL, "Line out PGA"},
+       {"ROUT", NULL, "Line out PGA"},
+       {"Mono PGA", NULL, "Mono Mixer"},
+       {"MONOOUT", NULL, "Mono PGA"},
+
+       /* inputs */
+       {"CD PGA", NULL, "CDINL"},
+       {"CD PGA", NULL, "CDINR"},
+       {"Line PGA", NULL, "LINEINL"},
+       {"Line PGA", NULL, "LINEINR"},
+       {"Phone PGA", NULL, "PHONE"},
+       {"Mic Source", "Mic 1", "MIC1"},
+       {"Mic Source", "Mic 2", "MIC2"},
+       {"Mic PGA", NULL, "Mic Source"},
+       {"PCBEEP PGA", NULL, "PCBEEP"},
+
+       /* Left capture selector */
+       {"Left Capture Source", "Mic", "Mic Source"},
+       {"Left Capture Source", "CD", "CDINL"},
+       {"Left Capture Source", "Line", "LINEINL"},
+       {"Left Capture Source", "Stereo Mix", "HP Mixer"},
+       {"Left Capture Source", "Mono Mix", "HP Mixer"},
+       {"Left Capture Source", "Phone", "PHONE"},
+
+       /* Right capture source */
+       {"Right Capture Source", "Mic", "Mic Source"},
+       {"Right Capture Source", "CD", "CDINR"},
+       {"Right Capture Source", "Line", "LINEINR"},
+       {"Right Capture Source", "Stereo Mix", "HP Mixer"},
+       {"Right Capture Source", "Mono Mix", "HP Mixer"},
+       {"Right Capture Source", "Phone", "PHONE"},
+
+       {"ADC PGA", NULL, "Left Capture Source"},
+       {"ADC PGA", NULL, "Right Capture Source"},
+
+       /* ADC's */
+       {"Left ADC",  NULL, "ADC PGA"},
+       {"Right ADC", NULL, "ADC PGA"},
+};
+
+static int wm9705_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,
+                                       ARRAY_SIZE(wm9705_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_widgets(codec);
+
+       return 0;
+}
+
+/* We use a register cache to enhance read performance. */
+static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       switch (reg) {
+       case AC97_RESET:
+       case AC97_VENDOR_ID1:
+       case AC97_VENDOR_ID2:
+               return soc_ac97_ops.read(codec->ac97, reg);
+       default:
+               reg = reg >> 1;
+
+               if (reg >= (ARRAY_SIZE(wm9705_reg)))
+                       return -EIO;
+
+               return cache[reg];
+       }
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int val)
+{
+       u16 *cache = codec->reg_cache;
+
+       soc_ac97_ops.write(codec->ac97, reg, val);
+       reg = reg >> 1;
+       if (reg < (ARRAY_SIZE(wm9705_reg)))
+               cache[reg] = val;
+
+       return 0;
+}
+
+static int ac97_prepare(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int reg;
+       u16 vra;
+
+       vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+       ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               reg = AC97_PCM_FRONT_DAC_RATE;
+       else
+               reg = AC97_PCM_LR_ADC_RATE;
+
+       return ac97_write(codec, reg, runtime->rate);
+}
+
+#define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
+                       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+                       SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_ops wm9705_dai_ops = {
+       .prepare        = ac97_prepare,
+};
+
+struct snd_soc_dai wm9705_dai[] = {
+       {
+               .name = "AC97 HiFi",
+               .ac97_control = 1,
+               .playback = {
+                       .stream_name = "HiFi Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM9705_AC97_RATES,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                       .stream_name = "HiFi Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM9705_AC97_RATES,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &wm9705_dai_ops,
+       },
+       {
+               .name = "AC97 Aux",
+               .playback = {
+                       .stream_name = "Aux Playback",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = WM9705_AC97_RATES,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       }
+};
+EXPORT_SYMBOL_GPL(wm9705_dai);
+
+static int wm9705_reset(struct snd_soc_codec *codec)
+{
+       if (soc_ac97_ops.reset) {
+               soc_ac97_ops.reset(codec->ac97);
+               if (ac97_read(codec, 0) == wm9705_reg[0])
+                       return 0; /* Success */
+       }
+
+       return -EIO;
+}
+
+static int wm9705_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       printk(KERN_INFO "WM9705 SoC Audio Codec\n");
+
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+                                     GFP_KERNEL);
+       if (socdev->card->codec == NULL)
+               return -ENOMEM;
+       codec = socdev->card->codec;
+       mutex_init(&codec->mutex);
+
+       codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               ret = -ENOMEM;
+               goto cache_err;
+       }
+       codec->reg_cache_size = sizeof(wm9705_reg);
+       codec->reg_cache_step = 2;
+
+       codec->name = "WM9705";
+       codec->owner = THIS_MODULE;
+       codec->dai = wm9705_dai;
+       codec->num_dai = ARRAY_SIZE(wm9705_dai);
+       codec->write = ac97_write;
+       codec->read = ac97_read;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
+               goto codec_err;
+       }
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0)
+               goto pcm_err;
+
+       ret = wm9705_reset(codec);
+       if (ret)
+               goto reset_err;
+
+       snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
+                               ARRAY_SIZE(wm9705_snd_ac97_controls));
+       wm9705_add_widgets(codec);
+
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm9705: failed to register card\n");
+               goto pcm_err;
+       }
+
+       return 0;
+
+reset_err:
+       snd_soc_free_pcms(socdev);
+pcm_err:
+       snd_soc_free_ac97_codec(codec);
+codec_err:
+       kfree(codec->reg_cache);
+cache_err:
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
+       return ret;
+}
+
+static int wm9705_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       if (codec == NULL)
+               return 0;
+
+       snd_soc_dapm_free(socdev);
+       snd_soc_free_pcms(socdev);
+       snd_soc_free_ac97_codec(codec);
+       kfree(codec->reg_cache);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+       .probe =        wm9705_soc_probe,
+       .remove =       wm9705_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+MODULE_DESCRIPTION("ASoC WM9705 driver");
+MODULE_AUTHOR("Ian Molton");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h
new file mode 100644 (file)
index 0000000..d380f11
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * wm9705.h  --  WM9705 Soc Audio driver
+ */
+
+#ifndef _WM9705_H
+#define _WM9705_H
+
+#define WM9705_DAI_AC97_HIFI   0
+#define WM9705_DAI_AC97_AUX    1
+
+extern struct snd_soc_dai wm9705_dai[2];
+extern struct snd_soc_codec_device soc_codec_dev_wm9705;
+
+#endif
index af83d629078a47f2dbaac75d6d47036086b57ce1..765cf1e7369eb37c3a8f85a5e8257a22c2957f8e 100644 (file)
@@ -154,21 +154,6 @@ SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
 SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
 };
 
-/* add non dapm controls */
-static int wm9712_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                                 snd_soc_cnew(&wm9712_snd_ac97_controls[i],
-                                              codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /* We have to create a fake left and right HP mixers because
  * the codec only has a single control that is shared by both channels.
  * This makes it impossible to determine the audio path.
@@ -467,7 +452,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        else {
                reg = reg >> 1;
 
-               if (reg > (ARRAY_SIZE(wm9712_reg)))
+               if (reg >= (ARRAY_SIZE(wm9712_reg)))
                        return -EIO;
 
                return cache[reg];
@@ -481,7 +466,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 
        soc_ac97_ops.write(codec->ac97, reg, val);
        reg = reg >> 1;
-       if (reg <= (ARRAY_SIZE(wm9712_reg)))
+       if (reg < (ARRAY_SIZE(wm9712_reg)))
                cache[reg] = val;
 
        return 0;
@@ -493,7 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int reg;
        u16 vra;
 
@@ -514,7 +499,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 vra, xsle;
 
        vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -532,6 +517,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
+       .prepare        = ac97_prepare,
+};
+
+static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
+       .prepare        = ac97_aux_prepare,
+};
+
 struct snd_soc_dai wm9712_dai[] = {
 {
        .name = "AC97 HiFi",
@@ -548,8 +541,7 @@ struct snd_soc_dai wm9712_dai[] = {
                .channels_max = 2,
                .rates = WM9712_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .prepare = ac97_prepare,},
+       .ops = &wm9712_dai_ops_hifi,
 },
 {
        .name = "AC97 Aux",
@@ -559,8 +551,7 @@ struct snd_soc_dai wm9712_dai[] = {
                .channels_max = 1,
                .rates = WM9712_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .prepare = ac97_aux_prepare,},
+       .ops = &wm9712_dai_ops_aux,
 }
 };
 EXPORT_SYMBOL_GPL(wm9712_dai);
@@ -607,7 +598,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev,
        pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -616,7 +607,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev,
 static int wm9712_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int i, ret;
        u16 *cache = codec->reg_cache;
 
@@ -652,10 +643,11 @@ static int wm9712_soc_probe(struct platform_device *pdev)
 
        printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->codec == NULL)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+                                     GFP_KERNEL);
+       if (socdev->card->codec == NULL)
                return -ENOMEM;
-       codec = socdev->codec;
+       codec = socdev->card->codec;
        mutex_init(&codec->mutex);
 
        codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
@@ -698,7 +690,8 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
 
        wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       wm9712_add_controls(codec);
+       snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
+                               ARRAY_SIZE(wm9712_snd_ac97_controls));
        wm9712_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0) {
@@ -718,15 +711,15 @@ codec_err:
        kfree(codec->reg_cache);
 
 cache_err:
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
        return ret;
 }
 
 static int wm9712_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec == NULL)
                return 0;
index f3ca8aaf013944a33a9516f9c7fd9bbc690e17f0..523bad077fa04cc3f84a74feb7289bbb01c2c6a5 100644 (file)
@@ -32,7 +32,6 @@
 
 struct wm9713_priv {
        u32 pll_in; /* PLL input frequency */
-       u32 pll_out; /* PLL output frequency */
 };
 
 static unsigned int ac97_read(struct snd_soc_codec *codec,
@@ -190,21 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
 SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 };
 
-/* add non dapm controls */
-static int wm9713_add_controls(struct snd_soc_codec *codec)
-{
-       int err, i;
-
-       for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm9713_snd_ac97_controls[i],
-                                       codec, NULL));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
 /* We have to create a fake left and right HP mixers because
  * the codec only has a single control that is shared by both channels.
  * This makes it impossible to determine the audio path using the current
@@ -636,7 +620,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        else {
                reg = reg >> 1;
 
-               if (reg > (ARRAY_SIZE(wm9713_reg)))
+               if (reg >= (ARRAY_SIZE(wm9713_reg)))
                        return -EIO;
 
                return cache[reg];
@@ -650,7 +634,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        if (reg < 0x7c)
                soc_ac97_ops.write(codec->ac97, reg, val);
        reg = reg >> 1;
-       if (reg <= (ARRAY_SIZE(wm9713_reg)))
+       if (reg < (ARRAY_SIZE(wm9713_reg)))
                cache[reg] = val;
 
        return 0;
@@ -738,13 +722,13 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        struct _pll_div pll_div;
 
        /* turn PLL off ? */
-       if (freq_in == 0 || freq_out == 0) {
+       if (freq_in == 0) {
                /* disable PLL power and select ext source */
                reg = ac97_read(codec, AC97_HANDSET_RATE);
                ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
                reg = ac97_read(codec, AC97_EXTENDED_MID);
                ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
-               wm9713->pll_out = 0;
+               wm9713->pll_in = 0;
                return 0;
        }
 
@@ -788,7 +772,6 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
        reg = ac97_read(codec, AC97_HANDSET_RATE);
        ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
-       wm9713->pll_out = freq_out;
        wm9713->pll_in = freq_in;
 
        /* wait 10ms AC97 link frames for the link to stabilise */
@@ -957,13 +940,14 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 status;
+       u16 status, rate;
 
        /* Gracefully shut down the voice interface. */
        status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
-       ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
+       rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
+       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
        schedule_timeout_interruptible(msecs_to_jiffies(1));
-       ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
+       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
        ac97_write(codec, AC97_EXTENDED_MID, status);
 }
 
@@ -1021,6 +1005,27 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
        (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
         SNDRV_PCM_FORMAT_S24_LE)
 
+static struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
+       .prepare        = ac97_hifi_prepare,
+       .set_clkdiv     = wm9713_set_dai_clkdiv,
+       .set_pll        = wm9713_set_dai_pll,
+};
+
+static struct snd_soc_dai_ops wm9713_dai_ops_aux = {
+       .prepare        = ac97_aux_prepare,
+       .set_clkdiv     = wm9713_set_dai_clkdiv,
+       .set_pll        = wm9713_set_dai_pll,
+};
+
+static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
+       .hw_params      = wm9713_pcm_hw_params,
+       .shutdown       = wm9713_voiceshutdown,
+       .set_clkdiv     = wm9713_set_dai_clkdiv,
+       .set_pll        = wm9713_set_dai_pll,
+       .set_fmt        = wm9713_set_dai_fmt,
+       .set_tristate   = wm9713_set_dai_tristate,
+};
+
 struct snd_soc_dai wm9713_dai[] = {
 {
        .name = "AC97 HiFi",
@@ -1037,10 +1042,7 @@ struct snd_soc_dai wm9713_dai[] = {
                .channels_max = 2,
                .rates = WM9713_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .prepare = ac97_hifi_prepare,
-               .set_clkdiv = wm9713_set_dai_clkdiv,
-               .set_pll = wm9713_set_dai_pll,},
+       .ops = &wm9713_dai_ops_hifi,
        },
        {
        .name = "AC97 Aux",
@@ -1050,10 +1052,7 @@ struct snd_soc_dai wm9713_dai[] = {
                .channels_max = 1,
                .rates = WM9713_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .prepare = ac97_aux_prepare,
-               .set_clkdiv = wm9713_set_dai_clkdiv,
-               .set_pll = wm9713_set_dai_pll,},
+       .ops = &wm9713_dai_ops_aux,
        },
        {
        .name = "WM9713 Voice",
@@ -1069,14 +1068,7 @@ struct snd_soc_dai wm9713_dai[] = {
                .channels_max = 2,
                .rates = WM9713_PCM_RATES,
                .formats = WM9713_PCM_FORMATS,},
-       .ops = {
-               .hw_params = wm9713_pcm_hw_params,
-               .shutdown = wm9713_voiceshutdown,
-               .set_clkdiv = wm9713_set_dai_clkdiv,
-               .set_pll = wm9713_set_dai_pll,
-               .set_fmt = wm9713_set_dai_fmt,
-               .set_tristate = wm9713_set_dai_tristate,
-       },
+       .ops = &wm9713_dai_ops_voice,
        },
 };
 EXPORT_SYMBOL_GPL(wm9713_dai);
@@ -1132,7 +1124,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
        pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Disable everything except touchpanel - that will be handled
@@ -1150,7 +1142,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
 static int wm9713_soc_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm9713_priv *wm9713 = codec->private_data;
        int i, ret;
        u16 *cache = codec->reg_cache;
@@ -1164,8 +1156,8 @@ static int wm9713_soc_resume(struct platform_device *pdev)
        wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* do we need to re-start the PLL ? */
-       if (wm9713->pll_out)
-               wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out);
+       if (wm9713->pll_in)
+               wm9713_set_pll(codec, 0, wm9713->pll_in, 0);
 
        /* only synchronise the codec if warm reset failed */
        if (ret == 0) {
@@ -1191,10 +1183,11 @@ static int wm9713_soc_probe(struct platform_device *pdev)
 
        printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION);
 
-       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->codec == NULL)
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+                                     GFP_KERNEL);
+       if (socdev->card->codec == NULL)
                return -ENOMEM;
-       codec = socdev->codec;
+       codec = socdev->card->codec;
        mutex_init(&codec->mutex);
 
        codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
@@ -1245,7 +1238,8 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        reg = ac97_read(codec, AC97_CD) & 0x7fff;
        ac97_write(codec, AC97_CD, reg);
 
-       wm9713_add_controls(codec);
+       snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
+                               ARRAY_SIZE(wm9713_snd_ac97_controls));
        wm9713_add_widgets(codec);
        ret = snd_soc_init_card(socdev);
        if (ret < 0)
@@ -1265,15 +1259,15 @@ priv_err:
        kfree(codec->reg_cache);
 
 cache_err:
-       kfree(socdev->codec);
-       socdev->codec = NULL;
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
        return ret;
 }
 
 static int wm9713_soc_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        if (codec == NULL)
                return 0;
index b502741692d6ba866047917046c04d267a3ac89f..bd7392c9657ef10450f49f5cb31469cd033ec771 100644 (file)
@@ -20,7 +20,7 @@ config SND_DAVINCI_SOC_EVM
 
 config SND_DAVINCI_SOC_SFFSDR
        tristate "SoC Audio support for SFFSDR"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR
+       depends on SND_DAVINCI_SOC && MACH_SFFSDR
        select SND_DAVINCI_SOC_I2S
        select SND_SOC_PCM3008
        select SFFSDR_FPGA
index 54851f318568b7ba277284bf65d9f01077f64527..9b90b347007cf400128bbceac8edbf3eaadac1e8 100644 (file)
@@ -186,7 +186,8 @@ static int __init evm_init(void)
 
        platform_set_drvdata(evm_snd_device, &evm_snd_devdata);
        evm_snd_devdata.dev = &evm_snd_device->dev;
-       evm_snd_device->dev.platform_data = &evm_snd_data;
+       platform_device_add_data(evm_snd_device, &evm_snd_data,
+                                sizeof(evm_snd_data));
 
        ret = platform_device_add_resources(evm_snd_device, evm_snd_resources,
                                            ARRAY_SIZE(evm_snd_resources));
index 0fee779e3c7601168334bc6e60506d302c9da7ab..ffdb9439d3d875edd6d17e3d884b50d2b626af1e 100644 (file)
@@ -499,6 +499,13 @@ static void davinci_i2s_remove(struct platform_device *pdev,
 
 #define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
+static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+       .startup        = davinci_i2s_startup,
+       .trigger        = davinci_i2s_trigger,
+       .hw_params      = davinci_i2s_hw_params,
+       .set_fmt        = davinci_i2s_set_dai_fmt,
+};
+
 struct snd_soc_dai davinci_i2s_dai = {
        .name = "davinci-i2s",
        .id = 0,
@@ -514,12 +521,7 @@ struct snd_soc_dai davinci_i2s_dai = {
                .channels_max = 2,
                .rates = DAVINCI_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .startup = davinci_i2s_startup,
-               .trigger = davinci_i2s_trigger,
-               .hw_params = davinci_i2s_hw_params,
-               .set_fmt = davinci_i2s_set_dai_fmt,
-       },
+       .ops = &davinci_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(davinci_i2s_dai);
 
index 366049d8578c1f10611d1e211dc66358fcd2045f..7af3b5b3a53d76fe920c9bd48b842f862baa5675 100644 (file)
@@ -286,7 +286,7 @@ static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
                                     runtime->dma_bytes);
 }
 
-struct snd_pcm_ops davinci_pcm_ops = {
+static struct snd_pcm_ops davinci_pcm_ops = {
        .open =         davinci_pcm_open,
        .close =        davinci_pcm_close,
        .ioctl =        snd_pcm_lib_ioctl,
index 4935d1bcbd8d4733408866475425bc5332fbebb5..40eccfe9e358c2f2bc05574d3cdeb87f6fa7bffc 100644 (file)
@@ -25,7 +25,9 @@
 
 #include <asm/dma.h>
 #include <asm/mach-types.h>
+#ifdef CONFIG_SFFSDR_FPGA
 #include <asm/plat-sffsdr/sffsdr-fpga.h>
+#endif
 
 #include <mach/mcbsp.h>
 #include <mach/edma.h>
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 
+/*
+ * CLKX and CLKR are the inputs for the Sample Rate Generator.
+ * FSX and FSR are outputs, driven by the sample Rate Generator.
+ */
+#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B |   \
+                     SND_SOC_DAIFMT_CBM_CFS |  \
+                     SND_SOC_DAIFMT_IB_NF)
+
 static int sffsdr_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *dai)
+                           struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int fs;
        int ret = 0;
 
-       /* Set cpu DAI configuration:
-        * CLKX and CLKR are the inputs for the Sample Rate Generator.
-        * FSX and FSR are outputs, driven by the sample Rate Generator. */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-                                 SND_SOC_DAIFMT_RIGHT_J |
-                                 SND_SOC_DAIFMT_CBM_CFS |
-                                 SND_SOC_DAIFMT_IB_NF);
-       if (ret < 0)
-               return ret;
-
        /* Fsref can be 32000, 44100 or 48000. */
        fs = params_rate(params);
 
+#ifndef CONFIG_SFFSDR_FPGA
+       /* Without the FPGA module, the Fs is fixed at 44100 Hz */
+       if (fs != 44100) {
+               pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n");
+               return -EINVAL;
+       }
+#endif
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
+       if (ret < 0)
+               return ret;
+
        pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
 
+#ifndef CONFIG_SFFSDR_FPGA
+       return 0;
+#else
        return sffsdr_fpga_set_codec_fs(fs);
+#endif
 }
 
 static struct snd_soc_ops sffsdr_ops = {
@@ -127,7 +143,8 @@ static int __init sffsdr_init(void)
 
        platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
        sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
-       sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data;
+       platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
+                                sizeof(sffsdr_snd_data));
 
        ret = platform_device_add_resources(sffsdr_snd_device,
                                            sffsdr_snd_resources,
index 95c12b26fe37c0a3acfdb1ba070facdf02ca4067..9fc9082833716dc4b16df21bf6e5e30267913f8f 100644 (file)
@@ -1,17 +1,18 @@
 config SND_SOC_OF_SIMPLE
        tristate
 
+# ASoC platform support for the Freescale MPC8610 SOC.  This compiles drivers
+# for the SSI and the Elo DMA controller.  You will still need to select
+# a platform driver and a codec driver.
 config SND_SOC_MPC8610
-       bool "ALSA SoC support for the MPC8610 SOC"
-       depends on MPC8610_HPCD
-       default y if MPC8610
-       help
-         Say Y if you want to add support for codecs attached to the SSI
-          device on an MPC8610.
+       tristate
+       depends on MPC8610
 
 config SND_SOC_MPC8610_HPCD
-       bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
-       depends on SND_SOC_MPC8610
+       tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
+       # I2C is necessary for the CS4270 driver
+       depends on MPC8610_HPCD && I2C
+       select SND_SOC_MPC8610
        select SND_SOC_CS4270
        select SND_SOC_CS4270_VD33_ERRATA
        default y if MPC8610_HPCD
index 035da4afec34bb8961dfbd86a5ffd23164bb0ce2..f85134c863871f6a73a5dca1e96f371893a8e602 100644 (file)
@@ -2,10 +2,13 @@
 obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
 
 # MPC8610 HPCD Machine Support
-obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
+snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
+obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
 
 # MPC8610 Platform Support
-obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
+snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
 
index 64993eda5679ebce0cd582afe2fc48f74b7f0605..b3eb8570cd7bf4a4073082fffdc9f3dbb71d9521 100644 (file)
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_JOINT_DUPLEX,
+                                 SNDRV_PCM_INFO_JOINT_DUPLEX |
+                                 SNDRV_PCM_INFO_PAUSE,
        .formats                = FSLDMA_PCM_FORMATS,
        .rates                  = FSLDMA_PCM_RATES,
        .rate_min               = 5512,
@@ -464,11 +465,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
                sizeof(struct fsl_dma_link_descriptor);
 
        for (i = 0; i < NUM_DMA_LINKS; i++) {
-               struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
-               link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
-               link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
-               link->next = cpu_to_be64(temp_link);
+               dma_private->link[i].next = cpu_to_be64(temp_link);
 
                temp_link += sizeof(struct fsl_dma_link_descriptor);
        }
@@ -525,79 +522,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
  * This function obtains hardware parameters about the opened stream and
  * programs the DMA controller accordingly.
  *
- * Note that due to a quirk of the SSI's STX register, the target address
- * for the DMA operations depends on the sample size.  So we don't program
- * the dest_addr (for playback -- source_addr for capture) fields in the
- * link descriptors here.  We do that in fsl_dma_prepare()
- */
-static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct fsl_dma_private *dma_private = runtime->private_data;
-
-       dma_addr_t temp_addr;   /* Pointer to next period */
-
-       unsigned int i;
-
-       /* Get all the parameters we need */
-       size_t buffer_size = params_buffer_bytes(hw_params);
-       size_t period_size = params_period_bytes(hw_params);
-
-       /* Initialize our DMA tracking variables */
-       dma_private->period_size = period_size;
-       dma_private->num_periods = params_periods(hw_params);
-       dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
-       dma_private->dma_buf_next = dma_private->dma_buf_phys +
-               (NUM_DMA_LINKS * period_size);
-       if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
-               dma_private->dma_buf_next = dma_private->dma_buf_phys;
-
-       /*
-        * The actual address in STX0 (destination for playback, source for
-        * capture) is based on the sample size, but we don't know the sample
-        * size in this function, so we'll have to adjust that later.  See
-        * comments in fsl_dma_prepare().
-        *
-        * The DMA controller does not have a cache, so the CPU does not
-        * need to tell it to flush its cache.  However, the DMA
-        * controller does need to tell the CPU to flush its cache.
-        * That's what the SNOOP bit does.
-        *
-        * Also, even though the DMA controller supports 36-bit addressing, for
-        * simplicity we currently support only 32-bit addresses for the audio
-        * buffer itself.
-        */
-       temp_addr = substream->dma_buffer.addr;
-
-       for (i = 0; i < NUM_DMA_LINKS; i++) {
-               struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
-               link->count = cpu_to_be32(period_size);
-
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       link->source_addr = cpu_to_be32(temp_addr);
-               else
-                       link->dest_addr = cpu_to_be32(temp_addr);
-
-               temp_addr += period_size;
-       }
-
-       return 0;
-}
-
-/**
- * fsl_dma_prepare - prepare the DMA registers for playback.
- *
- * This function is called after the specifics of the audio data are known,
- * i.e. snd_pcm_runtime is initialized.
- *
- * In this function, we finish programming the registers of the DMA
- * controller that are dependent on the sample size.
- *
- * One of the drawbacks with big-endian is that when copying integers of
- * different sizes to a fixed-sized register, the address to which the
- * integer must be copied is dependent on the size of the integer.
+ * One drawback of big-endian is that when copying integers of different
+ * sizes to a fixed-sized register, the address to which the integer must be
+ * copied is dependent on the size of the integer.
  *
  * For example, if P is the address of a 32-bit register, and X is a 32-bit
  * integer, then X should be copied to address P.  However, if X is a 16-bit
@@ -613,22 +540,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
  * and 8 bytes at a time).  So we do not support packed 24-bit samples.
  * 24-bit data must be padded to 32 bits.
  */
-static int fsl_dma_prepare(struct snd_pcm_substream *substream)
+static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *hw_params)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
+
+       /* Number of bits per sample */
+       unsigned int sample_size =
+               snd_pcm_format_physical_width(params_format(hw_params));
+
+       /* Number of bytes per frame */
+       unsigned int frame_size = 2 * (sample_size / 8);
+
+       /* Bus address of SSI STX register */
+       dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
+
+       /* Size of the DMA buffer, in bytes */
+       size_t buffer_size = params_buffer_bytes(hw_params);
+
+       /* Number of bytes per period */
+       size_t period_size = params_period_bytes(hw_params);
+
+       /* Pointer to next period */
+       dma_addr_t temp_addr = substream->dma_buffer.addr;
+
+       /* Pointer to DMA controller */
        struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
-       u32 mr;
+
+       u32 mr; /* DMA Mode Register */
+
        unsigned int i;
-       dma_addr_t ssi_sxx_phys;        /* Bus address of SSI STX register */
-       unsigned int frame_size;        /* Number of bytes per frame */
 
-       ssi_sxx_phys = dma_private->ssi_sxx_phys;
+       /* Initialize our DMA tracking variables */
+       dma_private->period_size = period_size;
+       dma_private->num_periods = params_periods(hw_params);
+       dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
+       dma_private->dma_buf_next = dma_private->dma_buf_phys +
+               (NUM_DMA_LINKS * period_size);
+
+       if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
+               /* This happens if the number of periods == NUM_DMA_LINKS */
+               dma_private->dma_buf_next = dma_private->dma_buf_phys;
 
        mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK |
                  CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK);
 
-       switch (runtime->sample_bits) {
+       /* Due to a quirk of the SSI's STX register, the target address
+        * for the DMA operations depends on the sample size.  So we calculate
+        * that offset here.  While we're at it, also tell the DMA controller
+        * how much data to transfer per sample.
+        */
+       switch (sample_size) {
        case 8:
                mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
                ssi_sxx_phys += 3;
@@ -641,12 +604,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
                mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4;
                break;
        default:
+               /* We should never get here */
                dev_err(substream->pcm->card->dev,
-                       "unsupported sample size %u\n", runtime->sample_bits);
+                       "unsupported sample size %u\n", sample_size);
                return -EINVAL;
        }
 
-       frame_size = runtime->frame_bits / 8;
        /*
         * BWC should always be a multiple of the frame size.  BWC determines
         * how many bytes are sent/received before the DMA controller checks the
@@ -655,7 +618,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
         * capture, the receive FIFO is triggered when it contains one frame, so
         * we want to receive one frame at a time.
         */
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                mr |= CCSR_DMA_MR_BWC(2 * frame_size);
        else
@@ -663,16 +625,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
 
        out_be32(&dma_channel->mr, mr);
 
-       /*
-        * Program the address of the DMA transfer to/from the SSI.
-        */
        for (i = 0; i < NUM_DMA_LINKS; i++) {
                struct fsl_dma_link_descriptor *link = &dma_private->link[i];
 
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               link->count = cpu_to_be32(period_size);
+
+               /* Even though the DMA controller supports 36-bit addressing,
+                * for simplicity we allow only 32-bit addresses for the audio
+                * buffer itself.  This was enforced in fsl_dma_new() with the
+                * DMA mask.
+                *
+                * The snoop bit tells the DMA controller whether it should tell
+                * the ECM to snoop during a read or write to an address. For
+                * audio, we use DMA to transfer data between memory and an I/O
+                * device (the SSI's STX0 or SRX0 register). Snooping is only
+                * needed if there is a cache, so we need to snoop memory
+                * addresses only.  For playback, that means we snoop the source
+                * but not the destination.  For capture, we snoop the
+                * destination but not the source.
+                *
+                * Note that failing to snoop properly is unlikely to cause
+                * cache incoherency if the period size is larger than the
+                * size of L1 cache.  This is because filling in one period will
+                * flush out the data for the previous period.  So if you
+                * increased period_bytes_min to a large enough size, you might
+                * get more performance by not snooping, and you'll still be
+                * okay.
+                */
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       link->source_addr = cpu_to_be32(temp_addr);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+
                        link->dest_addr = cpu_to_be32(ssi_sxx_phys);
-               else
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+               } else {
                        link->source_addr = cpu_to_be32(ssi_sxx_phys);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+
+                       link->dest_addr = cpu_to_be32(temp_addr);
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+               }
+
+               temp_addr += period_size;
        }
 
        return 0;
@@ -808,7 +802,6 @@ static struct snd_pcm_ops fsl_dma_ops = {
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = fsl_dma_hw_params,
        .hw_free        = fsl_dma_hw_free,
-       .prepare        = fsl_dma_prepare,
        .pointer        = fsl_dma_pointer,
 };
 
index c6d6eb71dc1d9635d7c109531f9b0a653c687d6c..169bca295b7831f263739042aa1ed3645d59c99a 100644 (file)
@@ -72,6 +72,7 @@
  * @dev: struct device pointer
  * @playback: the number of playback streams opened
  * @capture: the number of capture streams opened
+ * @asynchronous: 0=synchronous mode, 1=asynchronous mode
  * @cpu_dai: the CPU DAI for this device
  * @dev_attr: the sysfs device attribute structure
  * @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
        struct device *dev;
        unsigned int playback;
        unsigned int capture;
+       int asynchronous;
        struct snd_soc_dai cpu_dai;
        struct device_attribute dev_attr;
 
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                 *
                 * FIXME: Little-endian samples require a different shift dir
                 */
-               clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
-                       CCSR_SSI_SCR_TFR_CLK_DIS |
-                       CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
+               clrsetbits_be32(&ssi->scr,
+                       CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
+                       CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
+                       | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
 
                out_be32(&ssi->stcr,
                         CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                        SNDRV_PCM_HW_PARAM_RATE,
                        first_runtime->rate, first_runtime->rate);
 
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                       SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                       first_runtime->sample_bits,
-                       first_runtime->sample_bits);
+               /* If we're in synchronous mode, then we need to constrain
+                * the sample size as well.  We don't support independent sample
+                * rates in asynchronous mode.
+                */
+               if (!ssi_private->asynchronous)
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                               SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                               first_runtime->sample_bits,
+                               first_runtime->sample_bits);
 
                ssi_private->second_stream = substream;
        }
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 }
 
 /**
- * fsl_ssi_prepare: prepare the SSI.
+ * fsl_ssi_hw_params - program the sample size
  *
  * Most of the SSI registers have been programmed in the startup function,
  * but the word length must be programmed here.  Unfortunately, programming
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
  * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
  * clock master.
  */
-static int fsl_ssi_prepare(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
-
-       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
 
        if (substream == ssi_private->first_stream) {
-               u32 wl;
+               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+               unsigned int sample_size =
+                       snd_pcm_format_width(params_format(hw_params));
+               u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
 
                /* The SSI should always be disabled at this points (SSIEN=0) */
-               wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
 
                /* In synchronous mode, the SSI uses STCCR for capture */
-               clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+               if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
+                   !ssi_private->asynchronous)
+                       clrsetbits_be32(&ssi->stccr,
+                                       CCSR_SSI_SxCCR_WL_MASK, wl);
+               else
+                       clrsetbits_be32(&ssi->srccr,
+                                       CCSR_SSI_SxCCR_WL_MASK, wl);
        }
 
        return 0;
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
+               clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
                        setbits32(&ssi->scr,
                                CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
                } else {
-                       clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+                       long timeout = jiffies + 10;
+
                        setbits32(&ssi->scr,
                                CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
 
-                       /*
-                        * I think we need this delay to allow time for the SSI
-                        * to put data into its FIFO.  Without it, ALSA starts
-                        * to complain about overruns.
+                       /* Wait until the SSI has filled its FIFO. Without this
+                        * delay, ALSA complains about overruns.  When the FIFO
+                        * is full, the DMA controller initiates its first
+                        * transfer.  Until then, however, the DMA's DAR
+                        * register is zero, which translates to an
+                        * out-of-bounds pointer.  This makes ALSA think an
+                        * overrun has occurred.
                         */
-                       mdelay(1);
+                       while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
+                              (jiffies < timeout));
+                       if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
+                               return -EIO;
                }
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                        clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 /**
  * fsl_ssi_dai_template: template CPU DAI for the SSI
  */
+static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+       .startup        = fsl_ssi_startup,
+       .hw_params      = fsl_ssi_hw_params,
+       .shutdown       = fsl_ssi_shutdown,
+       .trigger        = fsl_ssi_trigger,
+       .set_sysclk     = fsl_ssi_set_sysclk,
+       .set_fmt        = fsl_ssi_set_fmt,
+};
+
 static struct snd_soc_dai fsl_ssi_dai_template = {
        .playback = {
                /* The SSI does not support monaural audio. */
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = {
                .rates = FSLSSI_I2S_RATES,
                .formats = FSLSSI_I2S_FORMATS,
        },
-       .ops = {
-               .startup = fsl_ssi_startup,
-               .prepare = fsl_ssi_prepare,
-               .shutdown = fsl_ssi_shutdown,
-               .trigger = fsl_ssi_trigger,
-               .set_sysclk = fsl_ssi_set_sysclk,
-               .set_fmt = fsl_ssi_set_fmt,
-       },
+       .ops = &fsl_ssi_dai_ops,
 };
 
 /**
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
        ssi_private->ssi_phys = ssi_info->ssi_phys;
        ssi_private->irq = ssi_info->irq;
        ssi_private->dev = ssi_info->dev;
+       ssi_private->asynchronous = ssi_info->asynchronous;
 
        ssi_private->dev->driver_data = fsl_ssi_dai;
 
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
 }
 EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
 
+static int __init fsl_ssi_init(void)
+{
+       printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
+
+       return 0;
+}
+module_init(fsl_ssi_init);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
 MODULE_LICENSE("GPL");
index 83b44d700e3328fbf973d25c616751555211f202..eade01feaab69f0d69ea82c13466307d52158a14 100644 (file)
@@ -208,6 +208,7 @@ struct ccsr_ssi {
  * ssi_phys: physical address of the SSI registers
  * irq: IRQ of this SSI
  * dev: struct device, used to create the sysfs statistics file
+ * asynchronous: 0=synchronous mode, 1=asynchronous mode
 */
 struct fsl_ssi_info {
        unsigned int id;
@@ -215,6 +216,7 @@ struct fsl_ssi_info {
        dma_addr_t ssi_phys;
        unsigned int irq;
        struct device *dev;
+       int asynchronous;
 };
 
 struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
index 9eb1ce185bd0cbd11e0e3e8744499ff7085fa624..3aa729df27b58cddea053c96f655d518d73ef694 100644 (file)
@@ -468,6 +468,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 /**
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
+static struct snd_soc_dai_ops psc_i2s_dai_ops = {
+       .startup        = psc_i2s_startup,
+       .hw_params      = psc_i2s_hw_params,
+       .hw_free        = psc_i2s_hw_free,
+       .shutdown       = psc_i2s_shutdown,
+       .trigger        = psc_i2s_trigger,
+       .set_sysclk     = psc_i2s_set_sysclk,
+       .set_fmt        = psc_i2s_set_fmt,
+};
+
 static struct snd_soc_dai psc_i2s_dai_template = {
        .playback = {
                .channels_min = 2,
@@ -481,15 +491,7 @@ static struct snd_soc_dai psc_i2s_dai_template = {
                .rates = PSC_I2S_RATES,
                .formats = PSC_I2S_FORMATS,
        },
-       .ops = {
-               .startup = psc_i2s_startup,
-               .hw_params = psc_i2s_hw_params,
-               .hw_free = psc_i2s_hw_free,
-               .shutdown = psc_i2s_shutdown,
-               .trigger = psc_i2s_trigger,
-               .set_sysclk = psc_i2s_set_sysclk,
-               .set_fmt = psc_i2s_set_fmt,
-       },
+       .ops = &psc_i2s_dai_ops,
 };
 
 /* ---------------------------------------------------------------------
index acf39a646b2f119043e018c135ff9a82993d3588..ef67d1cdffe7e4409c28f889a660351c8bfc2da9 100644 (file)
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
        }
        ssi_info.irq = machine_data->ssi_irq;
 
+       /* Do we want to use asynchronous mode? */
+       ssi_info.asynchronous =
+               of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
+       if (ssi_info.asynchronous)
+               dev_info(&ofdev->dev, "using asynchronous mode\n");
 
        /* Map the global utilities registers. */
        guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
index 4f7f040145850b2e0d86a76aaa95657baa2b6d48..675732e724d5ccfa5a824deec7365fecbaf86f96 100644 (file)
@@ -8,7 +8,7 @@ config SND_OMAP_SOC_MCBSP
 
 config SND_OMAP_SOC_N810
        tristate "SoC Audio support for Nokia N810"
-       depends on SND_OMAP_SOC && MACH_NOKIA_N810
+       depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
        select SND_OMAP_SOC_MCBSP
        select OMAP_MUX
        select SND_SOC_TLV320AIC3X
@@ -17,7 +17,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_OSK5912
        tristate "SoC Audio support for omap osk5912"
-       depends on SND_OMAP_SOC && MACH_OMAP_OSK
+       depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC23
        help
@@ -55,3 +55,13 @@ config SND_OMAP_SOC_OMAP3_PANDORA
        select SND_SOC_TWL4030
        help
          Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
+
+config SND_OMAP_SOC_OMAP3_BEAGLE
+       tristate "SoC Audio support for OMAP3 Beagle"
+       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y if you want to add support for SoC audio on the Beagleboard.
+
+
index 76fedd96e3657b8c4e52b9d0695d3fb47f8ae70c..0c9e4ac376601051a2136a861e68ae921ba439c0 100644 (file)
@@ -12,6 +12,7 @@ snd-soc-overo-objs := overo.o
 snd-soc-omap2evm-objs := omap2evm.o
 snd-soc-sdp3430-objs := sdp3430.o
 snd-soc-omap3pandora-objs := omap3pandora.o
+snd-soc-omap3beagle-objs := omap3beagle.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
 obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
 obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
index 25593fee9121e22df808bd88ac5f2048ea2f2fae..a6d1178ce128a94402a3057dab8715c8cfccd751 100644 (file)
 #define N810_HEADSET_AMP_GPIO  10
 #define N810_SPEAKER_AMP_GPIO  101
 
+enum {
+       N810_JACK_DISABLED,
+       N810_JACK_HP,
+       N810_JACK_HS,
+       N810_JACK_MIC,
+};
+
 static struct clk *sys_clkout2;
 static struct clk *sys_clkout2_src;
 static struct clk *func96m_clk;
@@ -50,15 +57,32 @@ static int n810_dmic_func;
 
 static void n810_ext_control(struct snd_soc_codec *codec)
 {
+       int hp = 0, line1l = 0;
+
+       switch (n810_jack_func) {
+       case N810_JACK_HS:
+               line1l = 1;
+       case N810_JACK_HP:
+               hp = 1;
+               break;
+       case N810_JACK_MIC:
+               line1l = 1;
+               break;
+       }
+
        if (n810_spk_func)
                snd_soc_dapm_enable_pin(codec, "Ext Spk");
        else
                snd_soc_dapm_disable_pin(codec, "Ext Spk");
 
-       if (n810_jack_func)
+       if (hp)
                snd_soc_dapm_enable_pin(codec, "Headphone Jack");
        else
                snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+       if (line1l)
+               snd_soc_dapm_enable_pin(codec, "LINE1L");
+       else
+               snd_soc_dapm_disable_pin(codec, "LINE1L");
 
        if (n810_dmic_func)
                snd_soc_dapm_enable_pin(codec, "DMic");
@@ -72,7 +96,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        snd_pcm_hw_constraint_minmax(runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -229,7 +253,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 };
 
 static const char *spk_function[] = {"Off", "On"};
-static const char *jack_function[] = {"Off", "Headphone"};
+static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
 static const char *input_function[] = {"ADC", "Digital Mic"};
 static const struct soc_enum n810_enum[] = {
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
@@ -248,20 +272,23 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
 
 static int n810_aic33_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        /* Not connected */
        snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
        snd_soc_dapm_nc_pin(codec, "HPLCOM");
        snd_soc_dapm_nc_pin(codec, "HPRCOM");
+       snd_soc_dapm_nc_pin(codec, "MIC3L");
+       snd_soc_dapm_nc_pin(codec, "MIC3R");
+       snd_soc_dapm_nc_pin(codec, "LINE1R");
+       snd_soc_dapm_nc_pin(codec, "LINE2L");
+       snd_soc_dapm_nc_pin(codec, "LINE2R");
 
        /* Add N810 specific controls */
-       for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&aic33_n810_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, aic33_n810_controls,
+                               ARRAY_SIZE(aic33_n810_controls));
+       if (err < 0)
+               return err;
 
        /* Add N810 specific widgets */
        snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
index 05dd5abcddf41d425f97d5883911f74f87dae6dc..d6882be33452ae3c6b63140b984d392e0f2e3f61 100644 (file)
@@ -461,6 +461,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
+static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+       .startup        = omap_mcbsp_dai_startup,
+       .shutdown       = omap_mcbsp_dai_shutdown,
+       .trigger        = omap_mcbsp_dai_trigger,
+       .hw_params      = omap_mcbsp_dai_hw_params,
+       .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
+       .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
+       .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
+};
+
 #define OMAP_MCBSP_DAI_BUILDER(link_id)                                \
 {                                                              \
        .name = "omap-mcbsp-dai-"#link_id,                      \
@@ -477,15 +487,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                .rates = OMAP_MCBSP_RATES,                      \
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
        },                                                      \
-       .ops = {                                                \
-               .startup = omap_mcbsp_dai_startup,              \
-               .shutdown = omap_mcbsp_dai_shutdown,            \
-               .trigger = omap_mcbsp_dai_trigger,              \
-               .hw_params = omap_mcbsp_dai_hw_params,          \
-               .set_fmt = omap_mcbsp_dai_set_dai_fmt,          \
-               .set_clkdiv = omap_mcbsp_dai_set_clkdiv,        \
-               .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,    \
-       },                                                      \
+       .ops = &omap_mcbsp_dai_ops,                             \
        .private_data = &mcbsp_data[(link_id)].bus_id,          \
 }
 
index dd3bb293376277d180749a31783bcb34efdf040c..8e1431cb46bbcb20008c6597e512b7eb71e41545 100644 (file)
@@ -265,7 +265,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
                                     runtime->dma_bytes);
 }
 
-struct snd_pcm_ops omap_pcm_ops = {
+static struct snd_pcm_ops omap_pcm_ops = {
        .open           = omap_pcm_open,
        .close          = omap_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
index fcc2f5d9a87884c069813c013cfcea9ae2ac2356..fe282d4ef4222d559e51a8c8566bbccb813fb6fb 100644 (file)
@@ -143,7 +143,7 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
-       SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+       SND_SOC_DAPM_MIC("Mic (internal)", NULL),
        SND_SOC_DAPM_MIC("Mic (external)", NULL),
        SND_SOC_DAPM_LINE("Line In", NULL),
 };
@@ -155,16 +155,33 @@ static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
 };
 
 static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
-       {"INL", NULL, "Line In"},
-       {"INR", NULL, "Line In"},
-       {"INL", NULL, "Mic (Internal)"},
-       {"INR", NULL, "Mic (external)"},
+       {"AUXL", NULL, "Line In"},
+       {"AUXR", NULL, "Line In"},
+
+       {"MAINMIC", NULL, "Mic Bias 1"},
+       {"Mic Bias 1", NULL, "Mic (internal)"},
+
+       {"SUBMIC", NULL, "Mic Bias 2"},
+       {"Mic Bias 2", NULL, "Mic (external)"},
 };
 
 static int omap3pandora_out_init(struct snd_soc_codec *codec)
 {
        int ret;
 
+       /* All TWL4030 output pins are floating */
+       snd_soc_dapm_nc_pin(codec, "OUTL");
+       snd_soc_dapm_nc_pin(codec, "OUTR");
+       snd_soc_dapm_nc_pin(codec, "EARPIECE");
+       snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(codec, "PREDRIVER");
+       snd_soc_dapm_nc_pin(codec, "HSOL");
+       snd_soc_dapm_nc_pin(codec, "HSOR");
+       snd_soc_dapm_nc_pin(codec, "CARKITL");
+       snd_soc_dapm_nc_pin(codec, "CARKITR");
+       snd_soc_dapm_nc_pin(codec, "HFL");
+       snd_soc_dapm_nc_pin(codec, "HFR");
+
        ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
                                ARRAY_SIZE(omap3pandora_out_dapm_widgets));
        if (ret < 0)
@@ -180,18 +197,11 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec)
 {
        int ret;
 
-       /* All TWL4030 output pins are floating */
-       snd_soc_dapm_nc_pin(codec, "OUTL"),
-       snd_soc_dapm_nc_pin(codec, "OUTR"),
-       snd_soc_dapm_nc_pin(codec, "EARPIECE"),
-       snd_soc_dapm_nc_pin(codec, "PREDRIVEL"),
-       snd_soc_dapm_nc_pin(codec, "PREDRIVER"),
-       snd_soc_dapm_nc_pin(codec, "HSOL"),
-       snd_soc_dapm_nc_pin(codec, "HSOR"),
-       snd_soc_dapm_nc_pin(codec, "CARKITL"),
-       snd_soc_dapm_nc_pin(codec, "CARKITR"),
-       snd_soc_dapm_nc_pin(codec, "HFL"),
-       snd_soc_dapm_nc_pin(codec, "HFR"),
+       /* Not comnnected */
+       snd_soc_dapm_nc_pin(codec, "HSMIC");
+       snd_soc_dapm_nc_pin(codec, "CARKITMIC");
+       snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
 
        ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
                                ARRAY_SIZE(omap3pandora_in_dapm_widgets));
@@ -251,10 +261,9 @@ static int __init omap3pandora_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3_pandora()) {
-               pr_debug(PREFIX "Not OMAP3 Pandora\n");
+       if (!machine_is_omap3_pandora())
                return -ENODEV;
-       }
+
        pr_info("OMAP3 Pandora SoC init\n");
 
        ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
index cd41a948df7be44abad30a15a11a529b5e0b6ca2..a952a4eb33614cd67bd6799909bdba98b3def169 100644 (file)
@@ -186,13 +186,6 @@ static int __init osk_soc_init(void)
                return -ENODEV;
        }
 
-       if (clk_get_usecount(tlv320aic23_mclk) > 0) {
-               /* MCLK is already in use */
-               printk(KERN_WARNING
-                      "MCLK in use at %d Hz. We change it to %d Hz\n",
-                      (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
-       }
-
        /*
         * Configure 12 MHz output on MCLK.
         */
@@ -205,9 +198,8 @@ static int __init osk_soc_init(void)
                }
        }
 
-       printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
-              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
-              clk_get_usecount(tlv320aic23_mclk));
+       printk(KERN_INFO "MCLK = %d [%d]\n",
+              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
 
        return 0;
 err1:
index e226fa75669c8695134958bff7732b0df8824a66..10f1c867f11d672692aef958f64750f7f691d5c3 100644 (file)
@@ -28,6 +28,7 @@
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/jack.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -38,6 +39,8 @@
 #include "omap-pcm.h"
 #include "../codecs/twl4030.h"
 
+static struct snd_soc_card snd_soc_sdp3430;
+
 static int sdp3430_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -81,12 +84,121 @@ static struct snd_soc_ops sdp3430_ops = {
        .hw_params = sdp3430_hw_params,
 };
 
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+       {
+               .gpio = (OMAP_MAX_GPIO_LINES + 2),
+               .name = "hsdet-gpio",
+               .report = SND_JACK_HEADSET,
+               .debounce_time = 200,
+       },
+};
+
+/* SDP3430 machine DAPM */
+static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Ext Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* External Mics: MAINMIC, SUBMIC with bias*/
+       {"MAINMIC", NULL, "Mic Bias 1"},
+       {"SUBMIC", NULL, "Mic Bias 2"},
+       {"Mic Bias 1", NULL, "Ext Mic"},
+       {"Mic Bias 2", NULL, "Ext Mic"},
+
+       /* External Speakers: HFL, HFR */
+       {"Ext Spk", NULL, "HFL"},
+       {"Ext Spk", NULL, "HFR"},
+
+       /* Headset Mic: HSMIC with bias */
+       {"HSMIC", NULL, "Headset Mic Bias"},
+       {"Headset Mic Bias", NULL, "Headset Mic"},
+
+       /* Headset Stereophone (Headphone): HSOL, HSOR */
+       {"Headset Stereophone", NULL, "HSOL"},
+       {"Headset Stereophone", NULL, "HSOR"},
+};
+
+static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       /* Add SDP3430 specific widgets */
+       ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
+                               ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
+       if (ret)
+               return ret;
+
+       /* Set up SDP3430 specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       /* SDP3430 connected pins */
+       snd_soc_dapm_enable_pin(codec, "Ext Mic");
+       snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       snd_soc_dapm_disable_pin(codec, "Headset Mic");
+       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+       /* TWL4030 not connected pins */
+       snd_soc_dapm_nc_pin(codec, "AUXL");
+       snd_soc_dapm_nc_pin(codec, "AUXR");
+       snd_soc_dapm_nc_pin(codec, "CARKITMIC");
+       snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
+
+       snd_soc_dapm_nc_pin(codec, "OUTL");
+       snd_soc_dapm_nc_pin(codec, "OUTR");
+       snd_soc_dapm_nc_pin(codec, "EARPIECE");
+       snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(codec, "PREDRIVER");
+       snd_soc_dapm_nc_pin(codec, "CARKITL");
+       snd_soc_dapm_nc_pin(codec, "CARKITR");
+
+       ret = snd_soc_dapm_sync(codec);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+                               SND_JACK_HEADSET, &hs_jack);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                               hs_jack_pins);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+                               hs_jack_gpios);
+
+       return ret;
+}
+
 /* Digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
        .cpu_dai = &omap_mcbsp_dai[0],
        .codec_dai = &twl4030_dai,
+       .init = sdp3430_twl4030_init,
        .ops = &sdp3430_ops,
 };
 
@@ -142,6 +254,9 @@ module_init(sdp3430_soc_init);
 
 static void __exit sdp3430_soc_exit(void)
 {
+       snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+                               hs_jack_gpios);
+
        platform_device_unregister(sdp3430_snd_device);
 }
 module_exit(sdp3430_soc_exit);
index f82e106994717da3c561515e0ba027f1ff32a965..5998ab366e833d8763780643ede4d66d6ca142f0 100644 (file)
@@ -61,6 +61,24 @@ config SND_PXA2XX_SOC_TOSA
          Say Y if you want to add support for SoC audio on Sharp
          Zaurus SL-C6000x models (Tosa).
 
+config SND_PXA2XX_SOC_E740
+       tristate "SoC AC97 Audio support for e740"
+       depends on SND_PXA2XX_SOC && MACH_E740
+       select SND_SOC_WM9705
+       select SND_PXA2XX_SOC_AC97
+       help
+         Say Y if you want to add support for SoC audio on the
+         toshiba e740 PDA
+
+config SND_PXA2XX_SOC_E750
+       tristate "SoC AC97 Audio support for e750"
+       depends on SND_PXA2XX_SOC && MACH_E750
+       select SND_SOC_WM9705
+       select SND_PXA2XX_SOC_AC97
+       help
+         Say Y if you want to add support for SoC audio on the
+         toshiba e750 PDA
+
 config SND_PXA2XX_SOC_E800
        tristate "SoC AC97 Audio support for e800"
        depends on SND_PXA2XX_SOC && MACH_E800
@@ -97,3 +115,12 @@ config SND_SOC_ZYLONITE
        help
          Say Y if you want to add support for SoC audio on the
          Marvell Zylonite reference platform.
+
+config SND_PXA2XX_SOC_MIOA701
+        tristate "SoC Audio support for MIO A701"
+        depends on SND_PXA2XX_SOC && MACH_MIOA701
+        select SND_PXA2XX_SOC_AC97
+        select SND_SOC_WM9713
+        help
+          Say Y if you want to add support for SoC audio on the
+          MIO A701.
index 08a9f279772991f76adbe8f307aee987b8f8351c..8ed881c5e5cc9aaad0ffc4394c6198b7365f1331 100644 (file)
@@ -13,17 +13,23 @@ obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
 snd-soc-corgi-objs := corgi.o
 snd-soc-poodle-objs := poodle.o
 snd-soc-tosa-objs := tosa.o
+snd-soc-e740-objs := e740_wm9705.o
+snd-soc-e750-objs := e750_wm9705.o
 snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
 snd-soc-zylonite-objs := zylonite.o
+snd-soc-mioa701-objs := mioa701_wm9713.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
 obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o
 obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
index 1ba25a559524296217824f188ac8f4de081a72ec..02263e5d8f039ba9879ffdb9c794840eeeb5899e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/timer.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
@@ -100,7 +101,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec)
 static int corgi_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        /* check the jack status at stream startup */
        corgi_ext_control(codec);
@@ -275,18 +276,16 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
  */
 static int corgi_wm8731_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
        snd_soc_dapm_nc_pin(codec, "RLINEIN");
 
        /* Add corgi specific controls */
-       for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, wm8731_corgi_controls,
+                               ARRAY_SIZE(wm8731_corgi_controls));
+       if (err < 0)
+               return err;
 
        /* Add corgi specific widgets */
        snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
@@ -317,19 +316,44 @@ static struct snd_soc_card snd_soc_corgi = {
        .num_links = 1,
 };
 
-/* corgi audio private data */
-static struct wm8731_setup_data corgi_wm8731_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1b,
-};
-
 /* corgi audio subsystem */
 static struct snd_soc_device corgi_snd_devdata = {
        .card = &snd_soc_corgi,
        .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &corgi_wm8731_setup,
 };
 
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = 0x1b;
+       strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(0);
+       if (!adapter) {
+               printk(KERN_ERR "can't get i2c adapter 0\n");
+               return -ENODEV;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               printk(KERN_ERR "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
 static struct platform_device *corgi_snd_device;
 
 static int __init corgi_init(void)
@@ -340,6 +364,10 @@ static int __init corgi_init(void)
              machine_is_husky()))
                return -ENODEV;
 
+       ret = wm8731_i2c_register();
+       if (ret != 0)
+               return ret;
+
        corgi_snd_device = platform_device_alloc("soc-audio", -1);
        if (!corgi_snd_device)
                return -ENOMEM;
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
new file mode 100644 (file)
index 0000000..7cd2f89
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * e740-wm9705.c  --  SoC audio for e740
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.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; version 2 ONLY.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm9705.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+
+#define E740_AUDIO_OUT 1
+#define E740_AUDIO_IN  2
+
+static int e740_audio_power;
+
+static void e740_sync_audio_power(int status)
+{
+       gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status);
+       gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0);
+       gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0);
+}
+
+static int e740_mic_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               e740_audio_power |= E740_AUDIO_IN;
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               e740_audio_power &= ~E740_AUDIO_IN;
+
+       e740_sync_audio_power(e740_audio_power);
+
+       return 0;
+}
+
+static int e740_output_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               e740_audio_power |= E740_AUDIO_OUT;
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               e740_audio_power &= ~E740_AUDIO_OUT;
+
+       e740_sync_audio_power(e740_audio_power);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget e740_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+       SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e740_output_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Output Amp", NULL, "LOUT"},
+       {"Output Amp", NULL, "ROUT"},
+       {"Output Amp", NULL, "MONOOUT"},
+
+       {"Speaker", NULL, "Output Amp"},
+       {"Headphone Jack", NULL, "Output Amp"},
+
+       {"MIC1", NULL, "Mic Amp"},
+       {"Mic Amp", NULL, "Mic (Internal)"},
+};
+
+static int e740_ac97_init(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_nc_pin(codec, "HPOUTL");
+       snd_soc_dapm_nc_pin(codec, "HPOUTR");
+       snd_soc_dapm_nc_pin(codec, "PHONE");
+       snd_soc_dapm_nc_pin(codec, "LINEINL");
+       snd_soc_dapm_nc_pin(codec, "LINEINR");
+       snd_soc_dapm_nc_pin(codec, "CDINL");
+       snd_soc_dapm_nc_pin(codec, "CDINR");
+       snd_soc_dapm_nc_pin(codec, "PCBEEP");
+       snd_soc_dapm_nc_pin(codec, "MIC2");
+
+       snd_soc_dapm_new_controls(codec, e740_dapm_widgets,
+                                       ARRAY_SIZE(e740_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link e740_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .init = e740_ac97_init,
+       },
+       {
+               .name = "AC97 Aux",
+               .stream_name = "AC97 Aux",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+       },
+};
+
+static struct snd_soc_card e740 = {
+       .name = "Toshiba e740",
+       .platform = &pxa2xx_soc_platform,
+       .dai_link = e740_dai,
+       .num_links = ARRAY_SIZE(e740_dai),
+};
+
+static struct snd_soc_device e740_snd_devdata = {
+       .card = &e740,
+       .codec_dev = &soc_codec_dev_wm9705,
+};
+
+static struct platform_device *e740_snd_device;
+
+static int __init e740_init(void)
+{
+       int ret;
+
+       if (!machine_is_e740())
+               return -ENODEV;
+
+       ret = gpio_request(GPIO_E740_MIC_ON,  "Mic amp");
+       if (ret)
+               return ret;
+
+       ret = gpio_request(GPIO_E740_AMP_ON, "Output amp");
+       if (ret)
+               goto free_mic_amp_gpio;
+
+       ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power");
+       if (ret)
+               goto free_op_amp_gpio;
+
+       /* Disable audio */
+       ret = gpio_direction_output(GPIO_E740_MIC_ON, 0);
+       if (ret)
+               goto free_apwr_gpio;
+       ret = gpio_direction_output(GPIO_E740_AMP_ON, 0);
+       if (ret)
+               goto free_apwr_gpio;
+       ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1);
+       if (ret)
+               goto free_apwr_gpio;
+
+       e740_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!e740_snd_device) {
+               ret = -ENOMEM;
+               goto free_apwr_gpio;
+       }
+
+       platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
+       e740_snd_devdata.dev = &e740_snd_device->dev;
+       ret = platform_device_add(e740_snd_device);
+
+       if (!ret)
+               return 0;
+
+/* Fail gracefully */
+       platform_device_put(e740_snd_device);
+free_apwr_gpio:
+       gpio_free(GPIO_E740_WM9705_nAVDD2);
+free_op_amp_gpio:
+       gpio_free(GPIO_E740_AMP_ON);
+free_mic_amp_gpio:
+       gpio_free(GPIO_E740_MIC_ON);
+
+       return ret;
+}
+
+static void __exit e740_exit(void)
+{
+       platform_device_unregister(e740_snd_device);
+}
+
+module_init(e740_init);
+module_exit(e740_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e740");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
new file mode 100644 (file)
index 0000000..8dceccc
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * e750-wm9705.c  --  SoC audio for e750
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.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; version 2 ONLY.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm9705.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0);
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1);
+
+       return 0;
+}
+
+static int e750_hp_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               gpio_set_value(GPIO_E750_HP_AMP_OFF, 0);
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               gpio_set_value(GPIO_E750_HP_AMP_OFF, 1);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget e750_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+       SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Amp", NULL, "HPOUTL"},
+       {"Headphone Amp", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "Headphone Amp"},
+
+       {"Speaker Amp", NULL, "MONOOUT"},
+       {"Speaker", NULL, "Speaker Amp"},
+
+       {"MIC1", NULL, "Mic (Internal)"},
+};
+
+static int e750_ac97_init(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_nc_pin(codec, "LOUT");
+       snd_soc_dapm_nc_pin(codec, "ROUT");
+       snd_soc_dapm_nc_pin(codec, "PHONE");
+       snd_soc_dapm_nc_pin(codec, "LINEINL");
+       snd_soc_dapm_nc_pin(codec, "LINEINR");
+       snd_soc_dapm_nc_pin(codec, "CDINL");
+       snd_soc_dapm_nc_pin(codec, "CDINR");
+       snd_soc_dapm_nc_pin(codec, "PCBEEP");
+       snd_soc_dapm_nc_pin(codec, "MIC2");
+
+       snd_soc_dapm_new_controls(codec, e750_dapm_widgets,
+                                       ARRAY_SIZE(e750_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link e750_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .init = e750_ac97_init,
+               /* use ops to check startup state */
+       },
+       {
+               .name = "AC97 Aux",
+               .stream_name = "AC97 Aux",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+       },
+};
+
+static struct snd_soc_card e750 = {
+       .name = "Toshiba e750",
+       .platform = &pxa2xx_soc_platform,
+       .dai_link = e750_dai,
+       .num_links = ARRAY_SIZE(e750_dai),
+};
+
+static struct snd_soc_device e750_snd_devdata = {
+       .card = &e750,
+       .codec_dev = &soc_codec_dev_wm9705,
+};
+
+static struct platform_device *e750_snd_device;
+
+static int __init e750_init(void)
+{
+       int ret;
+
+       if (!machine_is_e750())
+               return -ENODEV;
+
+       ret = gpio_request(GPIO_E750_HP_AMP_OFF,  "Headphone amp");
+       if (ret)
+               return ret;
+
+       ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp");
+       if (ret)
+               goto free_hp_amp_gpio;
+
+       ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1);
+       if (ret)
+               goto free_spk_amp_gpio;
+
+       ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1);
+       if (ret)
+               goto free_spk_amp_gpio;
+
+       e750_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!e750_snd_device) {
+               ret = -ENOMEM;
+               goto free_spk_amp_gpio;
+       }
+
+       platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
+       e750_snd_devdata.dev = &e750_snd_device->dev;
+       ret = platform_device_add(e750_snd_device);
+
+       if (!ret)
+               return 0;
+
+/* Fail gracefully */
+       platform_device_put(e750_snd_device);
+free_spk_amp_gpio:
+       gpio_free(GPIO_E750_SPK_AMP_OFF);
+free_hp_amp_gpio:
+       gpio_free(GPIO_E750_HP_AMP_OFF);
+
+       return ret;
+}
+
+static void __exit e750_exit(void)
+{
+       platform_device_unregister(e750_snd_device);
+       gpio_free(GPIO_E750_SPK_AMP_OFF);
+       gpio_free(GPIO_E750_HP_AMP_OFF);
+}
+
+module_init(e750_init);
+module_exit(e750_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e750");
+MODULE_LICENSE("GPL v2");
index 2e3386dfa0f0ed0604568b0b98d4a4b0f19105f8..bc019cdce42922c787f62dfd8bc30cd7a0582d25 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * e800-wm9712.c  --  SoC audio for e800
  *
- * Based on tosa.c
- *
  * Copyright 2007 (c) Ian Molton <spyro@f2s.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -13,7 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/device.h>
+#include <linux/gpio.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
-#include <mach/pxa-regs.h>
-#include <mach/hardware.h>
 #include <mach/audio.h>
+#include <mach/eseries-gpio.h>
 
 #include "../codecs/wm9712.h"
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static struct snd_soc_card e800;
+static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               gpio_set_value(GPIO_E800_SPK_AMP_ON, 1);
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               gpio_set_value(GPIO_E800_SPK_AMP_ON, 0);
 
-static struct snd_soc_dai_link e800_dai[] = {
+       return 0;
+}
+
+static int e800_hp_amp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               gpio_set_value(GPIO_E800_HP_AMP_OFF, 0);
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               gpio_set_value(GPIO_E800_HP_AMP_OFF, 1);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget e800_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic (Internal1)", NULL),
+       SND_SOC_DAPM_MIC("Mic (Internal2)", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "HPOUTL"},
+       {"Headphone Jack", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "Headphone Amp"},
+
+       {"Speaker Amp", NULL, "MONOOUT"},
+       {"Speaker", NULL, "Speaker Amp"},
+
+       {"MIC1", NULL, "Mic (Internal1)"},
+       {"MIC2", NULL, "Mic (Internal2)"},
+};
+
+static int e800_ac97_init(struct snd_soc_codec *codec)
 {
-       .name = "AC97 Aux",
-       .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
-},
+       snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
+                                       ARRAY_SIZE(e800_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link e800_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .init = e800_ac97_init,
+       },
+       {
+               .name = "AC97 Aux",
+               .stream_name = "AC97 Aux",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       },
 };
 
 static struct snd_soc_card e800 = {
@@ -61,6 +121,22 @@ static int __init e800_init(void)
        if (!machine_is_e800())
                return -ENODEV;
 
+       ret = gpio_request(GPIO_E800_HP_AMP_OFF,  "Headphone amp");
+       if (ret)
+               return ret;
+
+       ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp");
+       if (ret)
+               goto free_hp_amp_gpio;
+
+       ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1);
+       if (ret)
+               goto free_spk_amp_gpio;
+
+       ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1);
+       if (ret)
+               goto free_spk_amp_gpio;
+
        e800_snd_device = platform_device_alloc("soc-audio", -1);
        if (!e800_snd_device)
                return -ENOMEM;
@@ -69,8 +145,15 @@ static int __init e800_init(void)
        e800_snd_devdata.dev = &e800_snd_device->dev;
        ret = platform_device_add(e800_snd_device);
 
-       if (ret)
-               platform_device_put(e800_snd_device);
+       if (!ret)
+               return 0;
+
+/* Fail gracefully */
+       platform_device_put(e800_snd_device);
+free_spk_amp_gpio:
+       gpio_free(GPIO_E800_SPK_AMP_ON);
+free_hp_amp_gpio:
+       gpio_free(GPIO_E800_HP_AMP_OFF);
 
        return ret;
 }
@@ -78,6 +161,8 @@ static int __init e800_init(void)
 static void __exit e800_exit(void)
 {
        platform_device_unregister(e800_snd_device);
+       gpio_free(GPIO_E800_SPK_AMP_ON);
+       gpio_free(GPIO_E800_HP_AMP_OFF);
 }
 
 module_init(e800_init);
@@ -86,4 +171,4 @@ module_exit(e800_exit);
 /* Module information */
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 MODULE_DESCRIPTION("ALSA SoC driver for e800");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
new file mode 100644 (file)
index 0000000..19eda8b
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Handles the Mitac mioa701 SoC system
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation in version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This is a little schema of the sound interconnections :
+ *
+ *    Sagem X200                 Wolfson WM9713
+ *    +--------+             +-------------------+      Rear Speaker
+ *    |        |             |                   |           /-+
+ *    |        +--->----->---+MONOIN         SPKL+--->----+-+  |
+ *    |  GSM   |             |                   |        | |  |
+ *    |        +--->----->---+PCBEEP         SPKR+--->----+-+  |
+ *    |  CHIP  |             |                   |           \-+
+ *    |        +---<-----<---+MONO               |
+ *    |        |             |                   |      Front Speaker
+ *    +--------+             |                   |           /-+
+ *                           |                HPL+--->----+-+  |
+ *                           |                   |        | |  |
+ *                           |               OUT3+--->----+-+  |
+ *                           |                   |           \-+
+ *                           |                   |
+ *                           |                   |     Front Micro
+ *                           |                   |         +
+ *                           |               MIC1+-----<--+o+
+ *                           |                   |         +
+ *                           +-------------------+        ---
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "../codecs/wm9713.h"
+
+#define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
+
+#define AC97_GPIO_PULL         0x58
+
+/* Use GPIO8 for rear speaker amplifier */
+static int rear_amp_power(struct snd_soc_codec *codec, int power)
+{
+       unsigned short reg;
+
+       if (power) {
+               reg = snd_soc_read(codec, AC97_GPIO_CFG);
+               snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100);
+               reg = snd_soc_read(codec, AC97_GPIO_PULL);
+               snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15));
+       } else {
+               reg = snd_soc_read(codec, AC97_GPIO_CFG);
+               snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100);
+               reg = snd_soc_read(codec, AC97_GPIO_PULL);
+               snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15));
+       }
+
+       return 0;
+}
+
+static int rear_amp_event(struct snd_soc_dapm_widget *widget,
+                         struct snd_kcontrol *kctl, int event)
+{
+       struct snd_soc_codec *codec = widget->codec;
+
+       return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
+}
+
+/* mioa701 machine dapm widgets */
+static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Front Speaker", NULL),
+       SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event),
+       SND_SOC_DAPM_MIC("Headset", NULL),
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Front Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Call Mic */
+       {"Mic Bias", NULL, "Front Mic"},
+       {"MIC1", NULL, "Mic Bias"},
+
+       /* Headset Mic */
+       {"LINEL", NULL, "Headset Mic"},
+       {"LINER", NULL, "Headset Mic"},
+
+       /* GSM Module */
+       {"MONOIN", NULL, "GSM Line Out"},
+       {"PCBEEP", NULL, "GSM Line Out"},
+       {"GSM Line In", NULL, "MONO"},
+
+       /* headphone connected to HPL, HPR */
+       {"Headset", NULL, "HPL"},
+       {"Headset", NULL, "HPR"},
+
+       /* front speaker connected to HPL, OUT3 */
+       {"Front Speaker", NULL, "HPL"},
+       {"Front Speaker", NULL, "OUT3"},
+
+       /* rear speaker connected to SPKL, SPKR */
+       {"Rear Speaker", NULL, "SPKL"},
+       {"Rear Speaker", NULL, "SPKR"},
+};
+
+static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+{
+       unsigned short reg;
+
+       /* Add mioa701 specific widgets */
+       snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+
+       /* Set up mioa701 specific audio path audio_mapnects */
+       snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
+
+       /* Prepare GPIO8 for rear speaker amplifier */
+       reg = codec->read(codec, AC97_GPIO_CFG);
+       codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+
+       /* Prepare MIC input */
+       reg = codec->read(codec, AC97_3D_CONTROL);
+       codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+
+       snd_soc_dapm_enable_pin(codec, "Front Speaker");
+       snd_soc_dapm_enable_pin(codec, "Rear Speaker");
+       snd_soc_dapm_enable_pin(codec, "Front Mic");
+       snd_soc_dapm_enable_pin(codec, "GSM Line In");
+       snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_ops mioa701_ops;
+
+static struct snd_soc_dai_link mioa701_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+               .init = mioa701_wm9713_init,
+               .ops = &mioa701_ops,
+       },
+       {
+               .name = "AC97 Aux",
+               .stream_name = "AC97 Aux",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+               .ops = &mioa701_ops,
+       },
+};
+
+static struct snd_soc_card mioa701 = {
+       .name = "MioA701",
+       .platform = &pxa2xx_soc_platform,
+       .dai_link = mioa701_dai,
+       .num_links = ARRAY_SIZE(mioa701_dai),
+};
+
+static struct snd_soc_device mioa701_snd_devdata = {
+       .card = &mioa701,
+       .codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *mioa701_snd_device;
+
+static int mioa701_wm9713_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (!machine_is_mioa701())
+               return -ENODEV;
+
+       dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will"
+                "lead to overheating and possible destruction of your device."
+                "Do not use without a good knowledge of mio's board design!\n");
+
+       mioa701_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!mioa701_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
+       mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+
+       ret = platform_device_add(mioa701_snd_device);
+       if (!ret)
+               return 0;
+
+       platform_device_put(mioa701_snd_device);
+       return ret;
+}
+
+static int __devexit mioa701_wm9713_remove(struct platform_device *pdev)
+{
+       platform_device_unregister(mioa701_snd_device);
+       return 0;
+}
+
+static struct platform_driver mioa701_wm9713_driver = {
+       .probe          = mioa701_wm9713_probe,
+       .remove         = __devexit_p(mioa701_wm9713_remove),
+       .driver         = {
+               .name           = "mioa701-wm9713",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init mioa701_asoc_init(void)
+{
+       return platform_driver_register(&mioa701_wm9713_driver);
+}
+
+static void __exit mioa701_asoc_exit(void)
+{
+       platform_driver_unregister(&mioa701_wm9713_driver);
+}
+
+module_init(mioa701_asoc_init);
+module_exit(mioa701_asoc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
+MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
+MODULE_LICENSE("GPL");
index 4a9cf3083af0b01c554147e9c5aa7e5071562787..48a73f64500bc6ce78e40b0de21e5ba0413ef521 100644 (file)
@@ -55,7 +55,7 @@ static void palm27x_ext_control(struct snd_soc_codec *codec)
 static int palm27x_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        /* check the jack status at stream startup */
        palm27x_ext_control(codec);
@@ -146,19 +146,16 @@ static const struct snd_kcontrol_new palm27x_controls[] = {
 
 static int palm27x_ac97_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        snd_soc_dapm_nc_pin(codec, "OUT3");
        snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
        /* add palm27x specific controls */
-       for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&palm27x_controls[i],
-                                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, palm27x_controls,
+                               ARRAY_SIZE(palm27x_controls));
+       if (err < 0)
+               return err;
 
        /* add palm27x specific widgets */
        snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
index 6e9827189fffdca01b79b9c38bb212ee4998ce17..ef7c6c8dc8f1995c47b9c7fffdb919703308bdb9 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/timer.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
@@ -77,7 +78,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
 static int poodle_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        /* check the jack status at stream startup */
        poodle_ext_control(codec);
@@ -240,19 +241,17 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
  */
 static int poodle_wm8731_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
        snd_soc_dapm_nc_pin(codec, "RLINEIN");
        snd_soc_dapm_enable_pin(codec, "MICIN");
 
        /* Add poodle specific controls */
-       for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&wm8731_poodle_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, wm8731_poodle_controls,
+                               ARRAY_SIZE(wm8731_poodle_controls));
+       if (err < 0)
+               return err;
 
        /* Add poodle specific widgets */
        snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
@@ -283,17 +282,42 @@ static struct snd_soc_card snd_soc_poodle = {
        .num_links = 1,
 };
 
-/* poodle audio private data */
-static struct wm8731_setup_data poodle_wm8731_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1b,
-};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = 0x1b;
+       strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(0);
+       if (!adapter) {
+               printk(KERN_ERR "can't get i2c adapter 0\n");
+               return -ENODEV;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               printk(KERN_ERR "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               return -ENODEV;
+       }
+
+       return 0;
+}
 
 /* poodle audio subsystem */
 static struct snd_soc_device poodle_snd_devdata = {
        .card = &snd_soc_poodle,
        .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &poodle_wm8731_setup,
 };
 
 static struct platform_device *poodle_snd_device;
@@ -305,6 +329,10 @@ static int __init poodle_init(void)
        if (!machine_is_poodle())
                return -ENODEV;
 
+       ret = wm8731_i2c_register();
+       if (ret != 0)
+               return ret;
+
        locomo_gpio_set_dir(&poodle_locomo_device.dev,
                POODLE_LOCOMO_GPIO_AMP_ON, 0);
        /* should we mute HP at startup - burning power ?*/
index 73cb6b4c2f2d5efade62ae67848d56fcf23cbd03..b0bf40973d5bf7836e8e5cf092924a66b54d6b85 100644 (file)
@@ -1,4 +1,3 @@
-#define DEBUG
 /*
  * pxa-ssp.c  --  ALSA Soc Audio Layer
  *
@@ -21,6 +20,8 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <asm/irq.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
@@ -221,9 +222,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
        int ret = 0;
 
        if (!cpu_dai->active) {
-               ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ);
-               if (ret < 0)
-                       return ret;
+               priv->dev.port = cpu_dai->id + 1;
+               priv->dev.irq = NO_IRQ;
+               clk_enable(priv->dev.ssp->clk);
                ssp_disable(&priv->dev);
        }
        return ret;
@@ -238,7 +239,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
 
        if (!cpu_dai->active) {
                ssp_disable(&priv->dev);
-               ssp_exit(&priv->dev);
+               clk_disable(priv->dev.ssp->clk);
        }
 }
 
@@ -298,7 +299,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        int val;
 
        u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
-               ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+               ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
 
        dev_dbg(&ssp->pdev->dev,
                "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
@@ -326,7 +327,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        case PXA_SSP_CLK_AUDIO:
                priv->sysclk = 0;
                ssp_set_scr(&priv->dev, 1);
-               sscr0 |= SSCR0_ADC;
+               sscr0 |= SSCR0_ACS;
                break;
        default:
                return -ENODEV;
@@ -520,9 +521,20 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        u32 sscr1;
        u32 sspsp;
 
+       /* check if we need to change anything at all */
+       if (priv->dai_fmt == fmt)
+               return 0;
+
+       /* we can only change the settings if the port is not in use */
+       if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+               dev_err(&ssp->pdev->dev,
+                       "can't change hardware dai format: stream is in use");
+               return -EINVAL;
+       }
+
        /* reset port settings */
        sscr0 = ssp_read_reg(ssp, SSCR0) &
-               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
        sspsp = 0;
 
@@ -545,18 +557,18 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               sscr0 |= SSCR0_MOD | SSCR0_PSP;
+               sscr0 |= SSCR0_PSP;
                sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
 
+               /* See hw_params() */
                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
                case SND_SOC_DAIFMT_NB_NF:
-                       sspsp |= SSPSP_FSRT;
+                       sspsp |= SSPSP_SFRMP;
                        break;
                case SND_SOC_DAIFMT_NB_IF:
-                       sspsp |= SSPSP_SFRMP | SSPSP_FSRT;
                        break;
                case SND_SOC_DAIFMT_IB_IF:
-                       sspsp |= SSPSP_SFRMP;
+                       sspsp |= SSPSP_SCMODE(3);
                        break;
                default:
                        return -EINVAL;
@@ -642,34 +654,65 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                        sscr0 |= SSCR0_FPCKE;
 #endif
                sscr0 |= SSCR0_DataSize(16);
-               if (params_channels(params) > 1)
-                       sscr0 |= SSCR0_EDSS;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
-               /* we must be in network mode (2 slots) for 24 bit stereo */
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
-               /* we must be in network mode (2 slots) for 32 bit stereo */
                break;
        }
        ssp_write_reg(ssp, SSCR0, sscr0);
 
        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               /* Cleared when the DAI format is set */
-               sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width);
+              sspsp = ssp_read_reg(ssp, SSPSP);
+
+               if (((sscr0 & SSCR0_SCR) == SSCR0_SerClkDiv(4)) &&
+                    (width == 16)) {
+                       /* This is a special case where the bitclk is 64fs
+                       * and we're not dealing with 2*32 bits of audio
+                       * samples.
+                       *
+                       * The SSP values used for that are all found out by
+                       * trying and failing a lot; some of the registers
+                       * needed for that mode are only available on PXA3xx.
+                       */
+
+#ifdef CONFIG_PXA3xx
+                       if (!cpu_is_pxa3xx())
+                               return -EINVAL;
+
+                       sspsp |= SSPSP_SFRMWDTH(width * 2);
+                       sspsp |= SSPSP_SFRMDLY(width * 4);
+                       sspsp |= SSPSP_EDMYSTOP(3);
+                       sspsp |= SSPSP_DMYSTOP(3);
+                       sspsp |= SSPSP_DMYSTRT(1);
+#else
+                       return -EINVAL;
+#endif
+               } else {
+                       /* The frame width is the width the LRCLK is
+                        * asserted for; the delay is expressed in
+                        * half cycle units.  We need the extra cycle
+                        * because the data starts clocking out one BCLK
+                        * after LRCLK changes polarity.
+                        */
+                       sspsp |= SSPSP_SFRMWDTH(width + 1);
+                       sspsp |= SSPSP_SFRMDLY((width + 1) * 2);
+                       sspsp |= SSPSP_DMYSTRT(1);
+               }
+
                ssp_write_reg(ssp, SSPSP, sspsp);
                break;
        default:
                break;
        }
 
-       /* We always use a network mode so we always require TDM slots
+       /* When we use a network mode, we always require TDM slots
         * - complain loudly and fail if they've not been set up yet.
         */
-       if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) {
+       if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) {
                dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
                return -EINVAL;
        }
@@ -751,7 +794,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
        if (!priv)
                return -ENOMEM;
 
-       priv->dev.ssp = ssp_request(dai->id, "SoC audio");
+       priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio");
        if (priv->dev.ssp == NULL) {
                ret = -ENODEV;
                goto err_priv;
@@ -782,6 +825,19 @@ static void pxa_ssp_remove(struct platform_device *pdev,
                            SNDRV_PCM_FMTBIT_S24_LE |   \
                            SNDRV_PCM_FMTBIT_S32_LE)
 
+static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+       .startup        = pxa_ssp_startup,
+       .shutdown       = pxa_ssp_shutdown,
+       .trigger        = pxa_ssp_trigger,
+       .hw_params      = pxa_ssp_hw_params,
+       .set_sysclk     = pxa_ssp_set_dai_sysclk,
+       .set_clkdiv     = pxa_ssp_set_dai_clkdiv,
+       .set_pll        = pxa_ssp_set_dai_pll,
+       .set_fmt        = pxa_ssp_set_dai_fmt,
+       .set_tdm_slot   = pxa_ssp_set_dai_tdm_slot,
+       .set_tristate   = pxa_ssp_set_dai_tristate,
+};
+
 struct snd_soc_dai pxa_ssp_dai[] = {
        {
                .name = "pxa2xx-ssp1",
@@ -802,18 +858,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
-               .ops = {
-                       .startup = pxa_ssp_startup,
-                       .shutdown = pxa_ssp_shutdown,
-                       .trigger = pxa_ssp_trigger,
-                       .hw_params = pxa_ssp_hw_params,
-                       .set_sysclk = pxa_ssp_set_dai_sysclk,
-                       .set_clkdiv = pxa_ssp_set_dai_clkdiv,
-                       .set_pll = pxa_ssp_set_dai_pll,
-                       .set_fmt = pxa_ssp_set_dai_fmt,
-                       .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
-                       .set_tristate = pxa_ssp_set_dai_tristate,
-               },
+               .ops = &pxa_ssp_dai_ops,
        },
        {       .name = "pxa2xx-ssp2",
                .id = 1,
@@ -833,18 +878,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
-               .ops = {
-                       .startup = pxa_ssp_startup,
-                       .shutdown = pxa_ssp_shutdown,
-                       .trigger = pxa_ssp_trigger,
-                       .hw_params = pxa_ssp_hw_params,
-                       .set_sysclk = pxa_ssp_set_dai_sysclk,
-                       .set_clkdiv = pxa_ssp_set_dai_clkdiv,
-                       .set_pll = pxa_ssp_set_dai_pll,
-                       .set_fmt = pxa_ssp_set_dai_fmt,
-                       .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
-                       .set_tristate = pxa_ssp_set_dai_tristate,
-               },
+               .ops = &pxa_ssp_dai_ops,
        },
        {
                .name = "pxa2xx-ssp3",
@@ -865,18 +899,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
-               .ops = {
-                       .startup = pxa_ssp_startup,
-                       .shutdown = pxa_ssp_shutdown,
-                       .trigger = pxa_ssp_trigger,
-                       .hw_params = pxa_ssp_hw_params,
-                       .set_sysclk = pxa_ssp_set_dai_sysclk,
-                       .set_clkdiv = pxa_ssp_set_dai_clkdiv,
-                       .set_pll = pxa_ssp_set_dai_pll,
-                       .set_fmt = pxa_ssp_set_dai_fmt,
-                       .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
-                       .set_tristate = pxa_ssp_set_dai_tristate,
-               },
+               .ops = &pxa_ssp_dai_ops,
        },
        {
                .name = "pxa2xx-ssp4",
@@ -897,18 +920,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .rates = PXA_SSP_RATES,
                        .formats = PXA_SSP_FORMATS,
                 },
-               .ops = {
-                       .startup = pxa_ssp_startup,
-                       .shutdown = pxa_ssp_shutdown,
-                       .trigger = pxa_ssp_trigger,
-                       .hw_params = pxa_ssp_hw_params,
-                       .set_sysclk = pxa_ssp_set_dai_sysclk,
-                       .set_clkdiv = pxa_ssp_set_dai_clkdiv,
-                       .set_pll = pxa_ssp_set_dai_pll,
-                       .set_fmt = pxa_ssp_set_dai_fmt,
-                       .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
-                       .set_tristate = pxa_ssp_set_dai_tristate,
-               },
+               .ops = &pxa_ssp_dai_ops,
        },
 };
 EXPORT_SYMBOL_GPL(pxa_ssp_dai);
index 812c2b4d3e070d3357d06ce599a3e8025fba4211..01c21c6cdbbc2dd815f944f1b2df351f2b10ebec 100644 (file)
@@ -106,13 +106,13 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
 static int pxa2xx_ac97_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
-       return pxa2xx_ac97_hw_probe(pdev);
+       return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
 }
 
 static void pxa2xx_ac97_remove(struct platform_device *pdev,
                               struct snd_soc_dai *dai)
 {
-       pxa2xx_ac97_hw_remove(pdev);
+       pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
@@ -164,6 +164,18 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
+       .hw_params      = pxa2xx_ac97_hw_params,
+};
+
+static struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
+       .hw_params      = pxa2xx_ac97_hw_aux_params,
+};
+
+static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
+       .hw_params      = pxa2xx_ac97_hw_mic_params,
+};
+
 /*
  * There is only 1 physical AC97 interface for pxa2xx, but it
  * has extra fifo's that can be used for aux DACs and ADCs.
@@ -189,8 +201,7 @@ struct snd_soc_dai pxa_ac97_dai[] = {
                .channels_max = 2,
                .rates = PXA2XX_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = pxa2xx_ac97_hw_params,},
+       .ops = &pxa_ac97_hifi_dai_ops,
 },
 {
        .name = "pxa2xx-ac97-aux",
@@ -208,8 +219,7 @@ struct snd_soc_dai pxa_ac97_dai[] = {
                .channels_max = 1,
                .rates = PXA2XX_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = pxa2xx_ac97_hw_aux_params,},
+       .ops = &pxa_ac97_aux_dai_ops,
 },
 {
        .name = "pxa2xx-ac97-mic",
@@ -221,23 +231,52 @@ struct snd_soc_dai pxa_ac97_dai[] = {
                .channels_max = 1,
                .rates = PXA2XX_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = pxa2xx_ac97_hw_mic_params,},
+       .ops = &pxa_ac97_mic_dai_ops,
 },
 };
 
 EXPORT_SYMBOL_GPL(pxa_ac97_dai);
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
-static int __init pxa_ac97_init(void)
+static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++)
+               pxa_ac97_dai[i].dev = &pdev->dev;
+
+       /* Punt most of the init to the SoC probe; we may need the machine
+        * driver to do interesting things with the clocking to get us up
+        * and running.
+        */
        return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
 }
+
+static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+
+       return 0;
+}
+
+static struct platform_driver pxa2xx_ac97_driver = {
+       .probe          = pxa2xx_ac97_dev_probe,
+       .remove         = __devexit_p(pxa2xx_ac97_dev_remove),
+       .driver         = {
+               .name   = "pxa2xx-ac97",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init pxa_ac97_init(void)
+{
+       return platform_driver_register(&pxa2xx_ac97_driver);
+}
 module_init(pxa_ac97_init);
 
 static void __exit pxa_ac97_exit(void)
 {
-       snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+       platform_driver_unregister(&pxa2xx_ac97_driver);
 }
 module_exit(pxa_ac97_exit);
 
index 517991fb10993f16cdbdc758479885da69a840d4..e6c24408c5f9fb23714b22173e2b1fad8a8877d8 100644 (file)
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
-struct pxa2xx_gpio {
-       u32 sys;
-       u32     rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
-};
-
 /*
  * I2S Controller Register and Bit Definitions
  */
@@ -106,21 +97,6 @@ static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
                                  DCMD_BURST32 | DCMD_WIDTH4,
 };
 
-static struct pxa2xx_gpio gpio_bus[] = {
-       { /* I2S SoC Slave */
-               .rx = GPIO29_SDATA_IN_I2S_MD,
-               .tx = GPIO30_SDATA_OUT_I2S_MD,
-               .clk = GPIO28_BITCLK_IN_I2S_MD,
-               .frm = GPIO31_SYNC_I2S_MD,
-       },
-       { /* I2S SoC Master */
-               .rx = GPIO29_SDATA_IN_I2S_MD,
-               .tx = GPIO30_SDATA_OUT_I2S_MD,
-               .clk = GPIO28_BITCLK_OUT_I2S_MD,
-               .frm = GPIO31_SYNC_I2S_MD,
-       },
-};
-
 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
@@ -181,9 +157,6 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        if (clk_id != PXA2XX_I2S_SYSCLK)
                return -ENODEV;
 
-       if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
-               pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
-
        return 0;
 }
 
@@ -194,10 +167,6 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
        pxa_i2s_wait();
@@ -335,6 +304,15 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
+static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+       .startup        = pxa2xx_i2s_startup,
+       .shutdown       = pxa2xx_i2s_shutdown,
+       .trigger        = pxa2xx_i2s_trigger,
+       .hw_params      = pxa2xx_i2s_hw_params,
+       .set_fmt        = pxa2xx_i2s_set_dai_fmt,
+       .set_sysclk     = pxa2xx_i2s_set_dai_sysclk,
+};
+
 struct snd_soc_dai pxa_i2s_dai = {
        .name = "pxa2xx-i2s",
        .id = 0,
@@ -350,14 +328,7 @@ struct snd_soc_dai pxa_i2s_dai = {
                .channels_max = 2,
                .rates = PXA2XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .startup = pxa2xx_i2s_startup,
-               .shutdown = pxa2xx_i2s_shutdown,
-               .trigger = pxa2xx_i2s_trigger,
-               .hw_params = pxa2xx_i2s_hw_params,
-               .set_fmt = pxa2xx_i2s_set_dai_fmt,
-               .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
-       },
+       .ops = &pxa_i2s_dai_ops,
 };
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
@@ -398,11 +369,6 @@ static struct platform_driver pxa2xx_i2s_driver = {
 
 static int __init pxa2xx_i2s_init(void)
 {
-       if (cpu_is_pxa27x())
-               gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD;
-       else
-               gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD;
-
        clk_i2s = ERR_PTR(-ENOENT);
        return platform_driver_register(&pxa2xx_i2s_driver);
 }
index a3b9e6bdf9794cb1350d34448efeddbee1989591..6ca9f53080c67862ef235e9171f28c004e94ef79 100644 (file)
@@ -109,7 +109,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec)
 static int spitz_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        /* check the jack status at stream startup */
        spitz_ext_control(codec);
@@ -278,7 +278,7 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
  */
 static int spitz_wm8750_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        /* NC codec pins */
        snd_soc_dapm_nc_pin(codec, "RINPUT1");
@@ -290,12 +290,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
        snd_soc_dapm_nc_pin(codec, "MONO1");
 
        /* Add spitz specific controls */
-       for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, wm8750_spitz_controls,
+                               ARRAY_SIZE(wm8750_spitz_controls));
+       if (err < 0)
+               return err;
 
        /* Add spitz specific widgets */
        snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
index c77194f74c9b56eea9438db006c0d4b37b7912b5..fc781374b1bfa234cba453ed85459747e6d58be0 100644 (file)
@@ -82,7 +82,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->codec;
+       struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
        /* check the jack status at stream startup */
        tosa_ext_control(codec);
@@ -188,18 +188,16 @@ static const struct snd_kcontrol_new tosa_controls[] = {
 
 static int tosa_ac97_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
        snd_soc_dapm_nc_pin(codec, "OUT3");
        snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
        /* add tosa specific controls */
-       for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&tosa_controls[i],codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, tosa_controls,
+                               ARRAY_SIZE(tosa_controls));
+       if (err < 0)
+               return err;
 
        /* add tosa specific widgets */
        snd_soc_dapm_new_controls(codec, tosa_dapm_widgets,
index f8e9ecd589d3cf5d163573b2fb4eaee3a8dc397f..9a386b4c4ed13f09118bd27ed8a53cd8a3f63f45 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "pxa2xx-ac97.h"
 #include "pxa-ssp.h"
 
+/*
+ * There is a physical switch SW15 on the board which changes the MCLK
+ * for the WM9713 between the standard AC97 master clock and the
+ * output of the CLK_POUT signal from the PXA.
+ */
+static int clk_pout;
+module_param(clk_pout, int, 0);
+MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board).");
+
+static struct clk *pout;
+
 static struct snd_soc_card zylonite;
 
 static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = {
@@ -61,10 +73,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int zylonite_wm9713_init(struct snd_soc_codec *codec)
 {
-       /* Currently we only support use of the AC97 clock here.  If
-        * CLK_POUT is selected by SW15 then the clock API will need
-        * to be used to request and enable it here.
-        */
+       if (clk_pout)
+               snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0);
 
        snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
                                  ARRAY_SIZE(zylonite_dapm_widgets));
@@ -86,40 +96,35 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        unsigned int pll_out = 0;
-       unsigned int acds = 0;
        unsigned int wm9713_div = 0;
        int ret = 0;
+       int rate = params_rate(params);
+       int width = snd_pcm_format_physical_width(params_format(params));
 
-       switch (params_rate(params)) {
+       /* Only support ratios that we can generate neatly from the AC97
+        * based master clock - in particular, this excludes 44.1kHz.
+        * In most applications the voice DAC will be used for telephony
+        * data so multiples of 8kHz will be the common case.
+        */
+       switch (rate) {
        case 8000:
                wm9713_div = 12;
-               pll_out = 2048000;
                break;
        case 16000:
                wm9713_div = 6;
-               pll_out = 4096000;
                break;
        case 48000:
-       default:
                wm9713_div = 2;
-               pll_out = 12288000;
-               acds = 1;
                break;
+       default:
+               /* Don't support OSS emulation */
+               return -EINVAL;
        }
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
+       /* Add 1 to the width for the leading clock cycle */
+       pll_out = rate * (width + 1) * 8;
 
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai,
-                                      params_channels(params),
-                                      params_channels(params));
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
        if (ret < 0)
                return ret;
 
@@ -127,19 +132,22 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds);
+       if (clk_pout)
+               ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
+                                            WM9713_PCMDIV(wm9713_div));
+       else
+               ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
+                                            WM9713_PCMDIV(wm9713_div));
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
-       /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs
-        * to be set instead.
-        */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
-                                    WM9713_PCMDIV(wm9713_div));
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
@@ -173,8 +181,72 @@ static struct snd_soc_dai_link zylonite_dai[] = {
 },
 };
 
+static int zylonite_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (clk_pout) {
+               pout = clk_get(NULL, "CLK_POUT");
+               if (IS_ERR(pout)) {
+                       dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n",
+                               PTR_ERR(pout));
+                       return PTR_ERR(pout);
+               }
+
+               ret = clk_enable(pout);
+               if (ret != 0) {
+                       dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+                               ret);
+                       clk_put(pout);
+                       return ret;
+               }
+
+               dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n",
+                       clk_get_rate(pout));
+       }
+
+       return 0;
+}
+
+static int zylonite_remove(struct platform_device *pdev)
+{
+       if (clk_pout) {
+               clk_disable(pout);
+               clk_put(pout);
+       }
+
+       return 0;
+}
+
+static int zylonite_suspend_post(struct platform_device *pdev,
+                                pm_message_t state)
+{
+       if (clk_pout)
+               clk_disable(pout);
+
+       return 0;
+}
+
+static int zylonite_resume_pre(struct platform_device *pdev)
+{
+       int ret = 0;
+
+       if (clk_pout) {
+               ret = clk_enable(pout);
+               if (ret != 0)
+                       dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+                               ret);
+       }
+
+       return ret;
+}
+
 static struct snd_soc_card zylonite = {
        .name = "Zylonite",
+       .probe = &zylonite_probe,
+       .remove = &zylonite_remove,
+       .suspend_post = &zylonite_suspend_post,
+       .resume_pre = &zylonite_resume_pre,
        .platform = &pxa2xx_soc_platform,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
index fcd03acf10f6cd4a51d504c12ed4bf4c49d84eb8..2f3a21eee051750c99aaca707e7fda6b10c750bd 100644 (file)
@@ -1,19 +1,31 @@
 config SND_S3C24XX_SOC
-       tristate "SoC Audio for the Samsung S3C24XX chips"
-       depends on ARCH_S3C2410
+       tristate "SoC Audio for the Samsung S3CXXXX chips"
+       depends on ARCH_S3C2410 || ARCH_S3C64XX
        help
          Say Y or M if you want to add support for codecs attached to
-         the S3C24XX AC97, I2S or SSP interface. You will also need
-         to select the audio interfaces to support below.
+         the S3C24XX and S3C64XX AC97, I2S or SSP interface. You will
+         also need to select the audio interfaces to support below.
 
 config SND_S3C24XX_SOC_I2S
        tristate
+       select S3C2410_DMA
+
+config SND_S3C_I2SV2_SOC
+       tristate
 
 config SND_S3C2412_SOC_I2S
        tristate
+       select SND_S3C_I2SV2_SOC
+       select S3C2410_DMA
+
+config SND_S3C64XX_SOC_I2S
+       tristate
+       select SND_S3C_I2SV2_SOC
+       select S3C64XX_DMA
 
 config SND_S3C2443_SOC_AC97
        tristate
+       select S3C2410_DMA
        select AC97_BUS
        select SND_SOC_AC97_BUS
        
@@ -26,6 +38,14 @@ config SND_S3C24XX_SOC_NEO1973_WM8753
          Say Y if you want to add support for SoC audio on smdk2440
          with the WM8753.
 
+config SND_S3C24XX_SOC_JIVE_WM8750
+       tristate "SoC I2S Audio support for Jive"
+       depends on SND_S3C24XX_SOC && MACH_JIVE
+       select SND_SOC_WM8750
+       select SND_S3C2412_SOC_I2S
+       help
+         Sat Y if you want to add support for SoC audio on the Jive.
+
 config SND_S3C24XX_SOC_SMDK2443_WM9710
        tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
        depends on SND_S3C24XX_SOC && MACH_SMDK2443
@@ -48,4 +68,5 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X
        tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
                depends on SND_S3C24XX_SOC
                select SND_S3C24XX_SOC_I2S
+       select SND_SOC_L3
                select SND_SOC_UDA134X
index 96b3f3f617d4280dddb8fa03c5d0aa95ec9a1e11..07a93a2ebe5f35ca92062b4b44e972207829dc87 100644 (file)
@@ -2,19 +2,25 @@
 snd-soc-s3c24xx-objs := s3c24xx-pcm.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
+snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
 snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
+snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
 obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
 obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
+obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
+obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
 
 # S3C24XX Machine Support
+snd-soc-jive-wm8750-objs := jive_wm8750.o
 snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
 snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
 snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
 snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 
+obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
 obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
new file mode 100644 (file)
index 0000000..3206379
--- /dev/null
@@ -0,0 +1,201 @@
+/* sound/soc/s3c24xx/jive_wm8750.c
+ *
+ * Copyright 2007,2008 Simtec Electronics
+ *
+ * Based on sound/soc/pxa/spitz.c
+ *     Copyright 2005 Wolfson Microelectronics PLC.
+ *     Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c2412-i2s.h"
+
+#include "../codecs/wm8750.h"
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "Headphone Jack", NULL, "LOUT1" },
+       { "Headphone Jack", NULL, "ROUT1" },
+       { "Internal Speaker", NULL, "LOUT2" },
+       { "Internal Speaker", NULL, "ROUT2" },
+       { "LINPUT1", NULL, "Line Input" },
+       { "RINPUT1", NULL, "Line Input" },
+};
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Internal Speaker", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static int jive_hw_params(struct snd_pcm_substream *substream,
+                         struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct s3c_i2sv2_rate_calc div;
+       unsigned int clk = 0;
+       int ret = 0;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+               clk = 11289600;
+               break;
+       }
+
+       s3c_i2sv2_calc_rate(&div, NULL, params_rate(params),
+                           s3c2412_get_iisclk());
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
+                                    div.clk_div - 1);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops jive_ops = {
+       .hw_params      = jive_hw_params,
+};
+
+static int jive_wm8750_init(struct snd_soc_codec *codec)
+{
+       int err;
+
+       /* These endpoints are not being used. */
+       snd_soc_dapm_nc_pin(codec, "LINPUT2");
+       snd_soc_dapm_nc_pin(codec, "RINPUT2");
+       snd_soc_dapm_nc_pin(codec, "LINPUT3");
+       snd_soc_dapm_nc_pin(codec, "RINPUT3");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "MONO");
+
+       /* Add jive specific widgets */
+       err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+                                       ARRAY_SIZE(wm8750_dapm_widgets));
+       if (err) {
+               printk(KERN_ERR "%s: failed to add widgets (%d)\n",
+                      __func__, err);
+               return err;
+       }
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link jive_dai = {
+       .name           = "wm8750",
+       .stream_name    = "WM8750",
+       .cpu_dai        = &s3c2412_i2s_dai,
+       .codec_dai      = &wm8750_dai,
+       .init           = jive_wm8750_init,
+       .ops            = &jive_ops,
+};
+
+/* jive audio machine driver */
+static struct snd_soc_machine snd_soc_machine_jive = {
+       .name           = "Jive",
+       .dai_link       = &jive_dai,
+       .num_links      = 1,
+};
+
+/* jive audio private data */
+static struct wm8750_setup_data jive_wm8750_setup = {
+};
+
+/* jive audio subsystem */
+static struct snd_soc_device jive_snd_devdata = {
+       .machine        = &snd_soc_machine_jive,
+       .platform       = &s3c24xx_soc_platform,
+       .codec_dev      = &soc_codec_dev_wm8750_spi,
+       .codec_data     = &jive_wm8750_setup,
+};
+
+static struct platform_device *jive_snd_device;
+
+static int __init jive_init(void)
+{
+       int ret;
+
+       if (!machine_is_jive())
+               return 0;
+
+       printk("JIVE WM8750 Audio support\n");
+
+       jive_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!jive_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
+       jive_snd_devdata.dev = &jive_snd_device->dev;
+       ret = platform_device_add(jive_snd_device);
+
+       if (ret)
+               platform_device_put(jive_snd_device);
+
+       return ret;
+}
+
+static void __exit jive_exit(void)
+{
+       platform_device_unregister(jive_snd_device);
+}
+
+module_init(jive_init);
+module_exit(jive_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
+MODULE_LICENSE("GPL");
index 45bb12e8ea447df922a5f99c02d9479569bd632d..289fadf60b1038a24585f3c4bf7e65f8046a8b46 100644 (file)
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
 #include <linux/io.h>
 #include <mach/spi-gpio.h>
 
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 
 #include "../codecs/wm8753.h"
 #include "lm4857.h"
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
-/* Debugging stuff */
-#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0
-#if S3C24XX_SOC_NEO1973_WM8753_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x)
-#else
-#define DBG(x...)
-#endif
-
 /* define the scenarios */
 #define NEO_AUDIO_OFF                  0
 #define NEO_GSM_CALL_AUDIO_HANDSET     1
@@ -72,7 +64,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
        int ret = 0;
        unsigned long iis_clkrate;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iis_clkrate = s3c24xx_i2s_get_clockrate();
 
@@ -158,7 +150,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* disable the PLL */
        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
@@ -181,7 +173,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
        int ret = 0;
        unsigned long iis_clkrate;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iis_clkrate = s3c24xx_i2s_get_clockrate();
 
@@ -224,7 +216,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* disable the PLL */
        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
@@ -246,7 +238,7 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
 
 static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        switch (neo1973_scenario) {
        case NEO_AUDIO_OFF:
@@ -330,7 +322,7 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (neo1973_scenario == ucontrol->value.integer.value[0])
                return 0;
@@ -344,7 +336,7 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
 
 static void lm4857_write_regs(void)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
                printk(KERN_ERR "lm4857: i2c write failed\n");
@@ -357,7 +349,7 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0x0F;
        int mask = (kcontrol->private_value >> 16) & 0xFF;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
        return 0;
@@ -385,7 +377,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
 {
        u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (value)
                value -= 5;
@@ -399,7 +391,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
 {
        u8 value = ucontrol->value.integer.value[0];
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (value)
                value += 5;
@@ -506,9 +498,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
  */
 static int neo1973_wm8753_init(struct snd_soc_codec *codec)
 {
-       int i, err;
+       int err;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* set up NC codec pins */
        snd_soc_dapm_nc_pin(codec, "LOUT2");
@@ -526,13 +518,10 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
        set_scenario_endpoints(codec, NEO_AUDIO_OFF);
 
        /* add neo1973 specific controls */
-       for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
-               err = snd_ctl_add(codec->card,
-                               snd_soc_cnew(&wm8753_neo1973_controls[i],
-                               codec, NULL));
-               if (err < 0)
-                       return err;
-       }
+       err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
+                               ARRAY_SIZE(8753_neo1973_controls));
+       if (err < 0)
+               return err;
 
        /* set up neo1973 specific audio routes */
        err = snd_soc_dapm_add_routes(codec, dapm_routes,
@@ -585,21 +574,15 @@ static struct snd_soc_card neo1973 = {
        .num_links = ARRAY_SIZE(neo1973_dai),
 };
 
-static struct wm8753_setup_data neo1973_wm8753_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1a,
-};
-
 static struct snd_soc_device neo1973_snd_devdata = {
        .card = &neo1973,
        .codec_dev = &soc_codec_dev_wm8753,
-       .codec_data = &neo1973_wm8753_setup,
 };
 
 static int lm4857_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        i2c = client;
 
@@ -609,7 +592,7 @@ static int lm4857_i2c_probe(struct i2c_client *client,
 
 static int lm4857_i2c_remove(struct i2c_client *client)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        i2c = NULL;
 
@@ -620,7 +603,7 @@ static u8 lm4857_state;
 
 static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        dev_dbg(&dev->dev, "lm4857_suspend\n");
        lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
@@ -633,7 +616,7 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
 
 static int lm4857_resume(struct i2c_client *dev)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (lm4857_state) {
                lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
@@ -644,7 +627,7 @@ static int lm4857_resume(struct i2c_client *dev)
 
 static void lm4857_shutdown(struct i2c_client *dev)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        dev_dbg(&dev->dev, "lm4857_shutdown\n");
        lm4857_regs[LM4857_CTRL] &= 0xf0;
@@ -675,7 +658,7 @@ static int __init neo1973_init(void)
 {
        int ret;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (!machine_is_neo1973_gta01()) {
                printk(KERN_INFO
@@ -706,7 +689,7 @@ static int __init neo1973_init(void)
 
 static void __exit neo1973_exit(void)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        i2c_del_driver(&lm4857_i2c_driver);
        platform_device_unregister(neo1973_snd_device);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
new file mode 100644 (file)
index 0000000..295a4c9
--- /dev/null
@@ -0,0 +1,638 @@
+/* sound/soc/s3c24xx/s3c-i2c-v2.c
+ *
+ * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ *     Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *     linux@wolfsonmicro.com
+ *
+ * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/regs-s3c2412-iis.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_I2S_DEBUG_CON 0
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return cpu_dai->private_data;
+}
+
+#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
+
+#if S3C2412_I2S_DEBUG_CON
+static void dbg_showcon(const char *fn, u32 con)
+{
+       printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_LRINDEX),
+              bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
+              bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
+
+       printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
+              fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
+       printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
+}
+#else
+static inline void dbg_showcon(const char *fn, u32 con)
+{
+}
+#endif
+
+
+/* Turn on or off the transmission path. */
+void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       pr_debug("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_TXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_TXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXONLY:
+               case S3C2412_IISMOD_MODE_TXRX:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       } else {
+               /* Note, we do not have any indication that the FIFO problems
+                * tha the S3C2410/2440 had apply here, so we should be able
+                * to disable the DMA and TX without resetting the FIFOS.
+                */
+
+               con |=  S3C2412_IISCON_TXDMA_PAUSE;
+               con |=  S3C2412_IISCON_TXCH_PAUSE;
+               con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_RXONLY;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       dbg_showcon(__func__, con);
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
+
+void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       pr_debug("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_RXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       } else {
+               /* See txctrl notes on FIFOs. */
+
+               con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
+               con |=  S3C2412_IISCON_RXDMA_PAUSE;
+               con |=  S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXONLY;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
+{
+       u32 iiscon;
+       unsigned long timeout = jiffies + msecs_to_jiffies(5);
+
+       pr_debug("Entered %s\n", __func__);
+
+       while (1) {
+               iiscon = readl(i2s->regs + S3C2412_IISCON);
+               if (iiscon & S3C2412_IISCON_LRINDEX)
+                       break;
+
+               if (timeout < jiffies) {
+                       printk(KERN_ERR "%s: timeout\n", __func__);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Set S3C2412 I2S DAI format
+ */
+static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
+#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
+#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
+#endif
+
+#if defined(CONFIG_PLAT_S3C64XX)
+/* From Rev1.1 datasheet, we have two master and two slave modes:
+ * IMS[11:10]:
+ *     00 = master mode, fed from PCLK
+ *     01 = master mode, fed from CLKAUDIO
+ *     10 = slave mode, using PCLK
+ *     11 = slave mode, using I2SCLK
+ */
+#define IISMOD_MASTER_MASK (1 << 11)
+#define IISMOD_SLAVE (1 << 11)
+#define IISMOD_MASTER (0x0)
+#endif
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               i2s->master = 0;
+               iismod &= ~IISMOD_MASTER_MASK;
+               iismod |= IISMOD_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s->master = 1;
+               iismod &= ~IISMOD_MASTER_MASK;
+               iismod |= IISMOD_MASTER;
+               break;
+       default:
+               pr_debug("unknwon master/slave format\n");
+               return -EINVAL;
+       }
+
+       iismod &= ~S3C2412_IISMOD_SDF_MASK;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iismod |= S3C2412_IISMOD_SDF_MSB;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iismod |= S3C2412_IISMOD_SDF_LSB;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               iismod |= S3C2412_IISMOD_SDF_IIS;
+               break;
+       default:
+               pr_debug("Unknown data format\n");
+               return -EINVAL;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("hw_params w: IISMOD: %x \n", iismod);
+       return 0;
+}
+
+static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *dai = rtd->dai;
+       struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dai->cpu_dai->dma_data = i2s->dma_playback;
+       else
+               dai->cpu_dai->dma_data = i2s->dma_capture;
+
+       /* Working copies of register */
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               iismod |= S3C2412_IISMOD_8BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iismod &= ~S3C2412_IISMOD_8BIT;
+               break;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+       return 0;
+}
+
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+       unsigned long irqs;
+       int ret = 0;
+
+       pr_debug("Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* On start, ensure that the FIFOs are cleared and reset. */
+
+               writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
+                      i2s->regs + S3C2412_IISFIC);
+
+               /* clear again, just in case */
+               writel(0x0, i2s->regs + S3C2412_IISFIC);
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!i2s->master) {
+                       ret = s3c2412_snd_lrsync(i2s);
+                       if (ret)
+                               goto exit_err;
+               }
+
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(i2s, 1);
+               else
+                       s3c2412_snd_txctrl(i2s, 1);
+
+               local_irq_restore(irqs);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(i2s, 0);
+               else
+                       s3c2412_snd_txctrl(i2s, 0);
+
+               local_irq_restore(irqs);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+exit_err:
+       return ret;
+}
+
+/*
+ * Set S3C2412 Clock dividers
+ */
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                 int div_id, int div)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 reg;
+
+       pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+       switch (div_id) {
+       case S3C_I2SV2_DIV_BCLK:
+               reg = readl(i2s->regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_BCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+
+               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C_I2SV2_DIV_RCLK:
+               if (div > 3) {
+                       /* convert value to bit field */
+
+                       switch (div) {
+                       case 256:
+                               div = S3C2412_IISMOD_RCLK_256FS;
+                               break;
+
+                       case 384:
+                               div = S3C2412_IISMOD_RCLK_384FS;
+                               break;
+
+                       case 512:
+                               div = S3C2412_IISMOD_RCLK_512FS;
+                               break;
+
+                       case 768:
+                               div = S3C2412_IISMOD_RCLK_768FS;
+                               break;
+
+                       default:
+                               return -EINVAL;
+                       }
+               }
+
+               reg = readl(i2s->regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_RCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C_I2SV2_DIV_PRESCALER:
+               if (div >= 0) {
+                       writel((div << 8) | S3C2412_IISPSR_PSREN,
+                              i2s->regs + S3C2412_IISPSR);
+               } else {
+                       writel(0x0, i2s->regs + S3C2412_IISPSR);
+               }
+               pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* default table of all avaialable root fs divisors */
+static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
+
+int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+                         unsigned int *fstab,
+                         unsigned int rate, struct clk *clk)
+{
+       unsigned long clkrate = clk_get_rate(clk);
+       unsigned int div;
+       unsigned int fsclk;
+       unsigned int actual;
+       unsigned int fs;
+       unsigned int fsdiv;
+       signed int deviation = 0;
+       unsigned int best_fs = 0;
+       unsigned int best_div = 0;
+       unsigned int best_rate = 0;
+       unsigned int best_deviation = INT_MAX;
+
+       if (fstab == NULL)
+               fstab = iis_fs_tab;
+
+       for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
+               fsdiv = iis_fs_tab[fs];
+
+               fsclk = clkrate / fsdiv;
+               div = fsclk / rate;
+
+               if ((fsclk % rate) > (rate / 2))
+                       div++;
+
+               if (div <= 1)
+                       continue;
+
+               actual = clkrate / (fsdiv * div);
+               deviation = actual - rate;
+
+               printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
+                      fsdiv, div, actual, deviation);
+
+               deviation = abs(deviation);
+
+               if (deviation < best_deviation) {
+                       best_fs = fsdiv;
+                       best_div = div;
+                       best_rate = actual;
+                       best_deviation = deviation;
+               }
+
+               if (deviation == 0)
+                       break;
+       }
+
+       printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
+              best_fs, best_div, best_rate);
+
+       info->fs_div = best_fs;
+       info->clk_div = best_div;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
+
+int s3c_i2sv2_probe(struct platform_device *pdev,
+                   struct snd_soc_dai *dai,
+                   struct s3c_i2sv2_info *i2s,
+                   unsigned long base)
+{
+       struct device *dev = &pdev->dev;
+
+       i2s->dev = dev;
+
+       /* record our i2s structure for later use in the callbacks */
+       dai->private_data = i2s;
+
+       i2s->regs = ioremap(base, 0x100);
+       if (i2s->regs == NULL) {
+               dev_err(dev, "cannot ioremap registers\n");
+               return -ENXIO;
+       }
+
+       i2s->iis_pclk = clk_get(dev, "iis");
+       if (i2s->iis_pclk == NULL) {
+               dev_err(dev, "failed to get iis_clock\n");
+               iounmap(i2s->regs);
+               return -ENOENT;
+       }
+
+       clk_enable(i2s->iis_pclk);
+
+       s3c2412_snd_txctrl(i2s, 0);
+       s3c2412_snd_rxctrl(i2s, 0);
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
+
+#ifdef CONFIG_PM
+static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+       u32 iismod;
+
+       if (dai->active) {
+               i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
+               i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
+               i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
+
+               /* some basic suspend checks */
+
+               iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+               if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
+                       pr_warning("%s: RXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
+                       pr_warning("%s: TXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_IIS_ACTIVE)
+                       pr_warning("%s: IIS active\n", __func__);
+       }
+
+       return 0;
+}
+
+static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+
+       pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
+               dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+
+       if (dai->active) {
+               writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
+               writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
+               writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
+
+               writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
+                      i2s->regs + S3C2412_IISFIC);
+
+               ndelay(250);
+               writel(0x0, i2s->regs + S3C2412_IISFIC);
+       }
+
+       return 0;
+}
+#else
+#define s3c2412_i2s_suspend NULL
+#define s3c2412_i2s_resume  NULL
+#endif
+
+int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+{
+       dai->ops.trigger = s3c2412_i2s_trigger;
+       dai->ops.hw_params = s3c2412_i2s_hw_params;
+       dai->ops.set_fmt = s3c2412_i2s_set_fmt;
+       dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv;
+
+       dai->suspend = s3c2412_i2s_suspend;
+       dai->resume = s3c2412_i2s_resume;
+
+       return snd_soc_register_dai(dai);
+}
+
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
new file mode 100644 (file)
index 0000000..f66854a
--- /dev/null
@@ -0,0 +1,90 @@
+/* sound/soc/s3c24xx/s3c-i2s-v2.h
+ *
+ * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+*/
+
+/* This code is the core support for the I2S block found in a number of
+ * Samsung SoC devices which is unofficially named I2S-V2. Currently the
+ * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
+ * channels via configurable GPIO.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
+#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
+
+#define S3C_I2SV2_DIV_BCLK     (1)
+#define S3C_I2SV2_DIV_RCLK     (2)
+#define S3C_I2SV2_DIV_PRESCALER        (3)
+
+/**
+ * struct s3c_i2sv2_info - S3C I2S-V2 information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device registe block.
+ * @master: True if the I2S core is the I2S bit clock master.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ * @suspend_iismod: PM save for the IISMOD register.
+ * @suspend_iiscon: PM save for the IISCON register.
+ * @suspend_iispsr: PM save for the IISPSR register.
+ *
+ * This is the private codec state for the hardware associated with an
+ * I2S channel such as the register mappings and clock sources.
+ */
+struct s3c_i2sv2_info {
+       struct device   *dev;
+       void __iomem    *regs;
+
+       struct clk      *iis_pclk;
+       struct clk      *iis_cclk;
+       struct clk      *iis_clk;
+
+       unsigned char    master;
+
+       struct s3c24xx_pcm_dma_params   *dma_playback;
+       struct s3c24xx_pcm_dma_params   *dma_capture;
+
+       u32              suspend_iismod;
+       u32              suspend_iiscon;
+       u32              suspend_iispsr;
+};
+
+struct s3c_i2sv2_rate_calc {
+       unsigned int    clk_div;        /* for prescaler */
+       unsigned int    fs_div;         /* for root frame clock */
+};
+
+extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+                                  unsigned int *fstab,
+                                  unsigned int rate, struct clk *clk);
+
+/**
+ * s3c_i2sv2_probe - probe for i2s device helper
+ * @pdev: The platform device supplied to the original probe.
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ * @base: The base address for the registers.
+ */
+extern int s3c_i2sv2_probe(struct platform_device *pdev,
+                          struct snd_soc_dai *dai,
+                          struct s3c_i2sv2_info *i2s,
+                          unsigned long base);
+
+/**
+ * s3c_i2sv2_register_dai - register dai with soc core
+ * @dai: The snd_soc_dai structure to register
+ *
+ * Fill in any missing fields and then register the given dai with the
+ * soc core.
+ */
+extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+
+#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
index f3fc0aba0aaf78755d2e0170eeabcc82d575f31b..1ca3cdaa82133b009b57b2fd571bc9069524eb80 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <mach/hardware.h>
 
-#include <linux/io.h>
-#include <asm/dma.h>
-
-#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
+#include <plat/regs-s3c2412-iis.h>
 
-#include <mach/regs-gpio.h>
-#include <mach/audio.h>
+#include <plat/regs-gpio.h>
+#include <plat/audio.h>
 #include <mach/dma.h>
 
 #include "s3c24xx-pcm.h"
 #include "s3c2412-i2s.h"
 
 #define S3C2412_I2S_DEBUG 0
-#define S3C2412_I2S_DEBUG_CON 0
-
-#if S3C2412_I2S_DEBUG
-#define DBG(x...) printk(KERN_INFO x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
 
 static struct s3c2410_dma_client s3c2412_dma_client_out = {
        .name           = "I2S PCM Stereo out"
@@ -73,431 +64,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
        .dma_size       = 4,
 };
 
-struct s3c2412_i2s_info {
-       struct device   *dev;
-       void __iomem    *regs;
-       struct clk      *iis_clk;
-       struct clk      *iis_pclk;
-       struct clk      *iis_cclk;
-
-       u32              suspend_iismod;
-       u32              suspend_iiscon;
-       u32              suspend_iispsr;
-};
-
-static struct s3c2412_i2s_info s3c2412_i2s;
-
-#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
-
-#if S3C2412_I2S_DEBUG_CON
-static void dbg_showcon(const char *fn, u32 con)
-{
-       printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
-              bit_set(con, S3C2412_IISCON_LRINDEX),
-              bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
-              bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
-              bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
-              bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
-
-       printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
-              fn,
-              bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
-              bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
-              bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
-              bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
-       printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
-              bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
-              bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
-              bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
-}
-#else
-static inline void dbg_showcon(const char *fn, u32 con)
-{
-}
-#endif
-
-/* Turn on or off the transmission path. */
-static void s3c2412_snd_txctrl(int on)
-{
-       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-       void __iomem *regs = i2s->regs;
-       u32 fic, con, mod;
-
-       DBG("%s(%d)\n", __func__, on);
-
-       fic = readl(regs + S3C2412_IISFIC);
-       con = readl(regs + S3C2412_IISCON);
-       mod = readl(regs + S3C2412_IISMOD);
-
-       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
-       if (on) {
-               con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
-               con &= ~S3C2412_IISCON_TXDMA_PAUSE;
-               con &= ~S3C2412_IISCON_TXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXONLY:
-               case S3C2412_IISMOD_MODE_TXRX:
-                       /* do nothing, we are in the right mode */
-                       break;
-
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXRX;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
-               }
-
-               writel(con, regs + S3C2412_IISCON);
-               writel(mod, regs + S3C2412_IISMOD);
-       } else {
-               /* Note, we do not have any indication that the FIFO problems
-                * tha the S3C2410/2440 had apply here, so we should be able
-                * to disable the DMA and TX without resetting the FIFOS.
-                */
-
-               con |=  S3C2412_IISCON_TXDMA_PAUSE;
-               con |=  S3C2412_IISCON_TXCH_PAUSE;
-               con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXRX:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_RXONLY;
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
-               }
-
-               writel(mod, regs + S3C2412_IISMOD);
-               writel(con, regs + S3C2412_IISCON);
-       }
-
-       fic = readl(regs + S3C2412_IISFIC);
-       dbg_showcon(__func__, con);
-       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-static void s3c2412_snd_rxctrl(int on)
-{
-       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-       void __iomem *regs = i2s->regs;
-       u32 fic, con, mod;
-
-       DBG("%s(%d)\n", __func__, on);
-
-       fic = readl(regs + S3C2412_IISFIC);
-       con = readl(regs + S3C2412_IISCON);
-       mod = readl(regs + S3C2412_IISMOD);
-
-       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
-       if (on) {
-               con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
-               con &= ~S3C2412_IISCON_RXDMA_PAUSE;
-               con &= ~S3C2412_IISCON_RXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXRX:
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       /* do nothing, we are in the right mode */
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXRX;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
-               }
-
-               writel(mod, regs + S3C2412_IISMOD);
-               writel(con, regs + S3C2412_IISCON);
-       } else {
-               /* See txctrl notes on FIFOs. */
-
-               con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
-               con |=  S3C2412_IISCON_RXDMA_PAUSE;
-               con |=  S3C2412_IISCON_RXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXRX:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXONLY;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
-               }
-
-               writel(con, regs + S3C2412_IISCON);
-               writel(mod, regs + S3C2412_IISMOD);
-       }
-
-       fic = readl(regs + S3C2412_IISFIC);
-       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c2412_snd_lrsync(void)
-{
-       u32 iiscon;
-       unsigned long timeout = jiffies + msecs_to_jiffies(5);
-
-       DBG("Entered %s\n", __func__);
-
-       while (1) {
-               iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON);
-               if (iiscon & S3C2412_IISCON_LRINDEX)
-                       break;
-
-               if (timeout < jiffies) {
-                       printk(KERN_ERR "%s: timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Check whether CPU is the master or slave
- */
-static inline int s3c2412_snd_is_clkmaster(void)
-{
-       u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
-
-       DBG("Entered %s\n", __func__);
-
-       iismod &= S3C2412_IISMOD_MASTER_MASK;
-       return !(iismod == S3C2412_IISMOD_SLAVE);
-}
-
-/*
- * Set S3C2412 I2S DAI format
- */
-static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
-                              unsigned int fmt)
-{
-       u32 iismod;
-
-
-       DBG("Entered %s\n", __func__);
-
-       iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
-       DBG("hw_params r: IISMOD: %x \n", iismod);
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
-               iismod |= S3C2412_IISMOD_SLAVE;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
-               iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
-               break;
-       default:
-               DBG("unknwon master/slave format\n");
-               return -EINVAL;
-       }
-
-       iismod &= ~S3C2412_IISMOD_SDF_MASK;
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_RIGHT_J:
-               iismod |= S3C2412_IISMOD_SDF_MSB;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               iismod |= S3C2412_IISMOD_SDF_LSB;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               iismod |= S3C2412_IISMOD_SDF_IIS;
-               break;
-       default:
-               DBG("Unknown data format\n");
-               return -EINVAL;
-       }
-
-       writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
-       DBG("hw_params w: IISMOD: %x \n", iismod);
-       return 0;
-}
-
-static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       u32 iismod;
-
-       DBG("Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
-       else
-               rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
-
-       /* Working copies of register */
-       iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
-       DBG("%s: r: IISMOD: %x\n", __func__, iismod);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               iismod |= S3C2412_IISMOD_8BIT;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               iismod &= ~S3C2412_IISMOD_8BIT;
-               break;
-       }
-
-       writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
-       DBG("%s: w: IISMOD: %x\n", __func__, iismod);
-       return 0;
-}
-
-static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                              struct snd_soc_dai *dai)
-{
-       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-       unsigned long irqs;
-       int ret = 0;
-
-       DBG("Entered %s\n", __func__);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* On start, ensure that the FIFOs are cleared and reset. */
-
-               writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
-                      s3c2412_i2s.regs + S3C2412_IISFIC);
-
-               /* clear again, just in case */
-               writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (!s3c2412_snd_is_clkmaster()) {
-                       ret = s3c2412_snd_lrsync();
-                       if (ret)
-                               goto exit_err;
-               }
-
-               local_irq_save(irqs);
-
-               if (capture)
-                       s3c2412_snd_rxctrl(1);
-               else
-                       s3c2412_snd_txctrl(1);
-
-               local_irq_restore(irqs);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               local_irq_save(irqs);
-
-               if (capture)
-                       s3c2412_snd_rxctrl(0);
-               else
-                       s3c2412_snd_txctrl(0);
-
-               local_irq_restore(irqs);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-exit_err:
-       return ret;
-}
-
-/* default table of all avaialable root fs divisors */
-static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
-
-int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
-                         unsigned int *fstab,
-                         unsigned int rate, struct clk *clk)
-{
-       unsigned long clkrate = clk_get_rate(clk);
-       unsigned int div;
-       unsigned int fsclk;
-       unsigned int actual;
-       unsigned int fs;
-       unsigned int fsdiv;
-       signed int deviation = 0;
-       unsigned int best_fs = 0;
-       unsigned int best_div = 0;
-       unsigned int best_rate = 0;
-       unsigned int best_deviation = INT_MAX;
-
-
-       if (fstab == NULL)
-               fstab = s3c2412_iis_fs;
-
-       for (fs = 0;; fs++) {
-               fsdiv = s3c2412_iis_fs[fs];
-
-               if (fsdiv == 0)
-                       break;
-
-               fsclk = clkrate / fsdiv;
-               div = fsclk / rate;
-
-               if ((fsclk % rate) > (rate / 2))
-                       div++;
-
-               if (div <= 1)
-                       continue;
-
-               actual = clkrate / (fsdiv * div);
-               deviation = actual - rate;
-
-               printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
-                      fsdiv, div, actual, deviation);
-
-               deviation = abs(deviation);
-
-               if (deviation < best_deviation) {
-                       best_fs = fsdiv;
-                       best_div = div;
-                       best_rate = actual;
-                       best_deviation = deviation;
-               }
-
-               if (deviation == 0)
-                       break;
-       }
-
-       printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
-              best_fs, best_div, best_rate);
-
-       info->fs_div = best_fs;
-       info->clk_div = best_div;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
+static struct s3c_i2sv2_info s3c2412_i2s;
 
 /*
  * Set S3C2412 Clock source
@@ -507,15 +74,17 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 {
        u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
 
-       DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
+       pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
            freq, dir);
 
        switch (clk_id) {
        case S3C2412_CLKSRC_PCLK:
+               s3c2412_i2s.master = 1;
                iismod &= ~S3C2412_IISMOD_MASTER_MASK;
                iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
                break;
        case S3C2412_CLKSRC_I2SCLK:
+               s3c2412_i2s.master = 0;
                iismod &= ~S3C2412_IISMOD_MASTER_MASK;
                iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
                break;
@@ -527,74 +96,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-/*
- * Set S3C2412 Clock dividers
- */
-static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
-                                 int div_id, int div)
-{
-       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-       u32 reg;
-
-       DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
-
-       switch (div_id) {
-       case S3C2412_DIV_BCLK:
-               reg = readl(i2s->regs + S3C2412_IISMOD);
-               reg &= ~S3C2412_IISMOD_BCLK_MASK;
-               writel(reg | div, i2s->regs + S3C2412_IISMOD);
-
-               DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
-               break;
-
-       case S3C2412_DIV_RCLK:
-               if (div > 3) {
-                       /* convert value to bit field */
-
-                       switch (div) {
-                       case 256:
-                               div = S3C2412_IISMOD_RCLK_256FS;
-                               break;
-
-                       case 384:
-                               div = S3C2412_IISMOD_RCLK_384FS;
-                               break;
-
-                       case 512:
-                               div = S3C2412_IISMOD_RCLK_512FS;
-                               break;
-
-                       case 768:
-                               div = S3C2412_IISMOD_RCLK_768FS;
-                               break;
-
-                       default:
-                               return -EINVAL;
-                       }
-               }
-
-               reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
-               reg &= ~S3C2412_IISMOD_RCLK_MASK;
-               writel(reg | div, i2s->regs + S3C2412_IISMOD);
-               DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
-               break;
-
-       case S3C2412_DIV_PRESCALER:
-               if (div >= 0) {
-                       writel((div << 8) | S3C2412_IISPSR_PSREN,
-                              i2s->regs + S3C2412_IISPSR);
-               } else {
-                       writel(0x0, i2s->regs + S3C2412_IISPSR);
-               }
-               DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
 
 struct clk *s3c2412_get_iisclk(void)
 {
@@ -606,34 +107,30 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
 static int s3c2412_i2s_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
-       DBG("Entered %s\n", __func__);
+       int ret;
 
-       s3c2412_i2s.dev = &pdev->dev;
+       pr_debug("Entered %s\n", __func__);
 
-       s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
-       if (s3c2412_i2s.regs == NULL)
-               return -ENXIO;
+       ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+       if (ret)
+               return ret;
 
-       s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis");
-       if (s3c2412_i2s.iis_pclk == NULL) {
-               DBG("failed to get iis_clock\n");
-               iounmap(s3c2412_i2s.regs);
-               return -ENODEV;
-       }
+       s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
+       s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
 
        s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
        if (s3c2412_i2s.iis_cclk == NULL) {
-               DBG("failed to get i2sclk clock\n");
+               pr_debug("failed to get i2sclk clock\n");
                iounmap(s3c2412_i2s.regs);
                return -ENODEV;
        }
 
-       clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
+       /* Set MPLL as the source for IIS CLK */
 
-       clk_enable(s3c2412_i2s.iis_pclk);
+       clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
        clk_enable(s3c2412_i2s.iis_cclk);
 
-       s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk;
+       s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
 
        /* Configure the I2S pins in correct mode */
        s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
@@ -642,78 +139,22 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
        s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
        s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
 
-       s3c2412_snd_txctrl(0);
-       s3c2412_snd_rxctrl(0);
-
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
-{
-       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-       u32 iismod;
-
-       if (dai->active) {
-               i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
-               i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
-               i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
-
-               /* some basic suspend checks */
-
-               iismod = readl(i2s->regs + S3C2412_IISMOD);
-
-               if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
-                       pr_warning("%s: RXDMA active?\n", __func__);
-
-               if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
-                       pr_warning("%s: TXDMA active?\n", __func__);
-
-               if (iismod & S3C2412_IISCON_IIS_ACTIVE)
-                       pr_warning("%s: IIS active\n", __func__);
-       }
-
-       return 0;
-}
-
-static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
-{
-       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-
-       pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
-               dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
-
-       if (dai->active) {
-               writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
-               writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
-               writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
-
-               writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
-                      i2s->regs + S3C2412_IISFIC);
-
-               ndelay(250);
-               writel(0x0, i2s->regs + S3C2412_IISFIC);
-
-       }
-
-       return 0;
-}
-#else
-#define s3c2412_i2s_suspend NULL
-#define s3c2412_i2s_resume  NULL
-#endif /* CONFIG_PM */
-
 #define S3C2412_I2S_RATES \
        (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
+static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
+       .set_sysclk     = s3c2412_i2s_set_sysclk,
+};
+
 struct snd_soc_dai s3c2412_i2s_dai = {
-       .name   = "s3c2412-i2s",
-       .id     = 0,
-       .probe  = s3c2412_i2s_probe,
-       .suspend = s3c2412_i2s_suspend,
-       .resume = s3c2412_i2s_resume,
+       .name           = "s3c2412-i2s",
+       .id             = 0,
+       .probe          = s3c2412_i2s_probe,
        .playback = {
                .channels_min   = 2,
                .channels_max   = 2,
@@ -726,19 +167,13 @@ struct snd_soc_dai s3c2412_i2s_dai = {
                .rates          = S3C2412_I2S_RATES,
                .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .ops = {
-               .trigger        = s3c2412_i2s_trigger,
-               .hw_params      = s3c2412_i2s_hw_params,
-               .set_fmt        = s3c2412_i2s_set_fmt,
-               .set_clkdiv     = s3c2412_i2s_set_clkdiv,
-               .set_sysclk     = s3c2412_i2s_set_sysclk,
-       },
+       .ops = &s3c2412_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
 
 static int __init s3c2412_i2s_init(void)
 {
-       return snd_soc_register_dai(&s3c2412_i2s_dai);
+       return  s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
 }
 module_init(s3c2412_i2s_init);
 
@@ -748,7 +183,6 @@ static void __exit s3c2412_i2s_exit(void)
 }
 module_exit(s3c2412_i2s_exit);
 
-
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
index aac08a25e541df2dc2cb6e0c0ebba094029105c7..92848e54be16d049a71b7b7f91bdbe6df04a878e 100644 (file)
 #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
 #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
 
-#define S3C2412_DIV_BCLK       (1)
-#define S3C2412_DIV_RCLK       (2)
-#define S3C2412_DIV_PRESCALER  (3)
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_DIV_BCLK       S3C_I2SV2_DIV_BCLK
+#define S3C2412_DIV_RCLK       S3C_I2SV2_DIV_RCLK
+#define S3C2412_DIV_PRESCALER  S3C_I2SV2_DIV_PRESCALER
 
 #define S3C2412_CLKSRC_PCLK    (0)
 #define S3C2412_CLKSRC_I2SCLK  (1)
@@ -26,13 +28,4 @@ extern struct clk *s3c2412_get_iisclk(void);
 
 extern struct snd_soc_dai s3c2412_i2s_dai;
 
-struct s3c2412_rate_calc {
-       unsigned int    clk_div;        /* for prescaler */
-       unsigned int    fs_div;         /* for root frame clock */
-};
-
-extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
-                                unsigned int *fstab,
-                                unsigned int rate, struct clk *clk);
-
 #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
index 5822d2dd49ba9c1d2acbc6dee0c4c9b6c6777247..3698f707c44d0e53fdbc916d717211bf97a279ca 100644 (file)
@@ -31,7 +31,7 @@
 #include <plat/regs-ac97.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
 #include <asm/dma.h>
 #include <mach/dma.h>
 
@@ -355,6 +355,16 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
+static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = {
+       .hw_params      = s3c2443_ac97_hw_params,
+       .trigger        = s3c2443_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = {
+       .hw_params      = s3c2443_ac97_hw_mic_params,
+       .trigger        = s3c2443_ac97_mic_trigger,
+};
+
 struct snd_soc_dai s3c2443_ac97_dai[] = {
 {
        .name = "s3c2443-ac97",
@@ -374,9 +384,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = {
                .channels_max = 2,
                .rates = s3c2443_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = s3c2443_ac97_hw_params,
-               .trigger = s3c2443_ac97_trigger},
+       .ops = &s3c2443_ac97_dai_ops,
 },
 {
        .name = "pxa2xx-ac97-mic",
@@ -388,9 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = {
                .channels_max = 1,
                .rates = s3c2443_AC97_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .hw_params = s3c2443_ac97_hw_mic_params,
-               .trigger = s3c2443_ac97_mic_trigger,},
+       .ops = &s3c2443_ac97_mic_dai_ops,
 },
 };
 EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
index 6f4d439b57aaecf4a388d8a2ce80c3caa9301ace..cc066964dad6fe34eb7709115474c522ac0d80ba 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 2006 Wolfson Microelectronics PLC.
  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
  *
- * (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
-#define S3C24XX_I2S_DEBUG 0
-#if S3C24XX_I2S_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x)
-#else
-#define DBG(x...)
-#endif
-
 static struct s3c2410_dma_client s3c24xx_dma_client_out = {
        .name = "I2S PCM Stereo out"
 };
@@ -84,13 +77,13 @@ static void s3c24xx_snd_txctrl(int on)
        u32 iiscon;
        u32 iismod;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
        iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
        iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 
        if (on) {
                iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
@@ -120,7 +113,7 @@ static void s3c24xx_snd_txctrl(int on)
                writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
        }
 
-       DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 }
 
 static void s3c24xx_snd_rxctrl(int on)
@@ -129,13 +122,13 @@ static void s3c24xx_snd_rxctrl(int on)
        u32 iiscon;
        u32 iismod;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
        iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
        iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 
        if (on) {
                iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
@@ -165,7 +158,7 @@ static void s3c24xx_snd_rxctrl(int on)
                writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
        }
 
-       DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 }
 
 /*
@@ -177,7 +170,7 @@ static int s3c24xx_snd_lrsync(void)
        u32 iiscon;
        int timeout = 50; /* 5ms */
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        while (1) {
                iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -197,7 +190,7 @@ static int s3c24xx_snd_lrsync(void)
  */
 static inline int s3c24xx_snd_is_clkmaster(void)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
 }
@@ -210,10 +203,10 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 {
        u32 iismod;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params r: IISMOD: %lx \n", iismod);
+       pr_debug("hw_params r: IISMOD: %x \n", iismod);
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
@@ -238,7 +231,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        }
 
        writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params w: IISMOD: %lx \n", iismod);
+       pr_debug("hw_params w: IISMOD: %x \n", iismod);
        return 0;
 }
 
@@ -249,7 +242,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        u32 iismod;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;
@@ -258,7 +251,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* Working copies of register */
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params r: IISMOD: %lx\n", iismod);
+       pr_debug("hw_params r: IISMOD: %x\n", iismod);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
@@ -276,7 +269,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
        }
 
        writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params w: IISMOD: %lx\n", iismod);
+       pr_debug("hw_params w: IISMOD: %x\n", iismod);
        return 0;
 }
 
@@ -285,7 +278,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        int ret = 0;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -327,7 +320,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 {
        u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        iismod &= ~S3C2440_IISMOD_MPLL;
 
@@ -353,7 +346,7 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
 {
        u32 reg;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        switch (div_id) {
        case S3C24XX_DIV_BCLK:
@@ -389,7 +382,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 static int s3c24xx_i2s_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
        if (s3c24xx_i2s.regs == NULL)
@@ -397,7 +390,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
 
        s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
        if (s3c24xx_i2s.iis_clk == NULL) {
-               DBG("failed to get iis_clock\n");
+               pr_err("failed to get iis_clock\n");
                iounmap(s3c24xx_i2s.regs);
                return -ENODEV;
        }
@@ -421,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
 #ifdef CONFIG_PM
 static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
        s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -435,7 +428,7 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
 
 static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
 {
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
        clk_enable(s3c24xx_i2s.iis_clk);
 
        writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -456,6 +449,14 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
+static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+       .trigger        = s3c24xx_i2s_trigger,
+       .hw_params      = s3c24xx_i2s_hw_params,
+       .set_fmt        = s3c24xx_i2s_set_fmt,
+       .set_clkdiv     = s3c24xx_i2s_set_clkdiv,
+       .set_sysclk     = s3c24xx_i2s_set_sysclk,
+};
+
 struct snd_soc_dai s3c24xx_i2s_dai = {
        .name = "s3c24xx-i2s",
        .id = 0,
@@ -472,13 +473,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
                .channels_max = 2,
                .rates = S3C24XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .trigger = s3c24xx_i2s_trigger,
-               .hw_params = s3c24xx_i2s_hw_params,
-               .set_fmt = s3c24xx_i2s_set_fmt,
-               .set_clkdiv = s3c24xx_i2s_set_clkdiv,
-               .set_sysclk = s3c24xx_i2s_set_sysclk,
-       },
+       .ops = &s3c24xx_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
 
index 7c64d31d067e7283714c070001cf4c7f99764f84..a9d68fa2b34a337b8d3ac853a0b2467612cb290f 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 2006 Wolfson Microelectronics PLC.
  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
  *
- * (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
 #include <asm/dma.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
 
 #include "s3c24xx-pcm.h"
 
-#define S3C24XX_PCM_DEBUG 0
-#if S3C24XX_PCM_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x)
-#else
-#define DBG(x...)
-#endif
-
 static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -84,16 +77,16 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
        dma_addr_t pos = prtd->dma_pos;
        int ret;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        while (prtd->dma_loaded < prtd->dma_limit) {
                unsigned long len = prtd->dma_period;
 
-               DBG("dma_loaded: %d\n", prtd->dma_loaded);
+               pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
 
                if ((pos + len) > prtd->dma_end) {
                        len  = prtd->dma_end - pos;
-                       DBG(KERN_DEBUG "%s: corrected dma len %ld\n",
+                       pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
                               __func__, len);
                }
 
@@ -119,7 +112,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
        struct snd_pcm_substream *substream = dev_id;
        struct s3c24xx_runtime_data *prtd;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
                return;
@@ -148,7 +141,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
        unsigned long totbytes = params_buffer_bytes(params);
        int ret = 0;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -161,14 +154,14 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
                /* prepare DMA */
                prtd->params = dma;
 
-               DBG("params %p, client %p, channel %d\n", prtd->params,
+               pr_debug("params %p, client %p, channel %d\n", prtd->params,
                        prtd->params->client, prtd->params->channel);
 
                ret = s3c2410_dma_request(prtd->params->channel,
                                          prtd->params->client, NULL);
 
                if (ret < 0) {
-                       DBG(KERN_ERR "failed to get dma channel\n");
+                       printk(KERN_ERR "failed to get dma channel\n");
                        return ret;
                }
        }
@@ -196,7 +189,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* TODO - do we need to ensure DMA flushed */
        snd_pcm_set_runtime_buffer(substream, NULL);
@@ -214,7 +207,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
        int ret = 0;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -259,7 +252,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
        int ret = 0;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        spin_lock(&prtd->lock);
 
@@ -297,7 +290,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
        unsigned long res;
        dma_addr_t src, dst;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        spin_lock(&prtd->lock);
        s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
@@ -309,7 +302,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
 
        spin_unlock(&prtd->lock);
 
-       DBG("Pointer %x %x\n", src, dst);
+       pr_debug("Pointer %x %x\n", src, dst);
 
        /* we seem to be getting the odd error from the pcm library due
         * to out-of-bounds pointers. this is maybe due to the dma engine
@@ -330,7 +323,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
 
@@ -349,10 +342,10 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct s3c24xx_runtime_data *prtd = runtime->private_data;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (!prtd)
-               DBG("s3c24xx_pcm_close called with prtd == NULL\n");
+               pr_debug("s3c24xx_pcm_close called with prtd == NULL\n");
 
        kfree(prtd);
 
@@ -364,7 +357,7 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        return dma_mmap_writecombine(substream->pcm->card->dev, vma,
                                     runtime->dma_area,
@@ -390,7 +383,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        struct snd_dma_buffer *buf = &substream->dma_buffer;
        size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        buf->dev.type = SNDRV_DMA_TYPE_DEV;
        buf->dev.dev = pcm->card->dev;
@@ -409,7 +402,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        struct snd_dma_buffer *buf;
        int stream;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        for (stream = 0; stream < 2; stream++) {
                substream = pcm->streams[stream].substream;
@@ -433,7 +426,7 @@ static int s3c24xx_pcm_new(struct snd_card *card,
 {
        int ret = 0;
 
-       DBG("Entered %s\n", __func__);
+       pr_debug("Entered %s\n", __func__);
 
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &s3c24xx_pcm_dmamask;
index a0a4d1832a1407db4a018100cb856eb87eea343c..8e79a416db57b06c8f68ab8ae01f13690d9b7c3f 100644 (file)
@@ -22,7 +22,7 @@
 #include <sound/s3c24xx_uda134x.h>
 #include <sound/uda134x.h>
 
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
new file mode 100644 (file)
index 0000000..33c5de7
--- /dev/null
@@ -0,0 +1,222 @@
+/* sound/soc/s3c24xx/s3c64xx-i2s.c
+ *
+ * ALSA SoC Audio Layer - S3C64XX I2S driver
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/regs-s3c2412-iis.h>
+#include <plat/gpio-bank-d.h>
+#include <plat/gpio-bank-e.h>
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c64xx-i2s.h"
+
+static struct s3c2410_dma_client s3c64xx_dma_client_out = {
+       .name           = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c64xx_dma_client_in = {
+       .name           = "I2S PCM Stereo in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
+       [0] = {
+               .channel        = DMACH_I2S0_OUT,
+               .client         = &s3c64xx_dma_client_out,
+               .dma_addr       = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .channel        = DMACH_I2S1_OUT,
+               .client         = &s3c64xx_dma_client_out,
+               .dma_addr       = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
+       [0] = {
+               .channel        = DMACH_I2S0_IN,
+               .client         = &s3c64xx_dma_client_in,
+               .dma_addr       = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .channel        = DMACH_I2S1_IN,
+               .client         = &s3c64xx_dma_client_in,
+               .dma_addr       = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c_i2sv2_info s3c64xx_i2s[2];
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return cpu_dai->private_data;
+}
+
+static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+       switch (clk_id) {
+       case S3C64XX_CLKSRC_PCLK:
+               iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX;
+               break;
+
+       case S3C64XX_CLKSRC_MUX:
+               iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+
+       return 0;
+}
+
+
+unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+
+       return clk_get_rate(i2s->iis_cclk);
+}
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate);
+
+static int s3c64xx_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
+{
+       struct device *dev = &pdev->dev;
+       struct s3c_i2sv2_info *i2s;
+       int ret;
+
+       dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id);
+
+       if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) {
+               dev_err(dev, "id %d out of range\n", pdev->id);
+               return -EINVAL;
+       }
+
+       i2s = &s3c64xx_i2s[pdev->id];
+
+       ret = s3c_i2sv2_probe(pdev, dai, i2s,
+                             pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0);
+       if (ret)
+               return ret;
+
+       i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
+       i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
+
+       i2s->iis_cclk = clk_get(dev, "audio-bus");
+       if (IS_ERR(i2s->iis_cclk)) {
+               dev_err(dev, "failed to get audio-bus");
+               iounmap(i2s->regs);
+               return -ENODEV;
+       }
+
+       /* configure GPIO for i2s port */
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
+               s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
+               s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
+               break;
+       case 1:
+               s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
+               s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
+               s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
+               s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+       }
+
+       return 0;
+}
+
+
+#define S3C64XX_I2S_RATES \
+       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define S3C64XX_I2S_FMTS \
+       (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
+       .set_sysclk     = s3c64xx_i2s_set_sysclk,       
+};
+
+struct snd_soc_dai s3c64xx_i2s_dai = {
+       .name           = "s3c64xx-i2s",
+       .id             = 0,
+       .probe          = s3c64xx_i2s_probe,
+       .playback = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C64XX_I2S_RATES,
+               .formats        = S3C64XX_I2S_FMTS,
+       },
+       .capture = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C64XX_I2S_RATES,
+               .formats        = S3C64XX_I2S_FMTS,
+       },
+       .ops = &s3c64xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
+
+static int __init s3c64xx_i2s_init(void)
+{
+       return  s3c_i2sv2_register_dai(&s3c64xx_i2s_dai);
+}
+module_init(s3c64xx_i2s_init);
+
+static void __exit s3c64xx_i2s_exit(void)
+{
+       snd_soc_unregister_dai(&s3c64xx_i2s_dai);
+}
+module_exit(s3c64xx_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
+MODULE_LICENSE("GPL");
+
+
+
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
new file mode 100644 (file)
index 0000000..b7ffe3c
--- /dev/null
@@ -0,0 +1,31 @@
+/* sound/soc/s3c24xx/s3c64xx-i2s.h
+ *
+ * ALSA SoC Audio Layer - S3C64XX I2S driver
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
+#define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
+
+#include "s3c-i2s-v2.h"
+
+#define S3C64XX_DIV_BCLK       S3C_I2SV2_DIV_BCLK
+#define S3C64XX_DIV_RCLK       S3C_I2SV2_DIV_RCLK
+#define S3C64XX_DIV_PRESCALER  S3C_I2SV2_DIV_PRESCALER
+
+#define S3C64XX_CLKSRC_PCLK    (0)
+#define S3C64XX_CLKSRC_MUX     (1)
+
+extern struct snd_soc_dai s3c64xx_i2s_dai;
+
+extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai);
+
+#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
index eab31838badfed9515a93a97a8eb020d50e4688e..41db75af3c69d3b64f2420e07acfb2ca3473fa45 100644 (file)
@@ -267,6 +267,10 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
 #define AC97_FMTS      \
        SNDRV_PCM_FMTBIT_S16_LE
 
+static struct snd_soc_dai_ops hac_dai_ops = {
+       .hw_params      = hac_hw_params,
+};
+
 struct snd_soc_dai sh4_hac_dai[] = {
 {
        .name                   = "HAC0",
@@ -284,9 +288,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
                .channels_min   = 2,
                .channels_max   = 2,
        },
-       .ops = {
-               .hw_params      = hac_hw_params,
-       },
+       .ops = &hac_dai_ops,
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
@@ -305,9 +307,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
                .channels_min   = 2,
                .channels_max   = 2,
        },
-       .ops = {
-               .hw_params      = hac_hw_params,
-       },
+       .ops = &hac_dai_ops,
 
 },
 #endif
index d1e5390fddeb7ff82c999aac717ca281e966864e..56fa0872abbbb54a2bfd8cfcbb6a579cbd1bc8be 100644 (file)
@@ -336,6 +336,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
         SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
 
+static struct snd_soc_dai_ops ssi_dai_ops = {
+       .startup        = ssi_startup,
+       .shutdown       = ssi_shutdown,
+       .trigger        = ssi_trigger,
+       .hw_params      = ssi_hw_params,
+       .set_sysclk     = ssi_set_sysclk,
+       .set_clkdiv     = ssi_set_clkdiv,
+       .set_fmt        = ssi_set_fmt,
+};
+
 struct snd_soc_dai sh4_ssi_dai[] = {
 {
        .name                   = "SSI0",
@@ -352,15 +362,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
                .channels_min   = 2,
                .channels_max   = 8,
        },
-       .ops = {
-               .startup        = ssi_startup,
-               .shutdown       = ssi_shutdown,
-               .trigger        = ssi_trigger,
-               .hw_params      = ssi_hw_params,
-               .set_sysclk     = ssi_set_sysclk,
-               .set_clkdiv     = ssi_set_clkdiv,
-               .set_fmt        = ssi_set_fmt,
-       },
+       .ops = &ssi_dai_ops,
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
@@ -378,15 +380,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
                .channels_min   = 2,
                .channels_max   = 8,
        },
-       .ops = {
-               .startup        = ssi_startup,
-               .shutdown       = ssi_shutdown,
-               .trigger        = ssi_trigger,
-               .hw_params      = ssi_hw_params,
-               .set_sysclk     = ssi_set_sysclk,
-               .set_clkdiv     = ssi_set_clkdiv,
-               .set_fmt        = ssi_set_fmt,
-       },
+       .ops = &ssi_dai_ops,
 },
 #endif
 };
index ec3f8bb4b51d9805d827279e8b025aeeb12d657a..6e710f705a749d5c3162c87cd47793ac68db006f 100644 (file)
@@ -133,8 +133,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        mutex_lock(&pcm_mutex);
 
        /* startup the audio subsystem */
-       if (cpu_dai->ops.startup) {
-               ret = cpu_dai->ops.startup(substream, cpu_dai);
+       if (cpu_dai->ops->startup) {
+               ret = cpu_dai->ops->startup(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open interface %s\n",
                                cpu_dai->name);
@@ -150,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (codec_dai->ops.startup) {
-               ret = codec_dai->ops.startup(substream, codec_dai);
+       if (codec_dai->ops->startup) {
+               ret = codec_dai->ops->startup(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open codec %s\n",
                                codec_dai->name);
@@ -234,7 +234,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                cpu_dai->capture.active = codec_dai->capture.active = 1;
        cpu_dai->active = codec_dai->active = 1;
        cpu_dai->runtime = runtime;
-       socdev->codec->active++;
+       card->codec->active++;
        mutex_unlock(&pcm_mutex);
        return 0;
 
@@ -247,8 +247,8 @@ codec_dai_err:
                platform->pcm_ops->close(substream);
 
 platform_err:
-       if (cpu_dai->ops.shutdown)
-               cpu_dai->ops.shutdown(substream, cpu_dai);
+       if (cpu_dai->ops->shutdown)
+               cpu_dai->ops->shutdown(substream, cpu_dai);
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -264,7 +264,7 @@ static void close_delayed_work(struct work_struct *work)
        struct snd_soc_card *card = container_of(work, struct snd_soc_card,
                                                 delayed_work.work);
        struct snd_soc_device *socdev = card->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        struct snd_soc_dai *codec_dai;
        int i;
 
@@ -319,7 +319,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -340,11 +340,11 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                snd_soc_dai_digital_mute(codec_dai, 1);
 
-       if (cpu_dai->ops.shutdown)
-               cpu_dai->ops.shutdown(substream, cpu_dai);
+       if (cpu_dai->ops->shutdown)
+               cpu_dai->ops->shutdown(substream, cpu_dai);
 
-       if (codec_dai->ops.shutdown)
-               codec_dai->ops.shutdown(substream, codec_dai);
+       if (codec_dai->ops->shutdown)
+               codec_dai->ops->shutdown(substream, codec_dai);
 
        if (machine->ops && machine->ops->shutdown)
                machine->ops->shutdown(substream);
@@ -387,7 +387,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
@@ -408,16 +408,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                }
        }
 
-       if (codec_dai->ops.prepare) {
-               ret = codec_dai->ops.prepare(substream, codec_dai);
+       if (codec_dai->ops->prepare) {
+               ret = codec_dai->ops->prepare(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: codec DAI prepare error\n");
                        goto out;
                }
        }
 
-       if (cpu_dai->ops.prepare) {
-               ret = cpu_dai->ops.prepare(substream, cpu_dai);
+       if (cpu_dai->ops->prepare) {
+               ret = cpu_dai->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: cpu DAI prepare error\n");
                        goto out;
@@ -494,8 +494,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (codec_dai->ops.hw_params) {
-               ret = codec_dai->ops.hw_params(substream, params, codec_dai);
+       if (codec_dai->ops->hw_params) {
+               ret = codec_dai->ops->hw_params(substream, params, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't set codec %s hw params\n",
                                codec_dai->name);
@@ -503,8 +503,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (cpu_dai->ops.hw_params) {
-               ret = cpu_dai->ops.hw_params(substream, params, cpu_dai);
+       if (cpu_dai->ops->hw_params) {
+               ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: interface %s hw params failed\n",
                                cpu_dai->name);
@@ -526,12 +526,12 @@ out:
        return ret;
 
 platform_err:
-       if (cpu_dai->ops.hw_free)
-               cpu_dai->ops.hw_free(substream, cpu_dai);
+       if (cpu_dai->ops->hw_free)
+               cpu_dai->ops->hw_free(substream, cpu_dai);
 
 interface_err:
-       if (codec_dai->ops.hw_free)
-               codec_dai->ops.hw_free(substream, codec_dai);
+       if (codec_dai->ops->hw_free)
+               codec_dai->ops->hw_free(substream, codec_dai);
 
 codec_err:
        if (machine->ops && machine->ops->hw_free)
@@ -553,7 +553,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -570,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
                platform->pcm_ops->hw_free(substream);
 
        /* now free hw params for the DAI's  */
-       if (codec_dai->ops.hw_free)
-               codec_dai->ops.hw_free(substream, codec_dai);
+       if (codec_dai->ops->hw_free)
+               codec_dai->ops->hw_free(substream, codec_dai);
 
-       if (cpu_dai->ops.hw_free)
-               cpu_dai->ops.hw_free(substream, cpu_dai);
+       if (cpu_dai->ops->hw_free)
+               cpu_dai->ops->hw_free(substream, cpu_dai);
 
        mutex_unlock(&pcm_mutex);
        return 0;
@@ -591,8 +591,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_soc_dai *codec_dai = machine->codec_dai;
        int ret;
 
-       if (codec_dai->ops.trigger) {
-               ret = codec_dai->ops.trigger(substream, cmd, codec_dai);
+       if (codec_dai->ops->trigger) {
+               ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
                if (ret < 0)
                        return ret;
        }
@@ -603,8 +603,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                        return ret;
        }
 
-       if (cpu_dai->ops.trigger) {
-               ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai);
+       if (cpu_dai->ops->trigger) {
+               ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
                if (ret < 0)
                        return ret;
        }
@@ -629,7 +629,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_card *card = socdev->card;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        int i;
 
        /* Due to the resume being scheduled into a workqueue we could
@@ -645,8 +645,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        /* mute any active DAC's */
        for (i = 0; i < card->num_links; i++) {
                struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
-               if (dai->ops.digital_mute && dai->playback.active)
-                       dai->ops.digital_mute(dai, 1);
+               if (dai->ops->digital_mute && dai->playback.active)
+                       dai->ops->digital_mute(dai, 1);
        }
 
        /* suspend all pcms */
@@ -705,7 +705,7 @@ static void soc_resume_deferred(struct work_struct *work)
        struct snd_soc_device *socdev = card->socdev;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        struct platform_device *pdev = to_platform_device(socdev->dev);
        int i;
 
@@ -741,8 +741,8 @@ static void soc_resume_deferred(struct work_struct *work)
        /* unmute any active DACs */
        for (i = 0; i < card->num_links; i++) {
                struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
-               if (dai->ops.digital_mute && dai->playback.active)
-                       dai->ops.digital_mute(dai, 0);
+               if (dai->ops->digital_mute && dai->playback.active)
+                       dai->ops->digital_mute(dai, 0);
        }
 
        for (i = 0; i < card->num_links; i++) {
@@ -982,8 +982,8 @@ static struct platform_driver soc_driver = {
 static int soc_new_pcm(struct snd_soc_device *socdev,
        struct snd_soc_dai_link *dai_link, int num)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = card->codec;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *codec_dai = dai_link->codec_dai;
        struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
@@ -998,7 +998,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
 
        rtd->dai = dai_link;
        rtd->socdev = socdev;
-       codec_dai->codec = socdev->codec;
+       codec_dai->codec = card->codec;
 
        /* check client and interface hw capabilities */
        sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
@@ -1048,9 +1048,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
 }
 
 /* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf)
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 {
-       struct snd_soc_codec *codec = devdata->codec;
        int i, step = 1, count = 0;
 
        if (!codec->reg_cache_size)
@@ -1090,7 +1089,7 @@ static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
        struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       return soc_codec_reg_show(devdata, buf);
+       return soc_codec_reg_show(devdata->card->codec, buf);
 }
 
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -1107,12 +1106,10 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
 {
        ssize_t ret;
        struct snd_soc_codec *codec = file->private_data;
-       struct device *card_dev = codec->card->dev;
-       struct snd_soc_device *devdata = card_dev->driver_data;
        char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
-       ret = soc_codec_reg_show(devdata, buf);
+       ret = soc_codec_reg_show(codec, buf);
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
        kfree(buf);
@@ -1309,19 +1306,19 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits);
  */
 int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
-       int ret = 0, i;
+       struct snd_soc_codec *codec = card->codec;
+       int ret, i;
 
        mutex_lock(&codec->mutex);
 
        /* register a sound card */
-       codec->card = snd_card_new(idx, xid, codec->owner, 0);
-       if (!codec->card) {
+       ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
+       if (ret < 0) {
                printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
                        codec->name);
                mutex_unlock(&codec->mutex);
-               return -ENODEV;
+               return ret;
        }
 
        codec->card->dev = socdev->dev;
@@ -1355,8 +1352,8 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
  */
 int snd_soc_init_card(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = card->codec;
        int ret = 0, i, ac97 = 0, err = 0;
 
        for (i = 0; i < card->num_links; i++) {
@@ -1407,7 +1404,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
        if (err < 0)
                printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 
-       soc_init_codec_debugfs(socdev->codec);
+       soc_init_codec_debugfs(codec);
        mutex_unlock(&codec->mutex);
 
 out:
@@ -1424,18 +1421,19 @@ EXPORT_SYMBOL_GPL(snd_soc_init_card);
  */
 void snd_soc_free_pcms(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 #ifdef CONFIG_SND_SOC_AC97_BUS
        struct snd_soc_dai *codec_dai;
        int i;
 #endif
 
        mutex_lock(&codec->mutex);
-       soc_cleanup_codec_debugfs(socdev->codec);
+       soc_cleanup_codec_debugfs(codec);
 #ifdef CONFIG_SND_SOC_AC97_BUS
        for (i = 0; i < codec->num_dai; i++) {
                codec_dai = &codec->dai[i];
-               if (codec_dai->ac97_control && codec->ac97) {
+               if (codec_dai->ac97_control && codec->ac97 &&
+                   strcmp(codec->name, "AC97") != 0) {
                        soc_ac97_dev_unregister(codec);
                        goto free_card;
                }
@@ -1497,6 +1495,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
 }
 EXPORT_SYMBOL_GPL(snd_soc_cnew);
 
+/**
+ * snd_soc_add_controls - add an array of controls to a codec.
+ * Convienience function to add a list of controls. Many codecs were
+ * duplicating this code.
+ *
+ * @codec: codec to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_controls(struct snd_soc_codec *codec,
+       const struct snd_kcontrol_new *controls, int num_controls)
+{
+       struct snd_card *card = codec->card;
+       int err, i;
+
+       for (i = 0; i < num_controls; i++) {
+               const struct snd_kcontrol_new *control = &controls[i];
+               err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
+               if (err < 0) {
+                       dev_err(codec->dev, "%s: Failed to add %s\n",
+                               codec->name, control->name);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_controls);
+
 /**
  * snd_soc_info_enum_double - enumerated double mixer info callback
  * @kcontrol: mixer control
@@ -2023,8 +2052,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       if (dai->ops.set_sysclk)
-               return dai->ops.set_sysclk(dai, clk_id, freq, dir);
+       if (dai->ops->set_sysclk)
+               return dai->ops->set_sysclk(dai, clk_id, freq, dir);
        else
                return -EINVAL;
 }
@@ -2043,8 +2072,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
-       if (dai->ops.set_clkdiv)
-               return dai->ops.set_clkdiv(dai, div_id, div);
+       if (dai->ops->set_clkdiv)
+               return dai->ops->set_clkdiv(dai, div_id, div);
        else
                return -EINVAL;
 }
@@ -2062,8 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
        int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
-       if (dai->ops.set_pll)
-               return dai->ops.set_pll(dai, pll_id, freq_in, freq_out);
+       if (dai->ops->set_pll)
+               return dai->ops->set_pll(dai, pll_id, freq_in, freq_out);
        else
                return -EINVAL;
 }
@@ -2078,8 +2107,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       if (dai->ops.set_fmt)
-               return dai->ops.set_fmt(dai, fmt);
+       if (dai->ops->set_fmt)
+               return dai->ops->set_fmt(dai, fmt);
        else
                return -EINVAL;
 }
@@ -2097,8 +2126,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int mask, int slots)
 {
-       if (dai->ops.set_sysclk)
-               return dai->ops.set_tdm_slot(dai, mask, slots);
+       if (dai->ops->set_sysclk)
+               return dai->ops->set_tdm_slot(dai, mask, slots);
        else
                return -EINVAL;
 }
@@ -2113,8 +2142,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-       if (dai->ops.set_sysclk)
-               return dai->ops.set_tristate(dai, tristate);
+       if (dai->ops->set_sysclk)
+               return dai->ops->set_tristate(dai, tristate);
        else
                return -EINVAL;
 }
@@ -2129,8 +2158,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-       if (dai->ops.digital_mute)
-               return dai->ops.digital_mute(dai, mute);
+       if (dai->ops->digital_mute)
+               return dai->ops->digital_mute(dai, mute);
        else
                return -EINVAL;
 }
@@ -2183,6 +2212,9 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
        return 0;
 }
 
+static struct snd_soc_dai_ops null_dai_ops = {
+};
+
 /**
  * snd_soc_register_dai - Register a DAI with the ASoC core
  *
@@ -2197,6 +2229,9 @@ int snd_soc_register_dai(struct snd_soc_dai *dai)
        if (!dai->dev)
                printk(KERN_WARNING "No device for DAI %s\n", dai->name);
 
+       if (!dai->ops)
+               dai->ops = &null_dai_ops;
+
        INIT_LIST_HEAD(&dai->list);
 
        mutex_lock(&client_mutex);
index a2f1da8b464602fbac5ec55e86295d0f5fcda7ec..735903a7467500f4d93d750e527a693d67eabaa2 100644 (file)
 static int dapm_up_seq[] = {
        snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
        snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
-       snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp,
-       snd_soc_dapm_spk, snd_soc_dapm_post
+       snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga,
+       snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
 };
+
 static int dapm_down_seq[] = {
        snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
-       snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
-       snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
-       snd_soc_dapm_post
+       snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
+       snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
+       snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post
 };
 
 static int dapm_status = 1;
@@ -101,7 +102,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 {
        switch (w->id) {
        case snd_soc_dapm_switch:
-       case snd_soc_dapm_mixer: {
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl: {
                int val;
                struct soc_mixer_control *mc = (struct soc_mixer_control *)
                        w->kcontrols[i].private_value;
@@ -323,15 +325,32 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
                        if (path->name != (char*)w->kcontrols[i].name)
                                continue;
 
-                       /* add dapm control with long name */
-                       name_len = 2 + strlen(w->name)
-                               + strlen(w->kcontrols[i].name);
+                       /* add dapm control with long name.
+                        * for dapm_mixer this is the concatenation of the
+                        * mixer and kcontrol name.
+                        * for dapm_mixer_named_ctl this is simply the
+                        * kcontrol name.
+                        */
+                       name_len = strlen(w->kcontrols[i].name) + 1;
+                       if (w->id != snd_soc_dapm_mixer_named_ctl)
+                               name_len += 1 + strlen(w->name);
+
                        path->long_name = kmalloc(name_len, GFP_KERNEL);
+
                        if (path->long_name == NULL)
                                return -ENOMEM;
 
-                       snprintf(path->long_name, name_len, "%s %s",
-                                w->name, w->kcontrols[i].name);
+                       switch (w->id) {
+                       default:
+                               snprintf(path->long_name, name_len, "%s %s",
+                                        w->name, w->kcontrols[i].name);
+                               break;
+                       case snd_soc_dapm_mixer_named_ctl:
+                               snprintf(path->long_name, name_len, "%s",
+                                        w->kcontrols[i].name);
+                               break;
+                       }
+
                        path->long_name[name_len - 1] = '\0';
 
                        path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
@@ -502,6 +521,137 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
+/*
+ * Scan a single DAPM widget for a complete audio path and update the
+ * power status appropriately.
+ */
+static int dapm_power_widget(struct snd_soc_codec *codec, int event,
+                            struct snd_soc_dapm_widget *w)
+{
+       int in, out, power_change, power, ret;
+
+       /* vmid - no action */
+       if (w->id == snd_soc_dapm_vmid)
+               return 0;
+
+       /* active ADC */
+       if (w->id == snd_soc_dapm_adc && w->active) {
+               in = is_connected_input_ep(w);
+               dapm_clear_walk(w->codec);
+               w->power = (in != 0) ? 1 : 0;
+               dapm_update_bits(w);
+               return 0;
+       }
+
+       /* active DAC */
+       if (w->id == snd_soc_dapm_dac && w->active) {
+               out = is_connected_output_ep(w);
+               dapm_clear_walk(w->codec);
+               w->power = (out != 0) ? 1 : 0;
+               dapm_update_bits(w);
+               return 0;
+       }
+
+       /* pre and post event widgets */
+       if (w->id == snd_soc_dapm_pre) {
+               if (!w->event)
+                       return 0;
+
+               if (event == SND_SOC_DAPM_STREAM_START) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_PRE_PMU);
+                       if (ret < 0)
+                               return ret;
+               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_PRE_PMD);
+                       if (ret < 0)
+                               return ret;
+               }
+               return 0;
+       }
+       if (w->id == snd_soc_dapm_post) {
+               if (!w->event)
+                       return 0;
+
+               if (event == SND_SOC_DAPM_STREAM_START) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_POST_PMU);
+                       if (ret < 0)
+                               return ret;
+               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_POST_PMD);
+                       if (ret < 0)
+                               return ret;
+               }
+               return 0;
+       }
+
+       /* all other widgets */
+       in = is_connected_input_ep(w);
+       dapm_clear_walk(w->codec);
+       out = is_connected_output_ep(w);
+       dapm_clear_walk(w->codec);
+       power = (out != 0 && in != 0) ? 1 : 0;
+       power_change = (w->power == power) ? 0 : 1;
+       w->power = power;
+
+       if (!power_change)
+               return 0;
+
+       /* call any power change event handlers */
+       if (w->event)
+               pr_debug("power %s event for %s flags %x\n",
+                        w->power ? "on" : "off",
+                        w->name, w->event_flags);
+
+       /* power up pre event */
+       if (power && w->event &&
+           (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
+               ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* power down pre event */
+       if (!power && w->event &&
+           (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
+               ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Lower PGA volume to reduce pops */
+       if (w->id == snd_soc_dapm_pga && !power)
+               dapm_set_pga(w, power);
+
+       dapm_update_bits(w);
+
+       /* Raise PGA volume to reduce pops */
+       if (w->id == snd_soc_dapm_pga && power)
+               dapm_set_pga(w, power);
+
+       /* power up post event */
+       if (power && w->event &&
+           (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
+               ret = w->event(w,
+                              NULL, SND_SOC_DAPM_POST_PMU);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* power down post event */
+       if (!power && w->event &&
+           (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
+               ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -514,7 +664,7 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 {
        struct snd_soc_dapm_widget *w;
-       int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
+       int i, c = 1, *seq = NULL, ret = 0;
 
        /* do we have a sequenced stream event */
        if (event == SND_SOC_DAPM_STREAM_START) {
@@ -525,135 +675,20 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                seq = dapm_down_seq;
        }
 
-       for(i = 0; i < c; i++) {
+       for (i = 0; i < c; i++) {
                list_for_each_entry(w, &codec->dapm_widgets, list) {
 
                        /* is widget in stream order */
                        if (seq && seq[i] && w->id != seq[i])
                                continue;
 
-                       /* vmid - no action */
-                       if (w->id == snd_soc_dapm_vmid)
-                               continue;
-
-                       /* active ADC */
-                       if (w->id == snd_soc_dapm_adc && w->active) {
-                               in = is_connected_input_ep(w);
-                               dapm_clear_walk(w->codec);
-                               w->power = (in != 0) ? 1 : 0;
-                               dapm_update_bits(w);
-                               continue;
-                       }
-
-                       /* active DAC */
-                       if (w->id == snd_soc_dapm_dac && w->active) {
-                               out = is_connected_output_ep(w);
-                               dapm_clear_walk(w->codec);
-                               w->power = (out != 0) ? 1 : 0;
-                               dapm_update_bits(w);
-                               continue;
-                       }
-
-                       /* pre and post event widgets */
-                       if (w->id == snd_soc_dapm_pre) {
-                               if (!w->event)
-                                       continue;
-
-                               if (event == SND_SOC_DAPM_STREAM_START) {
-                                       ret = w->event(w,
-                                               NULL, SND_SOC_DAPM_PRE_PMU);
-                                       if (ret < 0)
-                                               return ret;
-                               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                                       ret = w->event(w,
-                                               NULL, SND_SOC_DAPM_PRE_PMD);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-                               continue;
-                       }
-                       if (w->id == snd_soc_dapm_post) {
-                               if (!w->event)
-                                       continue;
-
-                               if (event == SND_SOC_DAPM_STREAM_START) {
-                                       ret = w->event(w,
-                                               NULL, SND_SOC_DAPM_POST_PMU);
-                                       if (ret < 0)
-                                               return ret;
-                               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                                       ret = w->event(w,
-                                               NULL, SND_SOC_DAPM_POST_PMD);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-                               continue;
-                       }
-
-                       /* all other widgets */
-                       in = is_connected_input_ep(w);
-                       dapm_clear_walk(w->codec);
-                       out = is_connected_output_ep(w);
-                       dapm_clear_walk(w->codec);
-                       power = (out != 0 && in != 0) ? 1 : 0;
-                       power_change = (w->power == power) ? 0: 1;
-                       w->power = power;
-
-                       if (!power_change)
-                               continue;
-
-                       /* call any power change event handlers */
-                       if (w->event)
-                               pr_debug("power %s event for %s flags %x\n",
-                                        w->power ? "on" : "off",
-                                        w->name, w->event_flags);
-
-                       /* power up pre event */
-                       if (power && w->event &&
-                           (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
-                               ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
-                               if (ret < 0)
-                                       return ret;
-                       }
-
-                       /* power down pre event */
-                       if (!power && w->event &&
-                           (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
-                               ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
-                               if (ret < 0)
-                                       return ret;
-                       }
-
-                       /* Lower PGA volume to reduce pops */
-                       if (w->id == snd_soc_dapm_pga && !power)
-                               dapm_set_pga(w, power);
-
-                       dapm_update_bits(w);
-
-                       /* Raise PGA volume to reduce pops */
-                       if (w->id == snd_soc_dapm_pga && power)
-                               dapm_set_pga(w, power);
-
-                       /* power up post event */
-                       if (power && w->event &&
-                           (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
-                               ret = w->event(w,
-                                              NULL, SND_SOC_DAPM_POST_PMU);
-                               if (ret < 0)
-                                       return ret;
-                       }
-
-                       /* power down post event */
-                       if (!power && w->event &&
-                           (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
-                               ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
-                               if (ret < 0)
-                                       return ret;
-                       }
+                       ret = dapm_power_widget(codec, event, w);
+                       if (ret != 0)
+                               return ret;
                }
        }
 
-       return ret;
+       return 0;
 }
 
 #ifdef DEBUG
@@ -687,6 +722,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
                case snd_soc_dapm_adc:
                case snd_soc_dapm_pga:
                case snd_soc_dapm_mixer:
+               case snd_soc_dapm_mixer_named_ctl:
                        if (w->name) {
                                in = is_connected_input_ep(w);
                                dapm_clear_walk(w->codec);
@@ -760,6 +796,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
        int found = 0;
 
        if (widget->id != snd_soc_dapm_mixer &&
+           widget->id != snd_soc_dapm_mixer_named_ctl &&
            widget->id != snd_soc_dapm_switch)
                return -ENODEV;
 
@@ -795,7 +832,7 @@ static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
        struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       struct snd_soc_codec *codec = devdata->codec;
+       struct snd_soc_codec *codec = devdata->card->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
        char *state = "not set";
@@ -813,6 +850,7 @@ static ssize_t dapm_widget_show(struct device *dev,
                case snd_soc_dapm_adc:
                case snd_soc_dapm_pga:
                case snd_soc_dapm_mixer:
+               case snd_soc_dapm_mixer_named_ctl:
                        if (w->name)
                                count += sprintf(buf + count, "%s: %s\n",
                                        w->name, w->power ? "On":"Off");
@@ -876,7 +914,7 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
 }
 
 static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
-       char *pin, int status)
+                               const char *pin, int status)
 {
        struct snd_soc_dapm_widget *w;
 
@@ -991,6 +1029,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
                break;
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
                ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
                if (ret != 0)
                        goto err;
@@ -1068,6 +1107,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                switch(w->id) {
                case snd_soc_dapm_switch:
                case snd_soc_dapm_mixer:
+               case snd_soc_dapm_mixer_named_ctl:
                        dapm_new_mixer(codec, w);
                        break;
                case snd_soc_dapm_mux:
@@ -1395,6 +1435,76 @@ out:
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
 
+/**
+ * snd_soc_dapm_info_pin_switch - Info for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a pin switch control.
+ */
+int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
+
+/**
+ * snd_soc_dapm_get_pin_switch - Get information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ */
+int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       const char *pin = (const char *)kcontrol->private_value;
+
+       mutex_lock(&codec->mutex);
+
+       ucontrol->value.integer.value[0] =
+               snd_soc_dapm_get_pin_status(codec, pin);
+
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
+
+/**
+ * snd_soc_dapm_put_pin_switch - Set information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ */
+int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       const char *pin = (const char *)kcontrol->private_value;
+
+       mutex_lock(&codec->mutex);
+
+       if (ucontrol->value.integer.value[0])
+               snd_soc_dapm_enable_pin(codec, pin);
+       else
+               snd_soc_dapm_disable_pin(codec, pin);
+
+       snd_soc_dapm_sync(codec);
+
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
+
 /**
  * snd_soc_dapm_new_control - create new dapm control
  * @codec: audio codec
@@ -1527,8 +1637,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
                                enum snd_soc_bias_level level)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        if (card->set_bias_level)
@@ -1549,7 +1659,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin)
 {
        return snd_soc_dapm_set_pin(codec, pin, 1);
 }
@@ -1564,7 +1674,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin)
 {
        return snd_soc_dapm_set_pin(codec, pin, 0);
 }
@@ -1584,7 +1694,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin)
 {
        return snd_soc_dapm_set_pin(codec, pin, 0);
 }
@@ -1599,7 +1709,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
  *
  * Returns 1 for connected otherwise 0.
  */
-int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
 {
        struct snd_soc_dapm_widget *w;
 
@@ -1620,7 +1730,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
  */
 void snd_soc_dapm_free(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 
        snd_soc_dapm_sys_remove(socdev->dev);
        dapm_free_widgets(codec);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
new file mode 100644 (file)
index 0000000..28346fb
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * soc-jack.c  --  ALSA SoC jack handling
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+/**
+ * snd_soc_jack_new - Create a new jack
+ * @card:  ASoC card
+ * @id:    an identifying string for this jack
+ * @type:  a bitmask of enum snd_jack_type values that can be detected by
+ *         this jack
+ * @jack:  structure to use for the jack
+ *
+ * Creates a new jack object.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ * On success jack will be initialised.
+ */
+int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+                    struct snd_soc_jack *jack)
+{
+       jack->card = card;
+       INIT_LIST_HEAD(&jack->pins);
+
+       return snd_jack_new(card->codec->card, id, type, &jack->jack);
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_new);
+
+/**
+ * snd_soc_jack_report - Report the current status for a jack
+ *
+ * @jack:   the jack
+ * @status: a bitmask of enum snd_jack_type values that are currently detected.
+ * @mask:   a bitmask of enum snd_jack_type values that being reported.
+ *
+ * If configured using snd_soc_jack_add_pins() then the associated
+ * DAPM pins will be enabled or disabled as appropriate and DAPM
+ * synchronised.
+ *
+ * Note: This function uses mutexes and should be called from a
+ * context which can sleep (such as a workqueue).
+ */
+void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
+{
+       struct snd_soc_codec *codec = jack->card->codec;
+       struct snd_soc_jack_pin *pin;
+       int enable;
+       int oldstatus;
+
+       if (!jack) {
+               WARN_ON_ONCE(!jack);
+               return;
+       }
+
+       mutex_lock(&codec->mutex);
+
+       oldstatus = jack->status;
+
+       jack->status &= ~mask;
+       jack->status |= status;
+
+       /* The DAPM sync is expensive enough to be worth skipping */
+       if (jack->status == oldstatus)
+               goto out;
+
+       list_for_each_entry(pin, &jack->pins, list) {
+               enable = pin->mask & status;
+
+               if (pin->invert)
+                       enable = !enable;
+
+               if (enable)
+                       snd_soc_dapm_enable_pin(codec, pin->pin);
+               else
+                       snd_soc_dapm_disable_pin(codec, pin->pin);
+       }
+
+       snd_soc_dapm_sync(codec);
+
+       snd_jack_report(jack->jack, status);
+
+out:
+       mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_report);
+
+/**
+ * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack
+ *
+ * @jack:  ASoC jack
+ * @count: Number of pins
+ * @pins:  Array of pins
+ *
+ * After this function has been called the DAPM pins specified in the
+ * pins array will have their status updated to reflect the current
+ * state of the jack whenever the jack status is updated.
+ */
+int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
+                         struct snd_soc_jack_pin *pins)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (!pins[i].pin) {
+                       printk(KERN_ERR "No name for pin %d\n", i);
+                       return -EINVAL;
+               }
+               if (!pins[i].mask) {
+                       printk(KERN_ERR "No mask for pin %d (%s)\n", i,
+                              pins[i].pin);
+                       return -EINVAL;
+               }
+
+               INIT_LIST_HEAD(&pins[i].list);
+               list_add(&(pins[i].list), &jack->pins);
+       }
+
+       /* Update to reflect the last reported status; canned jack
+        * implementations are likely to set their state before the
+        * card has an opportunity to associate pins.
+        */
+       snd_soc_jack_report(jack, 0, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
+
+#ifdef CONFIG_GPIOLIB
+/* gpio detect */
+static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
+{
+       struct snd_soc_jack *jack = gpio->jack;
+       int enable;
+       int report;
+
+       if (gpio->debounce_time > 0)
+               mdelay(gpio->debounce_time);
+
+       enable = gpio_get_value(gpio->gpio);
+       if (gpio->invert)
+               enable = !enable;
+
+       if (enable)
+               report = gpio->report;
+       else
+               report = 0;
+
+       snd_soc_jack_report(jack, report, gpio->report);
+}
+
+/* irq handler for gpio pin */
+static irqreturn_t gpio_handler(int irq, void *data)
+{
+       struct snd_soc_jack_gpio *gpio = data;
+
+       schedule_work(&gpio->work);
+
+       return IRQ_HANDLED;
+}
+
+/* gpio work */
+static void gpio_work(struct work_struct *work)
+{
+       struct snd_soc_jack_gpio *gpio;
+
+       gpio = container_of(work, struct snd_soc_jack_gpio, work);
+       snd_soc_jack_gpio_detect(gpio);
+}
+
+/**
+ * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
+ *
+ * @jack:  ASoC jack
+ * @count: number of pins
+ * @gpios: array of gpio pins
+ *
+ * This function will request gpio, set data direction and request irq
+ * for each gpio in the array.
+ */
+int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+                       struct snd_soc_jack_gpio *gpios)
+{
+       int i, ret;
+
+       for (i = 0; i < count; i++) {
+               if (!gpio_is_valid(gpios[i].gpio)) {
+                       printk(KERN_ERR "Invalid gpio %d\n",
+                               gpios[i].gpio);
+                       ret = -EINVAL;
+                       goto undo;
+               }
+               if (!gpios[i].name) {
+                       printk(KERN_ERR "No name for gpio %d\n",
+                               gpios[i].gpio);
+                       ret = -EINVAL;
+                       goto undo;
+               }
+
+               ret = gpio_request(gpios[i].gpio, gpios[i].name);
+               if (ret)
+                       goto undo;
+
+               ret = gpio_direction_input(gpios[i].gpio);
+               if (ret)
+                       goto err;
+
+               ret = request_irq(gpio_to_irq(gpios[i].gpio),
+                               gpio_handler,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               jack->card->dev->driver->name,
+                               &gpios[i]);
+               if (ret)
+                       goto err;
+
+               INIT_WORK(&gpios[i].work, gpio_work);
+               gpios[i].jack = jack;
+       }
+
+       return 0;
+
+err:
+       gpio_free(gpios[i].gpio);
+undo:
+       snd_soc_jack_free_gpios(jack, i, gpios);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios);
+
+/**
+ * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
+ *
+ * @jack:  ASoC jack
+ * @count: number of pins
+ * @gpios: array of gpio pins
+ *
+ * Release gpio and irq resources for gpio pins associated with an ASoC jack.
+ */
+void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+                       struct snd_soc_jack_gpio *gpios)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+               gpio_free(gpios[i].gpio);
+               gpios[i].jack = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
+#endif /* CONFIG_GPIOLIB */
index f87933e48812d8c7aba976d64fd9477912c85e41..574af56ba8a6fa6d4b690f4b2079ea459281712c 100644 (file)
@@ -954,7 +954,8 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
        amd->regs = of_ioremap(&op->resource[0], 0,
                               resource_size(&op->resource[0]), "amd7930");
        if (!amd->regs) {
-               snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
+               snd_printk(KERN_ERR
+                          "amd7930-%d: Unable to map chip registers.\n", dev);
                return -EIO;
        }
 
@@ -962,7 +963,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
 
        if (request_irq(irq, snd_amd7930_interrupt,
                        IRQF_DISABLED | IRQF_SHARED, "amd7930", amd)) {
-               snd_printk("amd7930-%d: Unable to grab IRQ %d\n",
+               snd_printk(KERN_ERR "amd7930-%d: Unable to grab IRQ %d\n",
                           dev, irq);
                snd_amd7930_free(amd);
                return -EBUSY;
@@ -1018,9 +1019,10 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev_num], id[dev_num], THIS_MODULE, 0,
+                             &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "AMD7930");
        strcpy(card->shortname, "Sun AMD7930");
index 41c387587474c9ccaef6ae1c228ad1dffde14977..7d93fa705ccf493135b36cefff7ea242812ca11b 100644 (file)
@@ -1563,6 +1563,7 @@ static int __init cs4231_attach_begin(struct snd_card **rcard)
 {
        struct snd_card *card;
        struct snd_cs4231 *chip;
+       int err;
 
        *rcard = NULL;
 
@@ -1574,10 +1575,10 @@ static int __init cs4231_attach_begin(struct snd_card **rcard)
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_cs4231));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_cs4231), &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "CS4231");
        strcpy(card->shortname, "Sun CS4231");
index 23ed6f04a718c30d30db22e577974c4ee54f8190..af95ff1e126cc39a83d0e833fb0d126c334e6278 100644 (file)
@@ -2612,10 +2612,10 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id
                return -ENODEV;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct snd_dbri));
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct snd_dbri), &card);
+       if (err < 0)
+               return err;
 
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
index 09802e8a6fb834419f8c752ac8edb7c68405de88..4c7b051f9d17705bfc9827113e4fc8f74792e7c7 100644 (file)
@@ -965,12 +965,11 @@ static int __devinit snd_at73c213_probe(struct spi_device *spi)
                return PTR_ERR(board->dac_clk);
        }
 
-       retval = -ENOMEM;
-
        /* Allocate "card" using some unused identifiers. */
        snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
-       card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));
-       if (!card)
+       retval = snd_card_create(-1, id, THIS_MODULE,
+                                sizeof(struct snd_at73c213), &card);
+       if (retval < 0)
                goto out;
 
        chip = card->private_data;
index 0a5391436addfd3f0b67c5f91aa487f1af349bd7..ff0b2a8fd25bbe20dd51191935582746f8ba6edf 100644 (file)
 #include <asm/uaccess.h>
 #include "emux_voice.h"
 
-/*
- * open the hwdep device
- */
-static int
-snd_emux_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
-
-/*
- * close the device
- */
-static int
-snd_emux_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
 
 #define TMP_CLIENT_ID  0x1001
 
@@ -146,8 +127,6 @@ snd_emux_init_hwdep(struct snd_emux *emu)
        emu->hwdep = hw;
        strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
        hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
-       hw->ops.open = snd_emux_hwdep_open;
-       hw->ops.release = snd_emux_hwdep_release;
        hw->ops.ioctl = snd_emux_hwdep_ioctl;
        hw->exclusive = 1;
        hw->private_data = emu;
index 5c47b6c09264e26414276e1663a4723cff005650..87e42206c4ef02aabc071d56ba9c6ceedc47f453 100644 (file)
@@ -132,7 +132,7 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
        p = snd_emux_create_port(emu, tmpname, 32,
                                 1, &callback);
        if (p == NULL) {
-               snd_printk("can't create port\n");
+               snd_printk(KERN_ERR "can't create port\n");
                snd_emux_dec_count(emu);
                mutex_unlock(&emu->register_mutex);
                return -ENOMEM;
index 335aa2ce257427dc44a8af0f33021a1c9064b9c0..ca5f7effb4df48815c2367bd8473f1e1024fefdc 100644 (file)
@@ -74,15 +74,15 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
        emu->client = snd_seq_create_kernel_client(card, index,
                                                   "%s WaveTable", emu->name);
        if (emu->client < 0) {
-               snd_printk("can't create client\n");
+               snd_printk(KERN_ERR "can't create client\n");
                return -ENODEV;
        }
 
        if (emu->num_ports < 0) {
-               snd_printk("seqports must be greater than zero\n");
+               snd_printk(KERN_WARNING "seqports must be greater than zero\n");
                emu->num_ports = 1;
        } else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) {
-               snd_printk("too many ports."
+               snd_printk(KERN_WARNING "too many ports."
                           "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS);
                emu->num_ports = SNDRV_EMUX_MAX_PORTS;
        }
@@ -100,7 +100,7 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
                p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS,
                                         0, &pinfo);
                if (p == NULL) {
-                       snd_printk("can't create port\n");
+                       snd_printk(KERN_ERR "can't create port\n");
                        return -ENOMEM;
                }
 
@@ -147,12 +147,12 @@ snd_emux_create_port(struct snd_emux *emu, char *name,
 
        /* Allocate structures for this channel */
        if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) {
-               snd_printk("no memory\n");
+               snd_printk(KERN_ERR "no memory\n");
                return NULL;
        }
        p->chset.channels = kcalloc(max_channels, sizeof(struct snd_midi_channel), GFP_KERNEL);
        if (p->chset.channels == NULL) {
-               snd_printk("no memory\n");
+               snd_printk(KERN_ERR "no memory\n");
                kfree(p);
                return NULL;
        }
@@ -376,12 +376,12 @@ int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card)
                        goto __error;
                }
                emu->vmidi[i] = rmidi;
-               //snd_printk("virmidi %d ok\n", i);
+               /* snd_printk(KERN_DEBUG "virmidi %d ok\n", i); */
        }
        return 0;
 
 __error:
-       //snd_printk("error init..\n");
+       /* snd_printk(KERN_DEBUG "error init..\n"); */
        snd_emux_delete_virmidi(emu);
        return -ENOMEM;
 }
index 2cc6f6f7906574f77bc471cfc7405085c98434e1..3e921b386fd5a6c81c70cf73611831fb83634bbf 100644 (file)
@@ -956,7 +956,8 @@ void snd_emux_lock_voice(struct snd_emux *emu, int voice)
        if (emu->voices[voice].state == SNDRV_EMUX_ST_OFF)
                emu->voices[voice].state = SNDRV_EMUX_ST_LOCKED;
        else
-               snd_printk("invalid voice for lock %d (state = %x)\n",
+               snd_printk(KERN_WARNING
+                          "invalid voice for lock %d (state = %x)\n",
                           voice, emu->voices[voice].state);
        spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
@@ -973,7 +974,8 @@ void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
        if (emu->voices[voice].state == SNDRV_EMUX_ST_LOCKED)
                emu->voices[voice].state = SNDRV_EMUX_ST_OFF;
        else
-               snd_printk("invalid voice for unlock %d (state = %x)\n",
+               snd_printk(KERN_WARNING
+                          "invalid voice for unlock %d (state = %x)\n",
                           voice, emu->voices[voice].state);
        spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
index 36d53bd317ede3f2d3cc1974c7003a7746789d14..63c8f45c0c225ecbf35f1c2695e10c418fb509f9 100644 (file)
@@ -133,7 +133,7 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
        int  rc;
 
        if (count < (long)sizeof(patch)) {
-               snd_printk("patch record too small %ld\n", count);
+               snd_printk(KERN_ERR "patch record too small %ld\n", count);
                return -EINVAL;
        }
        if (copy_from_user(&patch, data, sizeof(patch)))
@@ -143,15 +143,16 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
        data += sizeof(patch);
 
        if (patch.key != SNDRV_OSS_SOUNDFONT_PATCH) {
-               snd_printk("'The wrong kind of patch' %x\n", patch.key);
+               snd_printk(KERN_ERR "The wrong kind of patch %x\n", patch.key);
                return -EINVAL;
        }
        if (count < patch.len) {
-               snd_printk("Patch too short %ld, need %d\n", count, patch.len);
+               snd_printk(KERN_ERR "Patch too short %ld, need %d\n",
+                          count, patch.len);
                return -EINVAL;
        }
        if (patch.len < 0) {
-               snd_printk("poor length %d\n", patch.len);
+               snd_printk(KERN_ERR "poor length %d\n", patch.len);
                return -EINVAL;
        }
 
@@ -195,7 +196,8 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
        case SNDRV_SFNT_REMOVE_INFO:
                /* patch must be opened */
                if (!sflist->currsf) {
-                       snd_printk("soundfont: remove_info: patch not opened\n");
+                       snd_printk(KERN_ERR "soundfont: remove_info: "
+                                  "patch not opened\n");
                        rc = -EINVAL;
                } else {
                        int bank, instr;
@@ -531,7 +533,7 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count)
                return -EINVAL;
 
        if (count < (long)sizeof(hdr)) {
-               printk("Soundfont error: invalid patch zone length\n");
+               printk(KERN_ERR "Soundfont error: invalid patch zone length\n");
                return -EINVAL;
        }
        if (copy_from_user((char*)&hdr, data, sizeof(hdr)))
@@ -541,12 +543,14 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count)
        count -= sizeof(hdr);
 
        if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
-               printk("Soundfont error: Illegal voice number %d\n", hdr.nvoices);
+               printk(KERN_ERR "Soundfont error: Illegal voice number %d\n",
+                      hdr.nvoices);
                return -EINVAL;
        }
 
        if (count < (long)sizeof(struct soundfont_voice_info) * hdr.nvoices) {
-               printk("Soundfont Error: patch length(%ld) is smaller than nvoices(%d)\n",
+               printk(KERN_ERR "Soundfont Error: "
+                      "patch length(%ld) is smaller than nvoices(%d)\n",
                       count, hdr.nvoices);
                return -EINVAL;
        }
@@ -952,7 +956,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
        int rc;
 
        if (count < (long)sizeof(patch)) {
-               snd_printk("patch record too small %ld\n", count);
+               snd_printk(KERN_ERR "patch record too small %ld\n", count);
                return -EINVAL;
        }
        if (copy_from_user(&patch, data, sizeof(patch)))
@@ -1034,7 +1038,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
        /* panning position; -128 - 127 => 0-127 */
        zone->v.pan = (patch.panning + 128) / 2;
 #if 0
-       snd_printk("gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",
+       snd_printk(KERN_DEBUG
+                  "gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",
                   (int)patch.base_freq, zone->v.rate_offset,
                   zone->v.root, zone->v.tune, zone->v.low, zone->v.high);
 #endif
@@ -1068,7 +1073,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
                zone->v.parm.volrelease = 0x8000 | snd_sf_calc_parm_decay(release);
                zone->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);
 #if 0
-               snd_printk("gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",
+               snd_printk(KERN_DEBUG
+                          "gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",
                           zone->v.parm.volatkhld,
                           zone->v.parm.voldcysus,
                           zone->v.parm.volrelease,
index 4f0eac9bff1e1afb10e3540e3871c9b6be2fff66..523aec188ccf64efa2de3aae90f8550eee77e3aa 100644 (file)
@@ -48,7 +48,10 @@ config SND_USB_CAIAQ
            * Native Instruments Kore Controller
            * Native Instruments Kore Controller 2
            * Native Instruments Audio Kontrol 1
+           * Native Instruments Audio 4 DJ
            * Native Instruments Audio 8 DJ
+           * Native Instruments Guitar Rig Session I/O
+           * Native Instruments Guitar Rig mobile
 
           To compile this driver as a module, choose M here: the module
           will be called snd-usb-caiaq.
index b3a60332583534735cfd54504cc8141cdb4587cd..08d51e0c9feae466175f87cb45fe87cebbcd13ec 100644 (file)
@@ -114,6 +114,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
        dev->output_panic = 0;
        dev->first_packet = 1;
        dev->streaming = 1;
+       dev->warned = 0;
 
        for (i = 0; i < N_URBS; i++) {
                ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC);
@@ -376,6 +377,9 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
 
                for (stream = 0; stream < dev->n_streams; stream++, i++) {
                        sub = dev->sub_capture[stream];
+                       if (dev->input_panic)
+                               usb_buf[i] = 0;
+
                        if (sub) {
                                struct snd_pcm_runtime *rt = sub->runtime;
                                char *audio_buf = rt->dma_area;
@@ -397,6 +401,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        if (!dev->streaming)
                return;
 
+       if (iso->actual_length < dev->bpp)
+               return;
+
        switch (dev->spec.data_alignment) {
        case 0:
                read_in_urb_mode0(dev, urb, iso);
@@ -406,10 +413,11 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
                break;
        }
 
-       if (dev->input_panic || dev->output_panic) {
+       if ((dev->input_panic || dev->output_panic) && !dev->warned) {
                debug("streaming error detected %s %s\n", 
                                dev->input_panic ? "(input)" : "",
                                dev->output_panic ? "(output)" : "");
+               dev->warned = 1;
        }
 }
 
@@ -638,9 +646,10 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):
-               dev->samplerates |= SNDRV_PCM_RATE_88200;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
                dev->samplerates |= SNDRV_PCM_RATE_192000;
-               break;
+               /* fall thru */
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
                dev->samplerates |= SNDRV_PCM_RATE_88200;
                break;
index ccd763dd7167e2ce37b469098807634a1500aab9..e92c2bbf4fe92742aa4f99a16d735d0996f7f8c9 100644 (file)
@@ -39,12 +39,12 @@ static int control_info(struct snd_kcontrol *kcontrol,
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
        int is_intval = pos & CNT_INTVAL;
+       unsigned int id = dev->chip.usb_id;
 
        uinfo->count = 1;
        pos &= ~CNT_INTVAL;
 
-       if (dev->chip.usb_id ==
-               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)
+       if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)
                && (pos == 0)) {
                /* current input mode of A8DJ */
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -53,6 +53,15 @@ static int control_info(struct snd_kcontrol *kcontrol,
                return 0;
        }
 
+       if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)
+               && (pos == 0)) {
+               /* current input mode of A4DJ */
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 1;
+               return 0;
+       }
+
        if (is_intval) {
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
                uinfo->value.integer.min = 0;
@@ -73,6 +82,14 @@ static int control_get(struct snd_kcontrol *kcontrol,
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
 
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
+               /* A4DJ has only one control */
+               /* do not expose hardware input mode 0 */
+               ucontrol->value.integer.value[0] = dev->control_state[0] - 1;
+               return 0;
+       }
+
        if (pos & CNT_INTVAL)
                ucontrol->value.integer.value[0]
                        = dev->control_state[pos & ~CNT_INTVAL];
@@ -90,10 +107,20 @@ static int control_put(struct snd_kcontrol *kcontrol,
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
 
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
+               /* A4DJ has only one control */
+               /* do not expose hardware input mode 0 */
+               dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+                               dev->control_state, sizeof(dev->control_state));
+               return 1;
+       }
+
        if (pos & CNT_INTVAL) {
                dev->control_state[pos & ~CNT_INTVAL]
                        = ucontrol->value.integer.value[0];
-               snd_usb_caiaq_send_command(dev, EP1_CMD_DIMM_LEDS,
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
                                dev->control_state, sizeof(dev->control_state));
        } else {
                if (ucontrol->value.integer.value[0])
@@ -243,10 +270,13 @@ static struct caiaq_controller a8dj_controller[] = {
        { "GND lift for TC Vinyl mode",         24 + 0          },
        { "GND lift for TC CD/Line mode",       24 + 1          },
        { "GND lift for phono mode",            24 + 2          },
-       { "GND lift for TC Vinyl mode",         24 + 3          },
        { "Software lock",                      40              }
 };
 
+static struct caiaq_controller a4dj_controller[] = {
+       { "Current input mode", 0 | CNT_INTVAL  }
+};
+
 static int __devinit add_controls(struct caiaq_controller *c, int num,
                                  struct snd_usb_caiaqdev *dev)
 {
@@ -295,6 +325,10 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
                ret = add_controls(a8dj_controller,
                        ARRAY_SIZE(a8dj_controller), dev);
                break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
+               ret = add_controls(a4dj_controller,
+                       ARRAY_SIZE(a4dj_controller), dev);
+               break;
        }
 
        return ret;
index 41c36b055f6b3f980b7c8217ce6b1496efe6bc43..cf573a982fdc542b71e4fe6f3cd891f44f018ba2 100644 (file)
 #endif
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.10");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.13");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
                         "{Native Instruments, Kore Controller},"
                         "{Native Instruments, Kore Controller 2},"
                         "{Native Instruments, Audio Kontrol 1},"
+                        "{Native Instruments, Audio 4 DJ},"
                         "{Native Instruments, Audio 8 DJ},"
-                        "{Native Instruments, Session I/O}}");
+                        "{Native Instruments, Session I/O},"
+                        "{Native Instruments, GuitarRig mobile}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -116,6 +118,16 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_SESSIONIO
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_GUITARRIGMOBILE
+       },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_AUDIO4DJ
+       },
        { /* terminator */ }
 };
 
@@ -239,6 +251,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
                
        if (dev->audio_parm_answer != 1) 
                debug("unable to set the device's audio params\n");
+       else
+               dev->bpp = bpp;
 
        return dev->audio_parm_answer == 1 ? 0 : -EINVAL;
 }
@@ -300,6 +314,12 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                }
 
                break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
+               /* Audio 4 DJ - default input mode to phono */
+               dev->control_state[0] = 2;
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+                       dev->control_state, 1);
+               break;
        }
        
        if (dev->spec.num_analog_audio_out +
@@ -336,9 +356,10 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                log("Unable to set up control system (ret=%d)\n", ret);
 }
 
-static struct snd_card* create_card(struct usb_device* usb_dev)
+static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
 {
        int devnum;
+       int err;
        struct snd_card *card;
        struct snd_usb_caiaqdev *dev;
 
@@ -347,12 +368,12 @@ static struct snd_card* create_card(struct usb_device* usb_dev)
                        break;
 
        if (devnum >= SNDRV_CARDS)
-               return NULL;
+               return -ENODEV;
 
-       card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, 
-                                       sizeof(struct snd_usb_caiaqdev));
-       if (!card)
-               return NULL;
+       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, 
+                             sizeof(struct snd_usb_caiaqdev), &card);
+       if (err < 0)
+               return err;
 
        dev = caiaqdev(card);
        dev->chip.dev = usb_dev;
@@ -362,7 +383,8 @@ static struct snd_card* create_card(struct usb_device* usb_dev)
        spin_lock_init(&dev->spinlock);
        snd_card_set_dev(card, &usb_dev->dev);
 
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int __devinit init_card(struct snd_usb_caiaqdev *dev)
@@ -441,10 +463,10 @@ static int __devinit snd_probe(struct usb_interface *intf,
        struct snd_card *card;
        struct usb_device *device = interface_to_usbdev(intf);
        
-       card = create_card(device);
+       ret = create_card(device, &card);
        
-       if (!card)
-               return -ENOMEM;
+       if (ret < 0)
+               return ret;
                        
        usb_set_intfdata(intf, card);
        ret = init_card(caiaqdev(card));
index ab56e738c5fc021f71af01365c5f164f64779cb2..4cce1ad7493db4ec138216bb3a56b6ae20fcc90f 100644 (file)
 #define USB_PID_KORECONTROLLER 0x4711
 #define USB_PID_KORECONTROLLER2        0x4712
 #define USB_PID_AK1            0x0815
+#define USB_PID_AUDIO4DJ       0x0839
 #define USB_PID_AUDIO8DJ       0x1978
 #define USB_PID_SESSIONIO      0x1915
+#define USB_PID_GUITARRIGMOBILE        0x0d8d
 
 #define EP1_BUFSIZE 64
 #define CAIAQ_USB_STR_LEN 0xff
@@ -87,9 +89,9 @@ struct snd_usb_caiaqdev {
        int audio_out_buf_pos[MAX_STREAMS];
        int period_in_count[MAX_STREAMS];
        int period_out_count[MAX_STREAMS];
-       int input_panic, output_panic;
+       int input_panic, output_panic, warned;
        char *audio_in_buf, *audio_out_buf;
-       unsigned int samplerates;
+       unsigned int samplerates, bpp;
 
        struct snd_pcm_substream *sub_playback[MAX_STREAMS];
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
index 19e37451c216182ebdc9d800f304a66f5e6bc9e7..c2db0f959681da6608e0906a580db3240000d45f 100644 (file)
@@ -107,7 +107,7 @@ MODULE_PARM_DESC(ignore_ctl_error,
 #define MAX_PACKS_HS   (MAX_PACKS * 8) /* in high speed mode */
 #define MAX_URBS       8
 #define SYNC_URBS      4       /* always four urbs for sync */
-#define MIN_PACKS_URB  1       /* minimum 1 packet per urb */
+#define MAX_QUEUE      24      /* try not to exceed this queue length, in ms */
 
 struct audioformat {
        struct list_head list;
@@ -525,7 +525,7 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
 /*
  * Prepare urb for streaming before playback starts or when paused.
  *
- * We don't have any data, so we send a frame of silence.
+ * We don't have any data, so we send silence.
  */
 static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
                                       struct snd_pcm_runtime *runtime,
@@ -537,13 +537,13 @@ static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
 
        offs = 0;
        urb->dev = ctx->subs->dev;
-       urb->number_of_packets = subs->packs_per_ms;
-       for (i = 0; i < subs->packs_per_ms; ++i) {
+       for (i = 0; i < ctx->packets; ++i) {
                counts = snd_usb_audio_next_packet_size(subs);
                urb->iso_frame_desc[i].offset = offs * stride;
                urb->iso_frame_desc[i].length = counts * stride;
                offs += counts;
        }
+       urb->number_of_packets = ctx->packets;
        urb->transfer_buffer_length = offs * stride;
        memset(urb->transfer_buffer,
               subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
@@ -1034,9 +1034,9 @@ static void release_substream_urbs(struct snd_usb_substream *subs, int force)
 static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes,
                               unsigned int rate, unsigned int frame_bits)
 {
-       unsigned int maxsize, n, i;
+       unsigned int maxsize, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
+       unsigned int urb_packs, total_packs, packs_per_ms;
 
        /* calculate the frequency in 16.16 format */
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -1070,8 +1070,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
        subs->packs_per_ms = packs_per_ms;
 
        if (is_playback) {
-               urb_packs = nrpacks;
-               urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+               urb_packs = max(nrpacks, 1);
                urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
        } else
                urb_packs = 1;
@@ -1079,7 +1078,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
 
        /* decide how many packets to be used */
        if (is_playback) {
-               unsigned int minsize;
+               unsigned int minsize, maxpacks;
                /* determine how small a packet can be */
                minsize = (subs->freqn >> (16 - subs->datainterval))
                          * (frame_bits >> 3);
@@ -1092,8 +1091,13 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                total_packs = (total_packs + packs_per_ms - 1)
                                & ~(packs_per_ms - 1);
                /* we need at least two URBs for queueing */
-               if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
-                       total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+               if (total_packs < 2 * packs_per_ms) {
+                       total_packs = 2 * packs_per_ms;
+               } else {
+                       /* and we don't want too long a queue either */
+                       maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
+                       total_packs = min(total_packs, maxpacks);
+               }
        } else {
                total_packs = MAX_URBS * urb_packs;
        }
@@ -1102,31 +1106,11 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                /* too much... */
                subs->nurbs = MAX_URBS;
                total_packs = MAX_URBS * urb_packs;
-       }
-       n = total_packs;
-       for (i = 0; i < subs->nurbs; i++) {
-               npacks[i] = n > urb_packs ? urb_packs : n;
-               n -= urb_packs;
-       }
-       if (subs->nurbs <= 1) {
+       } else if (subs->nurbs < 2) {
                /* too little - we need at least two packets
                 * to ensure contiguous playback/capture
                 */
                subs->nurbs = 2;
-               npacks[0] = (total_packs + 1) / 2;
-               npacks[1] = total_packs - npacks[0];
-       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
-               /* the last packet is too small.. */
-               if (subs->nurbs > 2) {
-                       /* merge to the first one */
-                       npacks[0] += npacks[subs->nurbs - 1];
-                       subs->nurbs--;
-               } else {
-                       /* divide to two */
-                       subs->nurbs = 2;
-                       npacks[0] = (total_packs + 1) / 2;
-                       npacks[1] = total_packs - npacks[0];
-               }
        }
 
        /* allocate and initialize data urbs */
@@ -1134,7 +1118,8 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                struct snd_urb_ctx *u = &subs->dataurb[i];
                u->index = i;
                u->subs = subs;
-               u->packets = npacks[i];
+               u->packets = (i + 1) * total_packs / subs->nurbs
+                       - i * total_packs / subs->nurbs;
                u->buffer_size = maxsize * u->packets;
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
@@ -1292,14 +1277,14 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
                if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
+                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, rate, ep);
                        return err;
                }
                if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n",
+                       snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, ep);
                        return 0; /* some devices don't support reading */
                }
@@ -1431,9 +1416,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        subs->cur_audiofmt = fmt;
 
 #if 0
-       printk("setting done: format = %d, rate = %d..%d, channels = %d\n",
+       printk(KERN_DEBUG
+              "setting done: format = %d, rate = %d..%d, channels = %d\n",
               fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
-       printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
+       printk(KERN_DEBUG
+              "  datapipe = 0x%0x, syncpipe = 0x%0x\n",
               subs->datapipe, subs->syncpipe);
 #endif
 
@@ -1468,7 +1455,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        channels = params_channels(hw_params);
        fmt = find_format(subs, format, rate, channels);
        if (!fmt) {
-               snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+               snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
                           format, rate, channels);
                return -EINVAL;
        }
@@ -1795,7 +1782,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
                        if (rates[f->format] && rates[f->format] != f->rates)
                                goto __out;
                }
-               channels[f->format] |= (1 << f->channels);
+               channels[f->format] |= 1 << (f->channels - 1);
                rates[f->format] |= f->rates;
                /* needs knot? */
                if (f->rates & SNDRV_PCM_RATE_KNOT)
@@ -1822,7 +1809,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
                        continue;
                for (i = 0; i < 32; i++) {
                        if (f->rates & (1 << i))
-                               channels[i] |= (1 << f->channels);
+                               channels[i] |= 1 << (f->channels - 1);
                }
        }
        cmaster = 0;
@@ -1919,7 +1906,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
         * in the current code assume the 1ms period.
         */
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                    1000 * MIN_PACKS_URB,
+                                    1000,
                                     /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
 
        err = check_hw_params_convention(subs);
@@ -2160,7 +2147,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                fp = list_entry(p, struct audioformat, list);
                snd_iprintf(buffer, "  Interface %d\n", fp->iface);
                snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-               snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);
+               snd_iprintf(buffer, "    Format: %#x\n", fp->format);
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -2180,7 +2167,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                        snd_iprintf(buffer, "\n");
                }
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
-               // snd_iprintf(buffer, "    EP Attribute = 0x%x\n", fp->attributes);
+               // snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes);
        }
 }
 
@@ -2621,7 +2608,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
        default:
-               snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected.  processed as MPEG.\n",
+               snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n",
                           chip->dev->devnum, fp->iface, fp->altsetting, format);
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
@@ -2819,7 +2806,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
                }
 
-               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
+               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
                err = add_audio_endpoint(chip, stream, fp);
                if (err < 0) {
                        kfree(fp->rate_table);
@@ -3466,10 +3453,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                return -ENXIO;
        }
 
-       card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0);
-       if (card == NULL) {
+       err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+       if (err < 0) {
                snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
-               return -ENOMEM;
+               return err;
        }
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
@@ -3766,7 +3753,7 @@ static int usb_audio_resume(struct usb_interface *intf)
 
 static int __init snd_usb_audio_init(void)
 {
-       if (nrpacks < MIN_PACKS_URB || nrpacks > MAX_PACKS) {
+       if (nrpacks < 1 || nrpacks > MAX_PACKS) {
                printk(KERN_WARNING "invalid nrpacks value.\n");
                return -EINVAL;
        }
index 00397c8a765ba62b6f004e5a36d818aa8f25f923..ecb58e7a6245f5bea88294093628a23c54744643 100644 (file)
@@ -66,6 +66,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
+       { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
 struct usb_mixer_interface {
@@ -78,7 +79,6 @@ struct usb_mixer_interface {
 
        /* Sound Blaster remote control stuff */
        const struct rc_config *rc_cfg;
-       unsigned long rc_hwdep_open;
        u32 rc_code;
        wait_queue_head_t rc_waitq;
        struct urb *rc_urb;
@@ -110,6 +110,8 @@ struct mixer_build {
        const struct usbmix_selector_map *selector_map;
 };
 
+#define MAX_CHANNELS   10      /* max logical channels */
+
 struct usb_mixer_elem_info {
        struct usb_mixer_interface *mixer;
        struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
@@ -120,6 +122,8 @@ struct usb_mixer_elem_info {
        int channels;
        int val_type;
        int min, max, res;
+       int cached;
+       int cache_val[MAX_CHANNELS];
        u8 initialized;
 };
 
@@ -181,8 +185,6 @@ enum {
        USB_PROC_DCR_RELEASE = 6,
 };
 
-#define MAX_CHANNELS   10      /* max logical channels */
-
 
 /*
  * manual mapping of mixer names
@@ -219,7 +221,10 @@ static int check_ignored_ctl(struct mixer_build *state, int unitid, int control)
        for (p = state->map; p->id; p++) {
                if (p->id == unitid && ! p->name &&
                    (! control || ! p->control || control == p->control)) {
-                       // printk("ignored control %d:%d\n", unitid, control);
+                       /*
+                       printk(KERN_DEBUG "ignored control %d:%d\n",
+                              unitid, control);
+                       */
                        return 1;
                }
        }
@@ -376,11 +381,35 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *
 }
 
 /* channel = 0: master, 1 = first channel */
-static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value)
+static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
+                                 int channel, int *value)
 {
        return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
 }
 
+static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
+                            int channel, int index, int *value)
+{
+       int err;
+
+       if (cval->cached & (1 << channel)) {
+               *value = cval->cache_val[index];
+               return 0;
+       }
+       err = get_cur_mix_raw(cval, channel, value);
+       if (err < 0) {
+               if (!cval->mixer->ignore_ctl_error)
+                       snd_printd(KERN_ERR "cannot get current value for "
+                                  "control %d ch %d: err = %d\n",
+                                  cval->control, channel, err);
+               return err;
+       }
+       cval->cached |= 1 << channel;
+       cval->cache_val[index] = *value;
+       return 0;
+}
+
+
 /*
  * set a mixer value
  */
@@ -412,9 +441,17 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int v
        return set_ctl_value(cval, SET_CUR, validx, value);
 }
 
-static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value)
+static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+                            int index, int value)
 {
-       return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
+       int err;
+       err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel,
+                           value);
+       if (err < 0)
+               return err;
+       cval->cached |= 1 << channel;
+       cval->cache_val[index] = value;
+       return 0;
 }
 
 /*
@@ -718,7 +755,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                if (cval->min + cval->res < cval->max) {
                        int last_valid_res = cval->res;
                        int saved, test, check;
-                       get_cur_mix_value(cval, minchn, &saved);
+                       get_cur_mix_raw(cval, minchn, &saved);
                        for (;;) {
                                test = saved;
                                if (test < cval->max)
@@ -726,8 +763,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                                else
                                        test -= cval->res;
                                if (test < cval->min || test > cval->max ||
-                                   set_cur_mix_value(cval, minchn, test) ||
-                                   get_cur_mix_value(cval, minchn, &check)) {
+                                   set_cur_mix_value(cval, minchn, 0, test) ||
+                                   get_cur_mix_raw(cval, minchn, &check)) {
                                        cval->res = last_valid_res;
                                        break;
                                }
@@ -735,7 +772,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                                        break;
                                cval->res *= 2;
                        }
-                       set_cur_mix_value(cval, minchn, saved);
+                       set_cur_mix_value(cval, minchn, 0, saved);
                }
 
                cval->initialized = 1;
@@ -775,35 +812,25 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
        int c, cnt, val, err;
 
+       ucontrol->value.integer.value[0] = cval->min;
        if (cval->cmask) {
                cnt = 0;
                for (c = 0; c < MAX_CHANNELS; c++) {
-                       if (cval->cmask & (1 << c)) {
-                               err = get_cur_mix_value(cval, c + 1, &val);
-                               if (err < 0) {
-                                       if (cval->mixer->ignore_ctl_error) {
-                                               ucontrol->value.integer.value[0] = cval->min;
-                                               return 0;
-                                       }
-                                       snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
-                                       return err;
-                               }
-                               val = get_relative_value(cval, val);
-                               ucontrol->value.integer.value[cnt] = val;
-                               cnt++;
-                       }
+                       if (!(cval->cmask & (1 << c)))
+                               continue;
+                       err = get_cur_mix_value(cval, c + 1, cnt, &val);
+                       if (err < 0)
+                               return cval->mixer->ignore_ctl_error ? 0 : err;
+                       val = get_relative_value(cval, val);
+                       ucontrol->value.integer.value[cnt] = val;
+                       cnt++;
                }
+               return 0;
        } else {
                /* master channel */
-               err = get_cur_mix_value(cval, 0, &val);
-               if (err < 0) {
-                       if (cval->mixer->ignore_ctl_error) {
-                               ucontrol->value.integer.value[0] = cval->min;
-                               return 0;
-                       }
-                       snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err);
-                       return err;
-               }
+               err = get_cur_mix_value(cval, 0, 0, &val);
+               if (err < 0)
+                       return cval->mixer->ignore_ctl_error ? 0 : err;
                val = get_relative_value(cval, val);
                ucontrol->value.integer.value[0] = val;
        }
@@ -820,34 +847,28 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (cval->cmask) {
                cnt = 0;
                for (c = 0; c < MAX_CHANNELS; c++) {
-                       if (cval->cmask & (1 << c)) {
-                               err = get_cur_mix_value(cval, c + 1, &oval);
-                               if (err < 0) {
-                                       if (cval->mixer->ignore_ctl_error)
-                                               return 0;
-                                       return err;
-                               }
-                               val = ucontrol->value.integer.value[cnt];
-                               val = get_abs_value(cval, val);
-                               if (oval != val) {
-                                       set_cur_mix_value(cval, c + 1, val);
-                                       changed = 1;
-                               }
-                               get_cur_mix_value(cval, c + 1, &val);
-                               cnt++;
+                       if (!(cval->cmask & (1 << c)))
+                               continue;
+                       err = get_cur_mix_value(cval, c + 1, cnt, &oval);
+                       if (err < 0)
+                               return cval->mixer->ignore_ctl_error ? 0 : err;
+                       val = ucontrol->value.integer.value[cnt];
+                       val = get_abs_value(cval, val);
+                       if (oval != val) {
+                               set_cur_mix_value(cval, c + 1, cnt, val);
+                               changed = 1;
                        }
+                       cnt++;
                }
        } else {
                /* master channel */
-               err = get_cur_mix_value(cval, 0, &oval);
-               if (err < 0 && cval->mixer->ignore_ctl_error)
-                       return 0;
+               err = get_cur_mix_value(cval, 0, 0, &oval);
                if (err < 0)
-                       return err;
+                       return cval->mixer->ignore_ctl_error ? 0 : err;
                val = ucontrol->value.integer.value[0];
                val = get_abs_value(cval, val);
                if (val != oval) {
-                       set_cur_mix_value(cval, 0, val);
+                       set_cur_mix_value(cval, 0, 0, val);
                        changed = 1;
                }
        }
@@ -1706,7 +1727,8 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
                break;
        /* live24ext: 4 = line-in jack */
        case 3: /* hp-out jack (may actuate Mute) */
-               if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+               if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                   mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
                        snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
                break;
        default:
@@ -1797,24 +1819,6 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb)
        wake_up(&mixer->rc_waitq);
 }
 
-static int snd_usb_sbrc_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       struct usb_mixer_interface *mixer = hw->private_data;
-
-       if (test_and_set_bit(0, &mixer->rc_hwdep_open))
-               return -EBUSY;
-       return 0;
-}
-
-static int snd_usb_sbrc_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       struct usb_mixer_interface *mixer = hw->private_data;
-
-       clear_bit(0, &mixer->rc_hwdep_open);
-       smp_mb__after_clear_bit();
-       return 0;
-}
-
 static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,
                                     long count, loff_t *offset)
 {
@@ -1867,9 +1871,8 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
        hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
        hwdep->private_data = mixer;
        hwdep->ops.read = snd_usb_sbrc_hwdep_read;
-       hwdep->ops.open = snd_usb_sbrc_hwdep_open;
-       hwdep->ops.release = snd_usb_sbrc_hwdep_release;
        hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
+       hwdep->exclusive = 1;
 
        mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!mixer->rc_urb)
@@ -1956,8 +1959,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
        int i, err;
 
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
-               if (i > 1 &&  /* Live24ext has 2 LEDs only */
-                       mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+               if (i > 1 && /* Live24ext has 2 LEDs only */
+                       (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
                                  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
@@ -1994,7 +1998,8 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
                jacks = jacks_audigy2nx;
-       else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+       else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
                jacks = jacks_live24ext;
        else
                return;
@@ -2044,7 +2049,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                goto _error;
 
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
-           mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) {
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
                struct snd_info_entry *entry;
 
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
index d755be0ad8115da5c1296211678f81a7774277d5..3e5d66cf1f5a3ef8212afe5fca7128d01fbcfff6 100644 (file)
@@ -261,6 +261,22 @@ static struct usbmix_name_map aureon_51_2_map[] = {
        {} /* terminator */
 };
 
+static struct usbmix_name_map scratch_live_map[] = {
+       /* 1: IT Line 1 (USB streaming) */
+       /* 2: OT Line 1 (Speaker) */
+       /* 3: IT Line 1 (Line connector) */
+       { 4, "Line 1 In" }, /* FU */
+       /* 5: OT Line 1 (USB streaming) */
+       /* 6: IT Line 2 (USB streaming) */
+       /* 7: OT Line 2 (Speaker) */
+       /* 8: IT Line 2 (Line connector) */
+       { 9, "Line 2 In" }, /* FU */
+       /* 10: OT Line 2 (USB streaming) */
+       /* 11: IT Mic (Line connector) */
+       /* 12: OT Mic (USB streaming) */
+       { 0 } /* terminator */
+};
+
 /*
  * Control map entries
  */
@@ -284,6 +300,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x041e, 0x3040),
                .map = live24ext_map,
        },
+       {
+               .id = USB_ID(0x041e, 0x3048),
+               .map = audigy2nx_map,
+               .selector_map = audigy2nx_selectors,
+       },
        {
                /* Hercules DJ Console (Windows Edition) */
                .id = USB_ID(0x06f8, 0xb000),
@@ -311,6 +332,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x0ccd, 0x0028),
                .map = aureon_51_2_map,
        },
+       {
+               .id = USB_ID(0x13e5, 0x0001),
+               .map = scratch_live_map,
+               .ignore_ctl_error = 1,
+       },
        { 0 } /* terminator */
 };
 
index 5d8ef09b9dcc17d01f85d2ca27047a7faa30fe4f..647ef502965179ec6f1eec15c042990a950aedf6 100644 (file)
        .idProduct = prod, \
        .bInterfaceClass = USB_CLASS_VENDOR_SPEC
 
+/* Creative/Toshiba Multimedia Center SB-0500 */
+{
+       USB_DEVICE(0x041e, 0x3048),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Toshiba",
+               .product_name = "SB-0500",
+               .ifnum = QUIRK_NO_INTERFACE
+       }
+},
+
 /* Creative/E-Mu devices */
 {
        USB_DEVICE(0x041e, 0x3010),
index 73e59f4403a483b16a041a9bba9f767e6b021c60..98276aafefe605040d7c18cd367fa4aa8096bd5a 100644 (file)
@@ -478,19 +478,21 @@ static bool us122l_create_card(struct snd_card *card)
        return true;
 }
 
-static struct snd_card *usx2y_create_card(struct usb_device *device)
+static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
 {
        int             dev;
        struct snd_card *card;
+       int err;
+
        for (dev = 0; dev < SNDRV_CARDS; ++dev)
                if (enable[dev] && !snd_us122l_card_used[dev])
                        break;
        if (dev >= SNDRV_CARDS)
-               return NULL;
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-                           sizeof(struct us122l));
-       if (!card)
-               return NULL;
+               return -ENODEV;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct us122l), &card);
+       if (err < 0)
+               return err;
        snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
 
        US122L(card)->chip.dev = device;
@@ -509,46 +511,57 @@ static struct snd_card *usx2y_create_card(struct usb_device *device)
                US122L(card)->chip.dev->devnum
                );
        snd_card_set_dev(card, &device->dev);
-       return card;
+       *cardp = card;
+       return 0;
 }
 
-static void *us122l_usb_probe(struct usb_interface *intf,
-                             const struct usb_device_id *device_id)
+static int us122l_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *device_id,
+                           struct snd_card **cardp)
 {
        struct usb_device *device = interface_to_usbdev(intf);
-       struct snd_card *card = usx2y_create_card(device);
+       struct snd_card *card;
+       int err;
 
-       if (!card)
-               return NULL;
+       err = usx2y_create_card(device, &card);
+       if (err < 0)
+               return err;
 
-       if (!us122l_create_card(card) ||
-           snd_card_register(card) < 0) {
+       if (!us122l_create_card(card)) {
                snd_card_free(card);
-               return NULL;
+               return -EINVAL;
+       }
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
        }
 
        usb_get_dev(device);
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 static int snd_us122l_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
        struct snd_card *card;
+       int err;
+
        snd_printdd(KERN_DEBUG"%p:%i\n",
                    intf, intf->cur_altsetting->desc.bInterfaceNumber);
        if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
                return 0;
 
-       card = us122l_usb_probe(usb_get_intf(intf), id);
-
-       if (card) {
-               usb_set_intfdata(intf, card);
-               return 0;
+       err = us122l_usb_probe(usb_get_intf(intf), id, &card);
+       if (err < 0) {
+               usb_put_intf(intf);
+               return err;
        }
 
-       usb_put_intf(intf);
-       return -EIO;
+       usb_set_intfdata(intf, card);
+       return 0;
 }
 
 static void snd_us122l_disconnect(struct usb_interface *intf)
index 1558a5c4094faebb589c9822a37182c837867c39..4af8740db7170ea34734037d6544d49ffd8e8953 100644 (file)
@@ -30,9 +30,6 @@
 #include "usbusx2y.h"
 #include "usX2Yhwdep.h"
 
-int usX2Y_hwdep_pcm_new(struct snd_card *card);
-
-
 static int snd_us428ctls_vm_fault(struct vm_area_struct *area,
                                  struct vm_fault *vmf)
 {
@@ -106,16 +103,6 @@ static unsigned int snd_us428ctls_poll(struct snd_hwdep *hw, struct file *file,
 }
 
 
-static int snd_usX2Y_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
-static int snd_usX2Y_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
-       return 0;
-}
-
 static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw,
                                      struct snd_hwdep_dsp_status *info)
 {
@@ -267,8 +254,6 @@ int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device)
 
        hw->iface = SNDRV_HWDEP_IFACE_USX2Y;
        hw->private_data = usX2Y(card);
-       hw->ops.open = snd_usX2Y_hwdep_open;
-       hw->ops.release = snd_usX2Y_hwdep_release;
        hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status;
        hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load;
        hw->ops.mmap = snd_us428ctls_mmap;
index 70b96355ca4cfba36b726c0fd11d0c62bbeaa359..24393dafcb6e9aa406f419403331b2674015b00d 100644 (file)
@@ -557,7 +557,7 @@ static void stream_start(struct usb_stream_kernel *sk,
                s->idle_insize -= max_diff - max_diff_0;
                s->idle_insize += urb_size - s->period_size;
                if (s->idle_insize < 0) {
-                       snd_printk("%i %i %i\n",
+                       snd_printk(KERN_WARNING "%i %i %i\n",
                                   s->idle_insize, urb_size, s->period_size);
                        return;
                } else if (s->idle_insize == 0) {
index 11639bd72a518fe340f54236ccecf6c2667f7f67..5ce0da23ee96fd22752b53ffcab1d7f8057672b9 100644 (file)
@@ -227,9 +227,9 @@ static void i_usX2Y_In04Int(struct urb *urb)
        
        if (usX2Y->US04) {
                if (0 == usX2Y->US04->submitted)
-                       do
+                       do {
                                err = usb_submit_urb(usX2Y->US04->urb[usX2Y->US04->submitted++], GFP_ATOMIC);
-                       while (!err && usX2Y->US04->submitted < usX2Y->US04->len);
+                       while (!err && usX2Y->US04->submitted < usX2Y->US04->len);
        } else
                if (us428ctls && us428ctls->p4outLast >= 0 && us428ctls->p4outLast < N_us428_p4out_BUFS) {
                        if (us428ctls->p4outLast != us428ctls->p4outSent) {
@@ -333,18 +333,21 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = {
        { /* terminator */ }
 };
 
-static struct snd_card *usX2Y_create_card(struct usb_device *device)
+static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
 {
        int             dev;
        struct snd_card *       card;
+       int err;
+
        for (dev = 0; dev < SNDRV_CARDS; ++dev)
                if (enable[dev] && !snd_usX2Y_card_used[dev])
                        break;
        if (dev >= SNDRV_CARDS)
-               return NULL;
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct usX2Ydev));
-       if (!card)
-               return NULL;
+               return -ENODEV;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct usX2Ydev), &card);
+       if (err < 0)
+               return err;
        snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1;
        card->private_free = snd_usX2Y_card_private_free;
        usX2Y(card)->chip.dev = device;
@@ -362,26 +365,36 @@ static struct snd_card *usX2Y_create_card(struct usb_device *device)
                usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
                );
        snd_card_set_dev(card, &device->dev);
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 
-static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *intf, const struct usb_device_id *device_id)
+static int usX2Y_usb_probe(struct usb_device *device,
+                          struct usb_interface *intf,
+                          const struct usb_device_id *device_id,
+                          struct snd_card **cardp)
 {
        int             err;
        struct snd_card *       card;
+
+       *cardp = NULL;
        if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
            (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
             le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
-            le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428) ||
-           !(card = usX2Y_create_card(device)))
-               return NULL;
+            le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))
+               return -EINVAL;
+
+       err = usX2Y_create_card(device, &card);
+       if (err < 0)
+               return err;
        if ((err = usX2Y_hwdep_new(card, device)) < 0  ||
            (err = snd_card_register(card)) < 0) {
                snd_card_free(card);
-               return NULL;
+               return err;
        }
-       return card;
+       *cardp = card;
+       return 0;
 }
 
 /*
@@ -389,13 +402,14 @@ static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *in
  */
 static int snd_usX2Y_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-       void *chip;
-       chip = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id);
-       if (chip) {
-               usb_set_intfdata(intf, chip);
-               return 0;
-       } else
-               return -EIO;
+       struct snd_card *card;
+       int err;
+
+       err = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id, &card);
+       if (err < 0)
+               return err;
+       dev_set_drvdata(&intf->dev, card);
+       return 0;
 }
 
 static void snd_usX2Y_disconnect(struct usb_interface *intf)
index c3382fdc386b6774e95e3a8bfdd083aa3004904b..9c4fb84b2aa0f8f2a1e6d851055829244d3bded7 100644 (file)
@@ -18,3 +18,5 @@ struct snd_usX2Y_hwdep_pcm_shm {
        volatile unsigned captured_iso_frames;
        int capture_iso_start;
 };
+
+int usX2Y_hwdep_pcm_new(struct snd_card *card);