Merge branch 'topic/hda' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Sun, 22 May 2011 08:01:35 +0000 (10:01 +0200)
committerTakashi Iwai <tiwai@suse.de>
Sun, 22 May 2011 08:01:35 +0000 (10:01 +0200)
943 files changed:
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/v4l/media-ioc-setup-link.xml
Documentation/DocBook/v4l/pixfmt-y12.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/subdev-formats.xml
Documentation/cgroups/memory.txt
Documentation/feature-removal-schedule.txt
Documentation/flexible-arrays.txt
Documentation/hwmon/adm1021
Documentation/hwmon/lm90
Documentation/hwmon/max16064 [new file with mode: 0644]
Documentation/hwmon/max34440 [new file with mode: 0644]
Documentation/hwmon/max8688 [new file with mode: 0644]
Documentation/hwmon/pmbus
Documentation/hwmon/smm665
Documentation/hwmon/submitting-patches [new file with mode: 0644]
Documentation/input/event-codes.txt [new file with mode: 0644]
Documentation/md.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/video4linux/sh_mobile_ceu_camera.txt
Documentation/workqueue.txt
MAINTAINERS
Makefile
arch/alpha/kernel/Makefile
arch/alpha/kernel/core_mcpcia.c
arch/alpha/kernel/err_titan.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smc37c93x.c
arch/alpha/kernel/sys_wildfire.c
arch/alpha/kernel/time.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/common/Makefile
arch/arm/configs/at91x40_defconfig [new file with mode: 0644]
arch/arm/include/asm/cputype.h
arch/arm/include/asm/kprobes.h
arch/arm/include/asm/thread_notify.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/Makefile
arch/arm/kernel/calls.S
arch/arm/kernel/elf.c
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/kprobes-decode.c
arch/arm/kernel/kprobes.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/smp.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/kernel/traps.c
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/board-eb01.c
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/board-mityomapl138.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/include/mach/debug-macro.S
arch/arm/mach-davinci/include/mach/serial.h
arch/arm/mach-mmp/include/mach/gpio.h
arch/arm/mach-mmp/include/mach/mfp-pxa168.h
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-msm/timer.c
arch/arm/mach-mx3/mach-vpr200.c
arch/arm/mach-mx5/board-mx53_loco.c
arch/arm/mach-mxs/clock-mx28.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/cm2xxx_3xxx.c
arch/arm/mach-omap2/control.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_l3_smx.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/voltage.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/include/mach/gpio.h
arch/arm/mach-pxa/include/mach/irqs.h
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/gpio.c
arch/arm/mach-tegra/include/mach/harmony_audio.h [deleted file]
arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h [new file with mode: 0644]
arch/arm/mach-tegra/tegra2_clocks.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mm/mmap.c
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/ssi-fiq.S
arch/arm/plat-s5p/pm.c
arch/arm/plat-samsung/pm-check.c
arch/arm/plat-samsung/pm.c
arch/arm/vfp/vfpmodule.c
arch/avr32/include/asm/setup.h
arch/avr32/kernel/setup.c
arch/avr32/kernel/traps.c
arch/avr32/mach-at32ap/clock.c
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/pio.c
arch/avr32/mach-at32ap/pm-at32ap700x.S
arch/blackfin/include/asm/system.h
arch/blackfin/kernel/gptimers.c
arch/blackfin/kernel/time-ts.c
arch/blackfin/mach-common/smp.c
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/entry_mm.S
arch/m68k/kernel/syscalltable.S
arch/m68k/mm/motorola.c
arch/microblaze/Kconfig
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/8xx_immap.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/pte-common.h
arch/powerpc/include/asm/uninorth.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/perf_event.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/time.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_rio.c
arch/s390/crypto/prng.c
arch/s390/kvm/sie64a.S
arch/s390/mm/fault.c
arch/s390/mm/pageattr.c
arch/sh/kernel/ptrace_32.c
arch/um/Kconfig.um
arch/um/Kconfig.x86
arch/um/include/asm/bug.h [new file with mode: 0644]
arch/um/include/asm/thread_info.h
arch/um/sys-i386/Makefile
arch/um/sys-i386/atomic64_cx8_32.S [new file with mode: 0644]
arch/x86/boot/memory.c
arch/x86/include/asm/gart.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/numa.h
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/reboot_32.S
arch/x86/mm/numa.c
arch/x86/mm/numa_64.c
arch/x86/mm/numa_emulation.c
arch/x86/platform/ce4100/falconfalls.dts
arch/x86/platform/mrst/mrst.c
arch/x86/xen/Kconfig
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/setup.c
arch/xtensa/kernel/irq.c
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-sysfs.c
block/cfq-iosched.c
block/elevator.c
block/genhd.c
drivers/acpi/scan.c
drivers/amba/bus.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ata_piix.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_at91.c
drivers/base/platform.c
drivers/base/power/main.c
drivers/base/power/wakeup.c
drivers/base/syscore.c
drivers/block/rbd.c
drivers/char/agp/generic.c
drivers/char/virtio_console.c
drivers/clk/clkdev.c
drivers/connector/connector.c
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/edac_mc_sysfs.c
drivers/firewire/ohci.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_evo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nvc0_vm.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/reg_srcs/r600
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/gpu/stub/Kconfig
drivers/hwmon/Kconfig
drivers/hwmon/lm85.c
drivers/hwmon/lm90.c
drivers/hwmon/pmbus_core.c
drivers/hwmon/twl4030-madc-hwmon.c
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-parport.c
drivers/i2c/i2c-core.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd_ioctl.c
drivers/ide/ide-gd.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_iba7220.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/keyboard/twl4030_keypad.c
drivers/input/misc/xen-kbdfront.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/wm831x-ts.c
drivers/leds/leds-regulator.c
drivers/md/dm-raid.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/common/tuners/tda18271-common.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda18271-maps.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/ngene/ngene-core.c
drivers/media/media-entity.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-maestro.c [deleted file]
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/saa7706h.c
drivers/media/radio/tef6862.c
drivers/media/rc/imon.c
drivers/media/rc/ite-cir.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/video/Kconfig
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx23885/Kconfig
drivers/media/video/imx074.c
drivers/media/video/m52790.c
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/isp.h
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/omap3isp/ispqueue.c
drivers/media/video/omap3isp/ispresizer.c
drivers/media/video/omap3isp/ispstat.h
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c
drivers/media/video/soc_camera.c
drivers/media/video/tda9840.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/v4l2-dev.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf2-core.c
drivers/media/video/videobuf2-dma-contig.c
drivers/mfd/mfd-core.c
drivers/mfd/omap-usb-host.c
drivers/misc/sgi-gru/grufile.c
drivers/mmc/core/bus.c
drivers/mmc/core/host.c
drivers/mmc/host/omap.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mtd/nand/diskonchip.c
drivers/net/amd8111e.c
drivers/net/atl1c/atl1c.h
drivers/net/atl1c/atl1c_main.c
drivers/net/benet/be_main.c
drivers/net/bna/bfa_ioc.c
drivers/net/bna/bfa_ioc.h
drivers/net/bna/bfa_ioc_ct.c
drivers/net/bna/bfi.h
drivers/net/bna/bnad.c
drivers/net/bnx2.c
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_alb.h
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/ehea/ehea_main.c
drivers/net/fs_enet/mac-fec.c
drivers/net/ftmac100.c
drivers/net/loopback.c
drivers/net/mii.c
drivers/net/natsemi.c
drivers/net/netconsole.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_main.c
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_main.c
drivers/net/r8169.c
drivers/net/sfc/efx.c
drivers/net/sfc/io.h
drivers/net/sfc/net_driver.h
drivers/net/sfc/nic.c
drivers/net/sfc/nic.h
drivers/net/sfc/selftest.c
drivers/net/sfc/tx.c
drivers/net/sis900.c
drivers/net/stmmac/dwmac_lib.c
drivers/net/stmmac/stmmac_main.c
drivers/net/tg3.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/olympic.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/regd_common.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/iwlegacy/Kconfig
drivers/net/wireless/iwlegacy/iwl-3945-hw.h
drivers/net/wireless/iwlegacy/iwl-4965-hw.h
drivers/net/wireless/iwlegacy/iwl-4965-tx.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-eeprom.c
drivers/net/wireless/iwlegacy/iwl-led.c
drivers/net/wireless/iwlegacy/iwl3945-base.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/txrx.c
drivers/parport/parport_pc.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/intel-iommu.c
drivers/pci/pci-driver.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_balloon3.c
drivers/pcmcia/pxa2xx_trizeps4.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/rapidio/rio.c
drivers/rapidio/switches/idt_gen2.c
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/cio/qdio_main.c
drivers/s390/kvm/kvm_virtio.c
drivers/scsi/device_handler/scsi_dh.c
drivers/scsi/mpt2sas/mpt2sas_ctl.c
drivers/scsi/pmcraid.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
drivers/staging/gma500/Kconfig
drivers/staging/intel_sst/intel_sst_drv_interface.c
drivers/staging/intel_sst/intelmid.c
drivers/staging/intel_sst/intelmid_v1_control.c
drivers/staging/intel_sst/intelmid_v2_control.c
drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
drivers/staging/rt2860/common/cmm_data_pci.c
drivers/staging/rt2860/common/cmm_data_usb.c
drivers/staging/rts_pstor/debug.h
drivers/staging/rts_pstor/ms.c
drivers/staging/rts_pstor/rtsx_chip.c
drivers/staging/rts_pstor/rtsx_scsi.c
drivers/staging/rts_pstor/sd.c
drivers/staging/rts_pstor/trace.h
drivers/staging/rts_pstor/xd.c
drivers/staging/samsung-laptop/Kconfig [deleted file]
drivers/staging/samsung-laptop/Makefile [deleted file]
drivers/staging/samsung-laptop/TODO [deleted file]
drivers/staging/samsung-laptop/samsung-laptop.c [deleted file]
drivers/staging/solo6x10/Kconfig
drivers/staging/spectra/ffsport.c
drivers/staging/tidspbridge/dynload/cload.c
drivers/staging/tty/specialix.c
drivers/staging/usbip/vhci_hcd.c
drivers/staging/usbip/vhci_sysfs.c
drivers/staging/wlan-ng/cfg80211.c
drivers/tty/n_gsm.c
drivers/tty/serial/imx.c
drivers/usb/Kconfig
drivers/usb/core/devices.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/gadget/f_audio.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-q.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/Kconfig
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musbhsdma.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/ux500.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/video/pxafb.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/watchdog/iTCO_wdt.c
drivers/xen/events.c
drivers/xen/manage.c
fs/9p/fid.c
fs/9p/v9fs.h
fs/9p/vfs_dentry.c
fs/9p/vfs_inode_dotl.c
fs/9p/vfs_super.c
fs/binfmt_elf.c
fs/btrfs/acl.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/README
fs/cifs/cache.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_spnego.c
fs/cifs/cifs_unicode.c
fs/cifs/cifs_unicode.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/sess.c
fs/dcache.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/kthread.c
fs/ecryptfs/main.c
fs/ecryptfs/super.c
fs/fhandle.c
fs/file.c
fs/filesystems.c
fs/gfs2/aops.c
fs/gfs2/dir.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/ops_fstype.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/hpfs/Kconfig
fs/hpfs/alloc.c
fs/hpfs/anode.c
fs/hpfs/buffer.c
fs/hpfs/dir.c
fs/hpfs/dnode.c
fs/hpfs/ea.c
fs/hpfs/file.c
fs/hpfs/hpfs.h
fs/hpfs/hpfs_fn.h
fs/hpfs/inode.c
fs/hpfs/map.c
fs/hpfs/name.c
fs/hpfs/namei.c
fs/hpfs/super.c
fs/logfs/super.c
fs/namei.c
fs/namespace.c
fs/nfs/namespace.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c
fs/ocfs2/ocfs2_fs.h
fs/partitions/efi.c
fs/partitions/ldm.c
fs/proc/base.c
fs/proc/task_mmu.c
fs/ramfs/file-nommu.c
fs/ubifs/debug.h
fs/ubifs/file.c
fs/ubifs/log.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/super.c
fs/xattr.c
fs/xfs/linux-2.6/xfs_message.c
include/drm/drm_fb_helper.h
include/drm/drm_mm.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/linux/bit_spinlock.h
include/linux/blkdev.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/flex_array.h
include/linux/ftrace_event.h
include/linux/huge_mm.h
include/linux/input.h
include/linux/input/mt.h
include/linux/libata.h
include/linux/list_bl.h
include/linux/memcontrol.h
include/linux/mfd/core.h
include/linux/mfd/wm831x/pdata.h
include/linux/mfd/wm8994/pdata.h
include/linux/mm.h
include/linux/mmc/host.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/pci_ids.h
include/linux/percpu.h
include/linux/pid.h
include/linux/platform_device.h
include/linux/posix-clock.h
include/linux/ptrace.h
include/linux/rio.h
include/linux/rio_ids.h
include/linux/rtc.h
include/linux/sched.h
include/linux/security.h
include/linux/sunrpc/sched.h
include/linux/suspend.h
include/linux/usb/usbnet.h
include/linux/v4l2-mediabus.h
include/linux/videodev2.h
include/linux/vmstat.h
include/media/v4l2-device.h
include/net/9p/9p.h
include/net/9p/client.h
include/sound/ak4641.h [new file with mode: 0644]
include/sound/control.h
include/sound/max98095.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/tea575x-tuner.h
include/sound/tlv320dac33-plat.h
include/sound/tpa6130a2-plat.h
include/sound/wm8915.h [new file with mode: 0644]
include/sound/wm8962.h
include/trace/events/block.h
init/Kconfig
kernel/exit.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/proc.c
kernel/kexec.c
kernel/perf_event.c
kernel/pid.c
kernel/power/Kconfig
kernel/power/hibernate.c
kernel/power/suspend.c
kernel/ptrace.c
kernel/sched.c
kernel/sched_fair.c
kernel/time/posix-clock.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/watchdog.c
kernel/workqueue.c
lib/flex_array.c
lib/kstrtox.c
lib/test-kstrtox.c
lib/xz/xz_dec_lzma2.c
mm/huge_memory.c
mm/memory.c
mm/memory_hotplug.c
mm/mlock.c
mm/mmap.c
mm/oom_kill.c
mm/page_alloc.c
mm/shmem.c
mm/slub.c
mm/vmscan.c
mm/vmstat.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_common.c
net/9p/trans_virtio.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/sco.c
net/bridge/br_input.c
net/bridge/br_netfilter.c
net/caif/cfdgml.c
net/caif/cfmuxl.c
net/can/bcm.c
net/can/raw.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/core/dev.c
net/dsa/Kconfig
net/dsa/mv88e6131.c
net/ieee802154/Makefile
net/ipv4/devinet.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/inetpeer.c
net/ipv4/ip_options.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/ipv6/esp6.c
net/ipv6/inet6_connection_sock.c
net/ipv6/route.c
net/ipv6/udp.c
net/irda/af_irda.c
net/l2tp/l2tp_ip.c
net/llc/llc_input.c
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/xt_set.c
net/sctp/associola.c
net/sctp/ulpevent.c
net/sunrpc/Kconfig
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/unix/af_unix.c
net/xfrm/xfrm_replay.c
net/xfrm/xfrm_user.c
scripts/kconfig/conf.c
security/capability.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/ss/policydb.c
security/smack/smack_lsm.c
sound/aoa/codecs/tas.c
sound/core/control.c
sound/core/init.c
sound/core/pcm_lib.c
sound/firewire/Kconfig
sound/firewire/Makefile
sound/firewire/isight.c [new file with mode: 0644]
sound/firewire/iso-resources.c
sound/firewire/packets-buffer.c
sound/i2c/other/Makefile
sound/i2c/other/tea575x-tuner.c
sound/oss/Kconfig
sound/oss/Makefile
sound/oss/ac97_codec.c [deleted file]
sound/oss/au1550_ac97.c [deleted file]
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpi_internal.h
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpicmn.h
sound/pci/asihpi/hpifunc.c
sound/pci/asihpi/hpimsgx.c
sound/pci/asihpi/hpioctl.c
sound/pci/au88x0/au8810.h
sound/pci/au88x0/au8820.h
sound/pci/au88x0/au8830.h
sound/pci/au88x0/au88x0_pcm.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/intel8x0m.c
sound/pci/lola/Makefile [new file with mode: 0644]
sound/pci/lola/lola.c [new file with mode: 0644]
sound/pci/lola/lola.h [new file with mode: 0644]
sound/pci/lola/lola_clock.c [new file with mode: 0644]
sound/pci/lola/lola_mixer.c [new file with mode: 0644]
sound/pci/lola/lola_pcm.c [new file with mode: 0644]
sound/pci/lola/lola_proc.c [new file with mode: 0644]
sound/ppc/tumbler.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.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/blackfin/bf5xx-sport.h
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c [new file with mode: 0644]
sound/soc/codecs/ak4641.h [new file with mode: 0644]
sound/soc/codecs/ak4671.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/dmic.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98088.h
sound/soc/codecs/max98095.c [new file with mode: 0644]
sound/soc/codecs/max98095.h [new file with mode: 0644]
sound/soc/codecs/sn95031.c
sound/soc/codecs/spdif_transciever.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm2602.h
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tlv320dac33.h
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/tpa6130a2.h
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wm1250-ev1.c [new file with mode: 0644]
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8915.c [new file with mode: 0644]
sound/soc/codecs/wm8915.h [new file with mode: 0644]
sound/soc/codecs/wm8958-dsp2.c [new file with mode: 0644]
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/imx/imx-ssi.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/qi_lb60.c
sound/soc/mid-x86/sst_platform.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/rx51.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/hx4700.c [new file with mode: 0644]
sound/soc/pxa/poodle.c
sound/soc/pxa/spitz.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/smdk_wm8580pcm.c [new file with mode: 0644]
sound/soc/samsung/speyside.c [new file with mode: 0644]
sound/soc/sh/fsi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-utils.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/harmony.c [deleted file]
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_i2s.c
sound/soc/tegra/tegra_wm8903.c [new file with mode: 0644]
sound/soc/tegra/trimslice.c [new file with mode: 0644]
sound/usb/6fire/control.c
sound/usb/6fire/control.h
sound/usb/6fire/firmware.c
sound/usb/6fire/pcm.c
sound/usb/Kconfig
sound/usb/clock.c
sound/usb/debug.h
sound/usb/format.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/perf/Makefile
tools/perf/builtin-record.c
tools/perf/builtin-stat.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/cgroup.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/python.c
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/hists.c

index 5d259c632cdfdb8af5627b990271d79201bb0c92..fea63b45471aadce771b99ce3874abb5ef2c9c36 100644 (file)
 <!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
 <!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
 <!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
+<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
 <!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
 <!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
index 2331e76ded17d652be38fdf24fdb1de848740b7e..cec97af4dab47cb924966439fbe771dbcbdea12a 100644 (file)
@@ -34,7 +34,7 @@
       <varlistentry>
        <term><parameter>request</parameter></term>
        <listitem>
-         <para>MEDIA_IOC_ENUM_LINKS</para>
+         <para>MEDIA_IOC_SETUP_LINK</para>
        </listitem>
       </varlistentry>
       <varlistentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-y12.xml b/Documentation/DocBook/v4l/pixfmt-y12.xml
new file mode 100644 (file)
index 0000000..ff417b8
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-Y12">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y12 ('Y12 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y12</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 12 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y12</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="9" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>Y'<subscript>00low</subscript></entry>
+                 <entry>Y'<subscript>00high</subscript></entry>
+                 <entry>Y'<subscript>01low</subscript></entry>
+                 <entry>Y'<subscript>01high</subscript></entry>
+                 <entry>Y'<subscript>02low</subscript></entry>
+                 <entry>Y'<subscript>02high</subscript></entry>
+                 <entry>Y'<subscript>03low</subscript></entry>
+                 <entry>Y'<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>Y'<subscript>10low</subscript></entry>
+                 <entry>Y'<subscript>10high</subscript></entry>
+                 <entry>Y'<subscript>11low</subscript></entry>
+                 <entry>Y'<subscript>11high</subscript></entry>
+                 <entry>Y'<subscript>12low</subscript></entry>
+                 <entry>Y'<subscript>12high</subscript></entry>
+                 <entry>Y'<subscript>13low</subscript></entry>
+                 <entry>Y'<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>Y'<subscript>20low</subscript></entry>
+                 <entry>Y'<subscript>20high</subscript></entry>
+                 <entry>Y'<subscript>21low</subscript></entry>
+                 <entry>Y'<subscript>21high</subscript></entry>
+                 <entry>Y'<subscript>22low</subscript></entry>
+                 <entry>Y'<subscript>22high</subscript></entry>
+                 <entry>Y'<subscript>23low</subscript></entry>
+                 <entry>Y'<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>Y'<subscript>30low</subscript></entry>
+                 <entry>Y'<subscript>30high</subscript></entry>
+                 <entry>Y'<subscript>31low</subscript></entry>
+                 <entry>Y'<subscript>31high</subscript></entry>
+                 <entry>Y'<subscript>32low</subscript></entry>
+                 <entry>Y'<subscript>32high</subscript></entry>
+                 <entry>Y'<subscript>33low</subscript></entry>
+                 <entry>Y'<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
index c6fdcbbd1b41dc7adbffc0011ac34a291b503509..40af4beb48b92aa7403e8c6682e1160cbbaa761d 100644 (file)
@@ -696,6 +696,7 @@ information.</para>
     &sub-packed-yuv;
     &sub-grey;
     &sub-y10;
+    &sub-y12;
     &sub-y16;
     &sub-yuyv;
     &sub-uyvy;
index 7041127d6dfcea31b867b0e33a75910396726839..d7ccd25edcc1f454e66e1bf1ae4b40ab52d9abd8 100644 (file)
              <entry>b<subscript>1</subscript></entry>
              <entry>b<subscript>0</subscript></entry>
            </row>
+           <row id="V4L2-MBUS-FMT-SGBRG8-1X8">
+             <entry>V4L2_MBUS_FMT_SGBRG8_1X8</entry>
+             <entry>0x3013</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
            <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
              <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
              <entry>0x3002</entry>
              <entry>g<subscript>1</subscript></entry>
              <entry>g<subscript>0</subscript></entry>
            </row>
+           <row id="V4L2-MBUS-FMT-SRGGB8-1X8">
+             <entry>V4L2_MBUS_FMT_SRGGB8_1X8</entry>
+             <entry>0x3014</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
            <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
              <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
              <entry>0x300b</entry>
              <entry>u<subscript>1</subscript></entry>
              <entry>u<subscript>0</subscript></entry>
            </row>
+           <row id="V4L2-MBUS-FMT-Y12-1X12">
+             <entry>V4L2_MBUS_FMT_Y12_1X12</entry>
+             <entry>0x2013</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>11</subscript></entry>
+             <entry>y<subscript>10</subscript></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
            <row id="V4L2-MBUS-FMT-UYVY8-1X16">
              <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
              <entry>0x200f</entry>
index b6ed61c958560d987e40cc28a9eca7f7d12401a1..7c163477fcd8f001fb217cc66e4c67812af907a7 100644 (file)
@@ -52,8 +52,10 @@ Brief summary of control files.
  tasks                          # attach a task(thread) and show list of threads
  cgroup.procs                   # show list of processes
  cgroup.event_control           # an interface for event_fd()
- memory.usage_in_bytes          # show current memory(RSS+Cache) usage.
- memory.memsw.usage_in_bytes    # show current memory+Swap usage
+ memory.usage_in_bytes          # show current res_counter usage for memory
+                                (See 5.5 for details)
+ memory.memsw.usage_in_bytes    # show current res_counter usage for memory+Swap
+                                (See 5.5 for details)
  memory.limit_in_bytes          # set/show limit of memory usage
  memory.memsw.limit_in_bytes    # set/show limit of memory+Swap usage
  memory.failcnt                         # show the number of memory usage hits limits
@@ -453,6 +455,15 @@ memory under it will be reclaimed.
 You can reset failcnt by writing 0 to failcnt file.
 # echo 0 > .../memory.failcnt
 
+5.5 usage_in_bytes
+
+For efficiency, as other kernel components, memory cgroup uses some optimization
+to avoid unnecessary cacheline false sharing. usage_in_bytes is affected by the
+method and doesn't show 'exact' value of memory(and swap) usage, it's an fuzz
+value for efficient access. (Of course, when necessary, it's synchronized.)
+If you want to know more exact memory usage, you should use RSS+CACHE(+SWAP)
+value in memory.stat(see 5.2).
+
 6. Hierarchy support
 
 The memory controller supports a deep hierarchy and hierarchical accounting.
index 274b32d12532a2e0e3814e70940b39721dde864a..492e81df296835e04ff6195304b3a32931e466c6 100644 (file)
@@ -387,26 +387,6 @@ Who:       Tejun Heo <tj@kernel.org>
 
 ----------------------------
 
-What:  Support for lcd_switch and display_get in asus-laptop driver
-When:  March 2010
-Why:   These two features use non-standard interfaces. There are the
-       only features that really need multiple path to guess what's
-       the right method name on a specific laptop.
-
-       Removing them will allow to remove a lot of code an significantly
-       clean the drivers.
-
-       This will affect the backlight code which won't be able to know
-       if the backlight is on or off. The platform display file will also be
-       write only (like the one in eeepc-laptop).
-
-       This should'nt affect a lot of user because they usually know
-       when their display is on or off.
-
-Who:   Corentin Chary <corentin.chary@gmail.com>
-
-----------------------------
-
 What:  sysfs-class-rfkill state file
 When:  Feb 2014
 Files: net/rfkill/core.c
index cb8a3a00cc92694947cb72840ddbcb340407ce08..df904aec99044f8056ac530b9e9dc6de8f26f73e 100644 (file)
@@ -66,10 +66,10 @@ trick is to ensure that any needed memory allocations are done before
 entering atomic context, using:
 
     int flex_array_prealloc(struct flex_array *array, unsigned int start,
-                           unsigned int end, gfp_t flags);
+                           unsigned int nr_elements, gfp_t flags);
 
 This function will ensure that memory for the elements indexed in the range
-defined by start and end has been allocated.  Thereafter, a
+defined by start and nr_elements has been allocated.  Thereafter, a
 flex_array_put() call on an element in that range is guaranteed not to
 block.
 
index 03d02bfb3df13a8f7f06859f8669de4a905bcc88..02ad96cf9b2b18e5b1307f0e8ad88be4f07d3fce 100644 (file)
@@ -14,10 +14,6 @@ Supported chips:
     Prefix: 'gl523sm'
     Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
     Datasheet:
-  * Intel Xeon Processor
-    Prefix: - any other - may require 'force_adm1021' parameter
-    Addresses scanned: none
-    Datasheet: Publicly available at Intel website
   * Maxim MAX1617
     Prefix: 'max1617'
     Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
@@ -91,21 +87,27 @@ will do no harm, but will return 'old' values. It is possible to make
 ADM1021-clones do faster measurements, but there is really no good reason
 for that.
 
-Xeon support
-------------
 
-Some Xeon processors have real max1617, adm1021, or compatible chips
-within them, with two temperature sensors.
+Netburst-based Xeon support
+---------------------------
 
-Other Xeons have chips with only one sensor.
+Some Xeon processors based on the Netburst (early Pentium 4, from 2001 to
+2003) microarchitecture had real MAX1617, ADM1021, or compatible chips
+within them, with two temperature sensors. Other Xeon processors of this
+era (with 400 MHz FSB) had chips with only one temperature sensor.
 
-If you have a Xeon, and the adm1021 module loads, and both temperatures
-appear valid, then things are good.
+If you have such an old Xeon, and you get two valid temperatures when
+loading the adm1021 module, then things are good.
 
-If the adm1021 module doesn't load, you should try this:
-       modprobe adm1021 force_adm1021=BUS,ADDRESS
-       ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e.
+If nothing happens when loading the adm1021 module, and you are certain
+that your specific Xeon processor model includes compatible sensors, you
+will have to explicitly instantiate the sensor chips from user-space. See
+method 4 in Documentation/i2c/instantiating-devices. Possible slave
+addresses are 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. It is likely that
+only temp2 will be correct and temp1 will have to be ignored.
 
-If you have dual Xeons you may have appear to have two separate
-adm1021-compatible chips, or two single-temperature sensors, at distinct
-addresses.
+Previous generations of the Xeon processor (based on Pentium II/III)
+didn't have these sensors. Next generations of Xeon processors (533 MHz
+FSB and faster) lost them, until the Core-based generation which
+introduced integrated digital thermal sensors. These are supported by
+the coretemp driver.
index fa475c0a48a34330e98b412e896013881dd6c50d..f3efd18e87f402ac3ba346ae15da07119f392fa6 100644 (file)
@@ -32,6 +32,16 @@ Supported chips:
     Addresses scanned: I2C 0x4c and 0x4d
     Datasheet: Publicly available at the ON Semiconductor website
                http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461
+  * Analog Devices ADT7461A
+    Prefix: 'adt7461a'
+    Addresses scanned: I2C 0x4c and 0x4d
+    Datasheet: Publicly available at the ON Semiconductor website
+               http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461A
+  * ON Semiconductor NCT1008
+    Prefix: 'nct1008'
+    Addresses scanned: I2C 0x4c and 0x4d
+    Datasheet: Publicly available at the ON Semiconductor website
+               http://www.onsemi.com/PowerSolutions/product.do?id=NCT1008
   * Maxim MAX6646
     Prefix: 'max6646'
     Addresses scanned: I2C 0x4d
@@ -149,7 +159,7 @@ ADM1032:
   * ALERT is triggered by open remote sensor.
   * SMBus PEC support for Write Byte and Receive Byte transactions.
 
-ADT7461:
+ADT7461, ADT7461A, NCT1008:
   * Extended temperature range (breaks compatibility)
   * Lower resolution for remote temperature
 
@@ -195,9 +205,9 @@ are exported, one for each channel, but these values are of course linked.
 Only the local hysteresis can be set from user-space, and the same delta
 applies to the remote hysteresis.
 
-The lm90 driver will not update its values more frequently than every
-other second; reading them more often will do no harm, but will return
-'old' values.
+The lm90 driver will not update its values more frequently than configured with
+the update_interval attribute; reading them more often will do no harm, but will
+return 'old' values.
 
 SMBus Alert Support
 -------------------
@@ -205,11 +215,12 @@ SMBus Alert Support
 This driver has basic support for SMBus alert. When an alert is received,
 the status register is read and the faulty temperature channel is logged.
 
-The Analog Devices chips (ADM1032 and ADT7461) do not implement the SMBus
-alert protocol properly so additional care is needed: the ALERT output is
-disabled when an alert is received, and is re-enabled only when the alarm
-is gone. Otherwise the chip would block alerts from other chips in the bus
-as long as the alarm is active.
+The Analog Devices chips (ADM1032, ADT7461 and ADT7461A) and ON
+Semiconductor chips (NCT1008) do not implement the SMBus alert protocol
+properly so additional care is needed: the ALERT output is disabled when
+an alert is received, and is re-enabled only when the alarm is gone.
+Otherwise the chip would block alerts from other chips in the bus as long
+as the alarm is active.
 
 PEC Support
 -----------
diff --git a/Documentation/hwmon/max16064 b/Documentation/hwmon/max16064
new file mode 100644 (file)
index 0000000..4172899
--- /dev/null
@@ -0,0 +1,62 @@
+Kernel driver max16064
+======================
+
+Supported chips:
+  * Maxim MAX16064
+    Prefix: 'max16064'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Maxim MAX16064 Quad Power-Supply
+Controller with Active-Voltage Output Control and PMBus Interface.
+
+The driver is a client driver to the core PMBus driver.
+Please see Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in[1-4]_label          "vout[1-4]"
+in[1-4]_input          Measured voltage. From READ_VOUT register.
+in[1-4]_min            Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[1-4]_max            Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[1-4]_lcrit          Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[1-4]_crit           Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[1-4]_min_alarm      Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[1-4]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[1-4]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[1-4]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
+temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
+temp1_crit             Critical high temperature. From OT_FAULT_LIMIT register.
+temp1_max_alarm                Chip temperature high alarm. Set by comparing
+                       READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING
+                       status is set.
+temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
+                       READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
+                       status is set.
diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440
new file mode 100644 (file)
index 0000000..6c525dd
--- /dev/null
@@ -0,0 +1,79 @@
+Kernel driver max34440
+======================
+
+Supported chips:
+  * Maxim MAX34440
+    Prefixes: 'max34440'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf
+  * Maxim MAX34441
+    PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller
+    Prefixes: 'max34441'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel
+Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager
+and Intelligent Fan Controller.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in[1-6]_label          "vout[1-6]".
+in[1-6]_input          Measured voltage. From READ_VOUT register.
+in[1-6]_min            Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[1-6]_max            Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[1-6]_lcrit          Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[1-6]_crit           Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[1-6]_min_alarm      Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[1-6]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[1-6]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[1-6]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr[1-6]_label                "iout[1-6]".
+curr[1-6]_input                Measured current. From READ_IOUT register.
+curr[1-6]_max          Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr[1-6]_crit         Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr[1-6]_max_alarm    Current high alarm. From IOUT_OC_WARNING status.
+curr[1-6]_crit_alarm   Current critical high alarm. From IOUT_OC_FAULT status.
+
+                       in6 and curr6 attributes only exist for MAX34440.
+
+temp[1-8]_input                Measured temperatures. From READ_TEMPERATURE_1 register.
+                       temp1 is the chip's internal temperature. temp2..temp5
+                       are remote I2C temperature sensors. For MAX34441, temp6
+                       is a remote thermal-diode sensor. For MAX34440, temp6..8
+                       are remote I2C temperature sensors.
+temp[1-8]_max          Maximum temperature. From OT_WARN_LIMIT register.
+temp[1-8]_crit         Critical high temperature. From OT_FAULT_LIMIT register.
+temp[1-8]_max_alarm    Temperature high alarm.
+temp[1-8]_crit_alarm   Temperature critical high alarm.
+
+                       temp7 and temp8 attributes only exist for MAX34440.
diff --git a/Documentation/hwmon/max8688 b/Documentation/hwmon/max8688
new file mode 100644 (file)
index 0000000..0ddd3a4
--- /dev/null
@@ -0,0 +1,69 @@
+Kernel driver max8688
+=====================
+
+Supported chips:
+  * Maxim MAX8688
+    Prefix: 'max8688'
+    Addresses scanned: -
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Maxim MAX8688 Digital Power-Supply
+Controller/Monitor with PMBus Interface.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label              "vout1"
+in1_input              Measured voltage. From READ_VOUT register.
+in1_min                        Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in1_max                        Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in1_lcrit              Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in1_crit               Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in1_min_alarm          Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in1_max_alarm          Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in1_lcrit_alarm                Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in1_crit_alarm         Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr1_label            "iout1"
+curr1_input            Measured current. From READ_IOUT register.
+curr1_max              Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr1_crit             Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr1_max_alarm                Current high alarm. From IOUT_OC_WARN_LIMIT register.
+curr1_crit_alarm       Current critical high alarm. From IOUT_OC_FAULT status.
+
+temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
+temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
+temp1_crit             Critical high temperature. From OT_FAULT_LIMIT register.
+temp1_max_alarm                Chip temperature high alarm. Set by comparing
+                       READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING
+                       status is set.
+temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
+                       READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
+                       status is set.
index dc4933e96344809ea8bf4f65ba607142426d4e69..5e462fc7f99b5f2e0f42c4edb92ebc1ac6c7571f 100644 (file)
@@ -13,26 +13,6 @@ Supported chips:
     Prefix: 'ltc2978'
     Addresses scanned: -
     Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
-  * Maxim MAX16064
-    Quad Power-Supply Controller
-    Prefix: 'max16064'
-    Addresses scanned: -
-    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf
-  * Maxim MAX34440
-    PMBus 6-Channel Power-Supply Manager
-    Prefixes: 'max34440'
-    Addresses scanned: -
-    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf
-  * Maxim MAX34441
-    PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller
-    Prefixes: 'max34441'
-    Addresses scanned: -
-    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf
-  * Maxim MAX8688
-    Digital Power-Supply Controller/Monitor
-    Prefix: 'max8688'
-    Addresses scanned: -
-    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf
   * Generic PMBus devices
     Prefix: 'pmbus'
     Addresses scanned: -
@@ -175,11 +155,13 @@ currX_crit                Critical maximum current.
                        From IIN_OC_FAULT_LIMIT or IOUT_OC_FAULT_LIMIT register.
 currX_alarm            Current high alarm.
                        From IIN_OC_WARNING or IOUT_OC_WARNING status.
+currX_max_alarm                Current high alarm.
+                       From IIN_OC_WARN_LIMIT or IOUT_OC_WARN_LIMIT status.
 currX_lcrit_alarm      Output current critical low alarm.
                        From IOUT_UC_FAULT status.
 currX_crit_alarm       Current critical high alarm.
                        From IIN_OC_FAULT or IOUT_OC_FAULT status.
-currX_label            "iin" or "vinY"
+currX_label            "iin" or "ioutY"
 
 powerX_input           Measured power. From READ_PIN or READ_POUT register.
 powerX_cap             Output power cap. From POUT_MAX register.
@@ -193,13 +175,13 @@ powerX_crit_alarm Output power critical high alarm.
                        From POUT_OP_FAULT status.
 powerX_label           "pin" or "poutY"
 
-tempX_input            Measured tempererature.
+tempX_input            Measured temperature.
                        From READ_TEMPERATURE_X register.
-tempX_min              Mimimum tempererature. From UT_WARN_LIMIT register.
-tempX_max              Maximum tempererature. From OT_WARN_LIMIT register.
-tempX_lcrit            Critical low tempererature.
+tempX_min              Mimimum temperature. From UT_WARN_LIMIT register.
+tempX_max              Maximum temperature. From OT_WARN_LIMIT register.
+tempX_lcrit            Critical low temperature.
                        From UT_FAULT_LIMIT register.
-tempX_crit             Critical high tempererature.
+tempX_crit             Critical high temperature.
                        From OT_FAULT_LIMIT register.
 tempX_min_alarm                Chip temperature low alarm. Set by comparing
                        READ_TEMPERATURE_X with UT_WARN_LIMIT if
index 3820fc9ca52d25ae4c3ed9a7e6d7f04fcb092bee..59e316140542017517be09171448fc4e6e16d28e 100644 (file)
@@ -150,8 +150,8 @@ in8_crit_alarm              Channel F critical alarm
 in9_crit_alarm         AIN1 critical alarm
 in10_crit_alarm                AIN2 critical alarm
 
-temp1_input            Chip tempererature
-temp1_min              Mimimum chip tempererature
-temp1_max              Maximum chip tempererature
-temp1_crit             Critical chip tempererature
+temp1_input            Chip temperature
+temp1_min              Mimimum chip temperature
+temp1_max              Maximum chip temperature
+temp1_crit             Critical chip temperature
 temp1_crit_alarm       Temperature critical alarm
diff --git a/Documentation/hwmon/submitting-patches b/Documentation/hwmon/submitting-patches
new file mode 100644 (file)
index 0000000..86f42e8
--- /dev/null
@@ -0,0 +1,109 @@
+       How to Get Your Patch Accepted Into the Hwmon Subsystem
+       -------------------------------------------------------
+
+This text is is a collection of suggestions for people writing patches or
+drivers for the hwmon subsystem. Following these suggestions will greatly
+increase the chances of your change being accepted.
+
+
+1. General
+----------
+
+* It should be unnecessary to mention, but please read and follow
+    Documentation/SubmitChecklist
+    Documentation/SubmittingDrivers
+    Documentation/SubmittingPatches
+    Documentation/CodingStyle
+
+* If your patch generates checkpatch warnings, please refrain from explanations
+  such as "I don't like that coding style". Keep in mind that each unnecessary
+  warning helps hiding a real problem. If you don't like the kernel coding
+  style, don't write kernel drivers.
+
+* Please test your patch thoroughly. We are not your test group.
+  Sometimes a patch can not or not completely be tested because of missing
+  hardware. In such cases, you should test-build the code on at least one
+  architecture. If run-time testing was not achieved, it should be written
+  explicitly below the patch header.
+
+* If your patch (or the driver) is affected by configuration options such as
+  CONFIG_SMP or CONFIG_HOTPLUG, make sure it compiles for all configuration
+  variants.
+
+
+2. Adding functionality to existing drivers
+-------------------------------------------
+
+* Make sure the documentation in Documentation/hwmon/<driver_name> is up to
+  date.
+
+* Make sure the information in Kconfig is up to date.
+
+* If the added functionality requires some cleanup or structural changes, split
+  your patch into a cleanup part and the actual addition. This makes it easier
+  to review your changes, and to bisect any resulting problems.
+
+* Never mix bug fixes, cleanup, and functional enhancements in a single patch.
+
+
+3. New drivers
+--------------
+
+* Running your patch or driver file(s) through checkpatch does not mean its
+  formatting is clean. If unsure about formatting in your new driver, run it
+  through Lindent. Lindent is not perfect, and you may have to do some minor
+  cleanup, but it is a good start.
+
+* Consider adding yourself to MAINTAINERS.
+
+* Document the driver in Documentation/hwmon/<driver_name>.
+
+* Add the driver to Kconfig and Makefile in alphabetical order.
+
+* Make sure that all dependencies are listed in Kconfig. For new drivers, it
+  is most likely prudent to add a dependency on EXPERIMENTAL.
+
+* Avoid forward declarations if you can. Rearrange the code if necessary.
+
+* Avoid calculations in macros and macro-generated functions. While such macros
+  may save a line or so in the source, it obfuscates the code and makes code
+  review more difficult. It may also result in code which is more complicated
+  than necessary. Use inline functions or just regular functions instead.
+
+* If the driver has a detect function, make sure it is silent. Debug messages
+  and messages printed after a successful detection are acceptable, but it
+  must not print messages such as "Chip XXX not found/supported".
+
+  Keep in mind that the detect function will run for all drivers supporting an
+  address if a chip is detected on that address. Unnecessary messages will just
+  pollute the kernel log and not provide any value.
+
+* Provide a detect function if and only if a chip can be detected reliably.
+
+* Avoid writing to chip registers in the detect function. If you have to write,
+  only do it after you have already gathered enough data to be certain that the
+  detection is going to be successful.
+
+  Keep in mind that the chip might not be what your driver believes it is, and
+  writing to it might cause a bad misconfiguration.
+
+* Make sure there are no race conditions in the probe function. Specifically,
+  completely initialize your chip first, then create sysfs entries and register
+  with the hwmon subsystem.
+
+* Do not provide support for deprecated sysfs attributes.
+
+* Do not create non-standard attributes unless really needed. If you have to use
+  non-standard attributes, or you believe you do, discuss it on the mailing list
+  first. Either case, provide a detailed explanation why you need the
+  non-standard attribute(s).
+  Standard attributes are specified in Documentation/hwmon/sysfs-interface.
+
+* When deciding which sysfs attributes to support, look at the chip's
+  capabilities. While we do not expect your driver to support everything the
+  chip may offer, it should at least support all limits and alarms.
+
+* Last but not least, please check if a driver for your chip already exists
+  before starting to write a new driver. Especially for temperature sensors,
+  new chips are often variants of previously released chips. In some cases,
+  a presumably new chip may simply have been relabeled.
diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt
new file mode 100644 (file)
index 0000000..23fcb05
--- /dev/null
@@ -0,0 +1,262 @@
+The input protocol uses a map of types and codes to express input device values
+to userspace. This document describes the types and codes and how and when they
+may be used.
+
+A single hardware event generates multiple input events. Each input event
+contains the new value of a single data item. A special event type, EV_SYN, is
+used to separate input events into packets of input data changes occurring at
+the same moment in time. In the following, the term "event" refers to a single
+input event encompassing a type, code, and value.
+
+The input protocol is a stateful protocol. Events are emitted only when values
+of event codes have changed. However, the state is maintained within the Linux
+input subsystem; drivers do not need to maintain the state and may attempt to
+emit unchanged values without harm. Userspace may obtain the current state of
+event code values using the EVIOCG* ioctls defined in linux/input.h. The event
+reports supported by a device are also provided by sysfs in
+class/input/event*/device/capabilities/, and the properties of a device are
+provided in class/input/event*/device/properties.
+
+Types:
+==========
+Types are groupings of codes under a logical input construct. Each type has a
+set of applicable codes to be used in generating events. See the Codes section
+for details on valid codes for each type.
+
+* EV_SYN:
+  - Used as markers to separate events. Events may be separated in time or in
+    space, such as with the multitouch protocol.
+
+* EV_KEY:
+  - Used to describe state changes of keyboards, buttons, or other key-like
+    devices.
+
+* EV_REL:
+  - Used to describe relative axis value changes, e.g. moving the mouse 5 units
+    to the left.
+
+* EV_ABS:
+  - Used to describe absolute axis value changes, e.g. describing the
+    coordinates of a touch on a touchscreen.
+
+* EV_MSC:
+  - Used to describe miscellaneous input data that do not fit into other types.
+
+* EV_SW:
+  - Used to describe binary state input switches.
+
+* EV_LED:
+  - Used to turn LEDs on devices on and off.
+
+* EV_SND:
+  - Used to output sound to devices.
+
+* EV_REP:
+  - Used for autorepeating devices.
+
+* EV_FF:
+  - Used to send force feedback commands to an input device.
+
+* EV_PWR:
+  - A special type for power button and switch input.
+
+* EV_FF_STATUS:
+  - Used to receive force feedback device status.
+
+Codes:
+==========
+Codes define the precise type of event.
+
+EV_SYN:
+----------
+EV_SYN event values are undefined. Their usage is defined only by when they are
+sent in the evdev event stream.
+
+* SYN_REPORT:
+  - Used to synchronize and separate events into packets of input data changes
+    occurring at the same moment in time. For example, motion of a mouse may set
+    the REL_X and REL_Y values for one motion, then emit a SYN_REPORT. The next
+    motion will emit more REL_X and REL_Y values and send another SYN_REPORT.
+
+* SYN_CONFIG:
+  - TBD
+
+* SYN_MT_REPORT:
+  - Used to synchronize and separate touch events. See the
+    multi-touch-protocol.txt document for more information.
+
+* SYN_DROPPED:
+  - Used to indicate buffer overrun in the evdev client's event queue.
+    Client should ignore all events up to and including next SYN_REPORT
+    event and query the device (using EVIOCG* ioctls) to obtain its
+    current state.
+
+EV_KEY:
+----------
+EV_KEY events take the form KEY_<name> or BTN_<name>. For example, KEY_A is used
+to represent the 'A' key on a keyboard. When a key is depressed, an event with
+the key's code is emitted with value 1. When the key is released, an event is
+emitted with value 0. Some hardware send events when a key is repeated. These
+events have a value of 2. In general, KEY_<name> is used for keyboard keys, and
+BTN_<name> is used for other types of momentary switch events.
+
+A few EV_KEY codes have special meanings:
+
+* BTN_TOOL_<name>:
+  - These codes are used in conjunction with input trackpads, tablets, and
+    touchscreens. These devices may be used with fingers, pens, or other tools.
+    When an event occurs and a tool is used, the corresponding BTN_TOOL_<name>
+    code should be set to a value of 1. When the tool is no longer interacting
+    with the input device, the BTN_TOOL_<name> code should be reset to 0. All
+    trackpads, tablets, and touchscreens should use at least one BTN_TOOL_<name>
+    code when events are generated.
+
+* BTN_TOUCH:
+    BTN_TOUCH is used for touch contact. While an input tool is determined to be
+    within meaningful physical contact, the value of this property must be set
+    to 1. Meaningful physical contact may mean any contact, or it may mean
+    contact conditioned by an implementation defined property. For example, a
+    touchpad may set the value to 1 only when the touch pressure rises above a
+    certain value. BTN_TOUCH may be combined with BTN_TOOL_<name> codes. For
+    example, a pen tablet may set BTN_TOOL_PEN to 1 and BTN_TOUCH to 0 while the
+    pen is hovering over but not touching the tablet surface.
+
+Note: For appropriate function of the legacy mousedev emulation driver,
+BTN_TOUCH must be the first evdev code emitted in a synchronization frame.
+
+Note: Historically a touch device with BTN_TOOL_FINGER and BTN_TOUCH was
+interpreted as a touchpad by userspace, while a similar device without
+BTN_TOOL_FINGER was interpreted as a touchscreen. For backwards compatibility
+with current userspace it is recommended to follow this distinction. In the
+future, this distinction will be deprecated and the device properties ioctl
+EVIOCGPROP, defined in linux/input.h, will be used to convey the device type.
+
+* BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP:
+  - These codes denote one, two, three, and four finger interaction on a
+    trackpad or touchscreen. For example, if the user uses two fingers and moves
+    them on the touchpad in an effort to scroll content on screen,
+    BTN_TOOL_DOUBLETAP should be set to value 1 for the duration of the motion.
+    Note that all BTN_TOOL_<name> codes and the BTN_TOUCH code are orthogonal in
+    purpose. A trackpad event generated by finger touches should generate events
+    for one code from each group. At most only one of these BTN_TOOL_<name>
+    codes should have a value of 1 during any synchronization frame.
+
+Note: Historically some drivers emitted multiple of the finger count codes with
+a value of 1 in the same synchronization frame. This usage is deprecated.
+
+Note: In multitouch drivers, the input_mt_report_finger_count() function should
+be used to emit these codes. Please see multi-touch-protocol.txt for details.
+
+EV_REL:
+----------
+EV_REL events describe relative changes in a property. For example, a mouse may
+move to the left by a certain number of units, but its absolute position in
+space is unknown. If the absolute position is known, EV_ABS codes should be used
+instead of EV_REL codes.
+
+A few EV_REL codes have special meanings:
+
+* REL_WHEEL, REL_HWHEEL:
+  - These codes are used for vertical and horizontal scroll wheels,
+    respectively.
+
+EV_ABS:
+----------
+EV_ABS events describe absolute changes in a property. For example, a touchpad
+may emit coordinates for a touch location.
+
+A few EV_ABS codes have special meanings:
+
+* ABS_DISTANCE:
+  - Used to describe the distance of a tool from an interaction surface. This
+    event should only be emitted while the tool is hovering, meaning in close
+    proximity of the device and while the value of the BTN_TOUCH code is 0. If
+    the input device may be used freely in three dimensions, consider ABS_Z
+    instead.
+
+* ABS_MT_<name>:
+  - Used to describe multitouch input events. Please see
+    multi-touch-protocol.txt for details.
+
+EV_SW:
+----------
+EV_SW events describe stateful binary switches. For example, the SW_LID code is
+used to denote when a laptop lid is closed.
+
+Upon binding to a device or resuming from suspend, a driver must report
+the current switch state. This ensures that the device, kernel, and userspace
+state is in sync.
+
+Upon resume, if the switch state is the same as before suspend, then the input
+subsystem will filter out the duplicate switch state reports. The driver does
+not need to keep the state of the switch at any time.
+
+EV_MSC:
+----------
+EV_MSC events are used for input and output events that do not fall under other
+categories.
+
+EV_LED:
+----------
+EV_LED events are used for input and output to set and query the state of
+various LEDs on devices.
+
+EV_REP:
+----------
+EV_REP events are used for specifying autorepeating events.
+
+EV_SND:
+----------
+EV_SND events are used for sending sound commands to simple sound output
+devices.
+
+EV_FF:
+----------
+EV_FF events are used to initialize a force feedback capable device and to cause
+such device to feedback.
+
+EV_PWR:
+----------
+EV_PWR events are a special type of event used specifically for power
+mangement. Its usage is not well defined. To be addressed later.
+
+Guidelines:
+==========
+The guidelines below ensure proper single-touch and multi-finger functionality.
+For multi-touch functionality, see the multi-touch-protocol.txt document for
+more information.
+
+Mice:
+----------
+REL_{X,Y} must be reported when the mouse moves. BTN_LEFT must be used to report
+the primary button press. BTN_{MIDDLE,RIGHT,4,5,etc.} should be used to report
+further buttons of the device. REL_WHEEL and REL_HWHEEL should be used to report
+scroll wheel events where available.
+
+Touchscreens:
+----------
+ABS_{X,Y} must be reported with the location of the touch. BTN_TOUCH must be
+used to report when a touch is active on the screen.
+BTN_{MOUSE,LEFT,MIDDLE,RIGHT} must not be reported as the result of touch
+contact. BTN_TOOL_<name> events should be reported where possible.
+
+Trackpads:
+----------
+Legacy trackpads that only provide relative position information must report
+events like mice described above.
+
+Trackpads that provide absolute touch position must report ABS_{X,Y} for the
+location of the touch. BTN_TOUCH should be used to report when a touch is active
+on the trackpad. Where multi-finger support is available, BTN_TOOL_<name> should
+be used to report the number of touches active on the trackpad.
+
+Tablets:
+----------
+BTN_TOOL_<name> events must be reported when a stylus or other tool is active on
+the tablet. ABS_{X,Y} must be reported with the location of the tool. BTN_TOUCH
+should be used to report when the tool is in contact with the tablet.
+BTN_{STYLUS,STYLUS2} should be used to report buttons on the tool itself. Any
+button may be used for buttons on the tablet except BTN_{MOUSE,LEFT}.
+BTN_{0,1,2,etc} are good generic codes for unlabeled buttons. Do not use
+meaningful buttons, like BTN_FORWARD, unless the button is labeled for that
+purpose on the device.
index a81c7b4790f2177afb7ad1911dbc20a5128ad7eb..2366b1c8cf19492f52480669449ecd2b0a0d0f34 100644 (file)
@@ -552,6 +552,16 @@ also have
      within the array where IO will be blocked.  This is currently
      only supported for raid4/5/6.
 
+   sync_min
+   sync_max
+     The two values, given as numbers of sectors, indicate a range
+     withing the array where 'check'/'repair' will operate. Must be
+     a multiple of chunk_size. When it reaches "sync_max" it will
+     pause, rather than complete.
+     You can use 'select' or 'poll' on "sync_completed" to wait for
+     that number to reach sync_max.  Then you can either increase
+     "sync_max", or can write 'idle' to "sync_action".
+
 
 Each active md device may also have attributes specific to the
 personality module that manages it.
index 9822afb6313cb1a56d5fdec722c62847cb98ce87..89757012c7ffda2d1babfd1dd9bc9d7e4d1604eb 100644 (file)
@@ -1230,6 +1230,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     This module supports multiple cards.
     The driver requires the firmware loader support on kernel.
 
+  Module snd-lola
+  ---------------
+
+    Module for Digigram Lola PCI-e boards
+
+    This module supports multiple cards.
+
   Module snd-lx6464es
   -------------------
 
index cb47e723af7436defbc6db5007bdf2fd3f675414..1e96ce6e2d2f9d39705c8a79e60b95bcc6cc9082 100644 (file)
@@ -37,7 +37,7 @@ Generic scaling / cropping scheme
 -1'-
 
 In the above chart minuses and slashes represent "real" data amounts, points and
-accents represent "useful" data, basically, CEU scaled amd cropped output,
+accents represent "useful" data, basically, CEU scaled and cropped output,
 mapped back onto the client's source plane.
 
 Such a configuration can be produced by user requests:
@@ -65,7 +65,7 @@ Do not touch input rectangle - it is already optimal.
 
 1. Calculate current sensor scales:
 
-       scale_s = ((3') - (3)) / ((2') - (2))
+       scale_s = ((2') - (2)) / ((3') - (3))
 
 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
 current sensor scales onto input window - this is user S_CROP:
@@ -80,7 +80,7 @@ window:
 4. Calculate sensor output window by applying combined scales to real input
 window:
 
-       width_s_out = ((2') - (2)) / scale_comb
+       width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb
 
 5. Apply iterative sensor S_FMT for sensor output window.
 
index 01c513fac40ece66b73a1709f6df496b5aade8d2..a0b577de918f7cd3fcdec46f06b72f7de074d6d8 100644 (file)
@@ -12,6 +12,7 @@ CONTENTS
 4. Application Programming Interface (API)
 5. Example Execution Scenarios
 6. Guidelines
+7. Debugging
 
 
 1. Introduction
@@ -379,3 +380,42 @@ If q1 has WQ_CPU_INTENSIVE set,
 * Unless work items are expected to consume a huge amount of CPU
   cycles, using a bound wq is usually beneficial due to the increased
   level of locality in wq operations and work item execution.
+
+
+7. Debugging
+
+Because the work functions are executed by generic worker threads
+there are a few tricks needed to shed some light on misbehaving
+workqueue users.
+
+Worker threads show up in the process list as:
+
+root      5671  0.0  0.0      0     0 ?        S    12:07   0:00 [kworker/0:1]
+root      5672  0.0  0.0      0     0 ?        S    12:07   0:00 [kworker/1:2]
+root      5673  0.0  0.0      0     0 ?        S    12:12   0:00 [kworker/0:0]
+root      5674  0.0  0.0      0     0 ?        S    12:13   0:00 [kworker/1:0]
+
+If kworkers are going crazy (using too much cpu), there are two types
+of possible problems:
+
+       1. Something beeing scheduled in rapid succession
+       2. A single work item that consumes lots of cpu cycles
+
+The first one can be tracked using tracing:
+
+       $ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event
+       $ cat /sys/kernel/debug/tracing/trace_pipe > out.txt
+       (wait a few secs)
+       ^C
+
+If something is busy looping on work queueing, it would be dominating
+the output and the offender can be determined with the work item
+function.
+
+For the second type of problems it should be possible to just check
+the stack trace of the offending worker thread.
+
+       $ cat /proc/THE_OFFENDING_KWORKER/stack
+
+The work item's function should be trivially visible in the stack
+trace.
index 9f926c0229db3bd76ed0b5982b31398ade6a0868..6e645474654037ed42abcb8c399bcb50a44f3e1c 100644 (file)
@@ -151,6 +151,7 @@ S:  Maintained
 F:     drivers/net/hamradio/6pack.c
 
 8169 10/100/1000 GIGABIT ETHERNET DRIVER
+M:     Realtek linux nic maintainers <nic_swsd@realtek.com>
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
@@ -184,10 +185,9 @@ F: Documentation/filesystems/9p.txt
 F:     fs/9p/
 
 A2232 SERIAL BOARD DRIVER
-M:     Enver Haase <A2232@gmx.net>
 L:     linux-m68k@lists.linux-m68k.org
-S:     Maintained
-F:     drivers/char/ser_a2232*
+S:     Orphan
+F:     drivers/staging/generic_serial/ser_a2232*
 
 AACRAID SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@adaptec.com>
@@ -877,6 +877,13 @@ F: arch/arm/mach-mv78xx0/
 F:     arch/arm/mach-orion5x/
 F:     arch/arm/plat-orion/
 
+ARM/Orion SoC/Technologic Systems TS-78xx platform support
+M:     Alexander Clouter <alex@digriz.org.uk>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W:     http://www.digriz.org.uk/ts78xx/kernel
+S:     Maintained
+F:     arch/arm/mach-orion5x/ts78xx-*
+
 ARM/MIOA701 MACHINE SUPPORT
 M:     Robert Jarzmik <robert.jarzmik@free.fr>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1025,12 +1032,13 @@ W:      http://www.fluff.org/ben/linux/
 S:     Maintained
 F:     arch/arm/mach-s3c64xx/
 
-ARM/S5P ARM ARCHITECTURES
+ARM/S5P EXYNOS ARM ARCHITECTURES
 M:     Kukjin Kim <kgene.kim@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-s5p*/
+F:     arch/arm/mach-exynos*/
 
 ARM/SAMSUNG MOBILE MACHINE SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -1063,7 +1071,7 @@ F:        arch/arm/mach-shmobile/
 F:     drivers/sh/
 
 ARM/TELECHIPS ARM ARCHITECTURE
-M:     "Hans J. Koch" <hjk@linutronix.de>
+M:     "Hans J. Koch" <hjk@hansjkoch.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/plat-tcc/
@@ -1823,11 +1831,10 @@ S:      Maintained
 F:     drivers/platform/x86/compal-laptop.c
 
 COMPUTONE INTELLIPORT MULTIPORT CARD
-M:     "Michael H. Warfield" <mhw@wittsend.com>
 W:     http://www.wittsend.com/computone.html
-S:     Maintained
+S:     Orphan
 F:     Documentation/serial/computone.txt
-F:     drivers/char/ip2/
+F:     drivers/staging/tty/ip2/
 
 CONEXANT ACCESSRUNNER USB DRIVER
 M:     Simon Arlott <cxacru@fire.lp0.eu>
@@ -2010,7 +2017,7 @@ F:        drivers/net/wan/cycx*
 CYCLADES ASYNC MUX DRIVER
 W:     http://www.cyclades.com/
 S:     Orphan
-F:     drivers/char/cyclades.c
+F:     drivers/tty/cyclades.c
 F:     include/linux/cyclades.h
 
 CYCLADES PC300 DRIVER
@@ -2124,8 +2131,8 @@ L:        Eng.Linux@digi.com
 W:     http://www.digi.com
 S:     Orphan
 F:     Documentation/serial/digiepca.txt
-F:     drivers/char/epca*
-F:     drivers/char/digi*
+F:     drivers/staging/tty/epca*
+F:     drivers/staging/tty/digi*
 
 DIOLAN U2C-12 I2C DRIVER
 M:     Guenter Roeck <guenter.roeck@ericsson.com>
@@ -2802,7 +2809,7 @@ GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
 S:     Maintained
 T:     git git://git.secretlab.ca/git/linux-2.6.git
-F:     Documentation/gpio/gpio.txt
+F:     Documentation/gpio.txt
 F:     drivers/gpio/
 F:     include/linux/gpio*
 
@@ -4077,7 +4084,7 @@ F:        drivers/video/matrox/matroxfb_*
 F:     include/linux/matroxfb.h
 
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
-M:     "Hans J. Koch" <hjk@linutronix.de>
+M:     "Hans J. Koch" <hjk@hansjkoch.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/max6650
@@ -4192,7 +4199,7 @@ MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
 F:     Documentation/serial/moxa-smartio
-F:     drivers/char/mxser.*
+F:     drivers/tty/mxser.*
 
 MSI LAPTOP SUPPORT
 M:     "Lee, Chun-Yi" <jlee@novell.com>
@@ -4234,7 +4241,7 @@ F:        sound/oss/msnd*
 
 MULTITECH MULTIPORT CARD (ISICOM)
 S:     Orphan
-F:     drivers/char/isicom.c
+F:     drivers/tty/isicom.c
 F:     include/linux/isicom.h
 
 MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
@@ -4257,6 +4264,13 @@ M:       Tim Hockin <thockin@hockin.org>
 S:     Maintained
 F:     drivers/net/natsemi.c
 
+NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
+M:     Daniel Mack <zonque@gmail.com>
+S:     Maintained
+L:     alsa-devel@alsa-project.org
+W:     http://www.native-instruments.com
+F:     sound/usb/caiaq/
+
 NCP FILESYSTEM
 M:     Petr Vandrovec <petr@vandrovec.name>
 S:     Odd Fixes
@@ -5273,14 +5287,14 @@ F:      drivers/memstick/host/r592.*
 RISCOM8 DRIVER
 S:     Orphan
 F:     Documentation/serial/riscom8.txt
-F:     drivers/char/riscom8*
+F:     drivers/staging/tty/riscom8*
 
 ROCKETPORT DRIVER
 P:     Comtrol Corp.
 W:     http://www.comtrol.com
 S:     Maintained
 F:     Documentation/serial/rocket.txt
-F:     drivers/char/rocket*
+F:     drivers/tty/rocket*
 
 ROSE NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
@@ -5840,7 +5854,7 @@ F:        include/sound/
 F:     sound/
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M:     Liam Girdwood <lrg@slimlogic.co.uk>
+M:     Liam Girdwood <lrg@ti.com>
 M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -5916,10 +5930,9 @@ F:       arch/arm/mach-spear6xx/spear600.c
 F:     arch/arm/mach-spear6xx/spear600_evb.c
 
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
-M:     Roger Wolff <R.E.Wolff@BitWizard.nl>
-S:     Supported
+S:     Orphan
 F:     Documentation/serial/specialix.txt
-F:     drivers/char/specialix*
+F:     drivers/staging/tty/specialix*
 
 SPI SUBSYSTEM
 M:     David Brownell <dbrownell@users.sourceforge.net>
@@ -5964,7 +5977,6 @@ F:        arch/alpha/kernel/srm_env.c
 
 STABLE BRANCH
 M:     Greg Kroah-Hartman <greg@kroah.com>
-M:     Chris Wright <chrisw@sous-sol.org>
 L:     stable@kernel.org
 S:     Maintained
 
@@ -6093,7 +6105,7 @@ F:        drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
 TI TWL4030 SERIES SOC CODEC DRIVER
-M:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/soc/codecs/twl4030*
@@ -6248,7 +6260,8 @@ M:        Greg Ungerer <gerg@uclinux.org>
 W:     http://www.uclinux.org/
 L:     uclinux-dev@uclinux.org  (subscribers-only)
 S:     Maintained
-F:     arch/m68knommu/
+F:     arch/m68k/*/*_no.*
+F:     arch/m68k/include/asm/*_no.*
 
 UCLINUX FOR RENESAS H8/300 (H8300)
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
@@ -6550,7 +6563,7 @@ S:        Maintained
 F:     drivers/usb/host/uhci*
 
 USB "USBNET" DRIVER FRAMEWORK
-M:     David Brownell <dbrownell@users.sourceforge.net>
+M:     Oliver Neukum <oneukum@suse.de>
 L:     netdev@vger.kernel.org
 W:     http://www.linux-usb.org/usbnet
 S:     Maintained
@@ -6618,7 +6631,7 @@ F:        fs/hostfs/
 F:     fs/hppfs/
 
 USERSPACE I/O (UIO)
-M:     "Hans J. Koch" <hjk@linutronix.de>
+M:     "Hans J. Koch" <hjk@hansjkoch.de>
 M:     Greg Kroah-Hartman <gregkh@suse.de>
 S:     Maintained
 F:     Documentation/DocBook/uio-howto.tmpl
@@ -6736,7 +6749,7 @@ F:        drivers/scsi/vmw_pvscsi.c
 F:     drivers/scsi/vmw_pvscsi.h
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-M:     Liam Girdwood <lrg@slimlogic.co.uk>
+M:     Liam Girdwood <lrg@ti.com>
 M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
 W:     http://opensource.wolfsonmicro.com/node/15
 W:     http://www.slimlogic.co.uk/?p=48
@@ -6916,6 +6929,18 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.
 S:     Maintained
 F:     drivers/platform/x86
 
+XEN HYPERVISOR INTERFACE
+M:     Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:     virtualization@lists.linux-foundation.org
+S:     Supported
+F:     arch/x86/xen/
+F:     drivers/*/xen-*front.c
+F:     drivers/xen/
+F:     arch/x86/include/asm/xen/
+F:     include/xen/
+
 XEN NETWORK BACKEND DRIVER
 M:     Ian Campbell <ian.campbell@citrix.com>
 L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
@@ -6937,18 +6962,6 @@ S:       Supported
 F:     arch/x86/xen/*swiotlb*
 F:     drivers/xen/*swiotlb*
 
-XEN HYPERVISOR INTERFACE
-M:     Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
-M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
-L:     virtualization@lists.linux-foundation.org
-S:     Supported
-F:     arch/x86/xen/
-F:     drivers/*/xen-*front.c
-F:     drivers/xen/
-F:     arch/x86/include/asm/xen/
-F:     include/xen/
-
 XFS FILESYSTEM
 P:     Silicon Graphics Inc
 M:     Alex Elder <aelder@sgi.com>
index 322e7334ccb9a5d97a9fe59b46e738df87c42220..41ea6fbec55a1edcdcd697510afcc417578b057c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 39
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc7
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index 9bb7b858ed239ef4e590732a75fe250bbf934eaf..7a6d908bb865c2e83a5cc51dcd975830f8cdfc4a 100644 (file)
@@ -4,7 +4,7 @@
 
 extra-y                := head.o vmlinux.lds
 asflags-y      := $(KBUILD_CFLAGS)
-ccflags-y      := -Werror -Wno-sign-compare
+ccflags-y      := -Wno-sign-compare
 
 obj-y    := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
            irq_alpha.o signal.o setup.o ptrace.o time.o \
index 381fec0af52e35a6262586059ccdacbcfd863148..da7bcc372f16c50f6cc3f048b6a6956df748aec4 100644 (file)
@@ -88,7 +88,7 @@ conf_read(unsigned long addr, unsigned char type1,
 {
        unsigned long flags;
        unsigned long mid = MCPCIA_HOSE2MID(hose->index);
-       unsigned int stat0, value, temp, cpu;
+       unsigned int stat0, value, cpu;
 
        cpu = smp_processor_id();
 
@@ -101,7 +101,7 @@ conf_read(unsigned long addr, unsigned char type1,
        stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
        *(vuip)MCPCIA_CAP_ERR(mid) = stat0;
        mb();
-       temp = *(vuip)MCPCIA_CAP_ERR(mid);
+       *(vuip)MCPCIA_CAP_ERR(mid);
        DBG_CFG(("conf_read: MCPCIA_CAP_ERR(%d) was 0x%x\n", mid, stat0));
 
        mb();
@@ -136,7 +136,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1,
 {
        unsigned long flags;
        unsigned long mid = MCPCIA_HOSE2MID(hose->index);
-       unsigned int stat0, temp, cpu;
+       unsigned int stat0, cpu;
 
        cpu = smp_processor_id();
 
@@ -145,7 +145,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1,
        /* Reset status register to avoid losing errors.  */
        stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
        *(vuip)MCPCIA_CAP_ERR(mid) = stat0; mb();
-       temp = *(vuip)MCPCIA_CAP_ERR(mid);
+       *(vuip)MCPCIA_CAP_ERR(mid);
        DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", mid, stat0));
 
        draina();
@@ -157,7 +157,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1,
        *((vuip)addr) = value;
        mb();
        mb();  /* magic */
-       temp = *(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */
+       *(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */
        mcheck_expected(cpu) = 0;
        mb();
 
@@ -572,12 +572,10 @@ mcpcia_print_system_area(unsigned long la_ptr)
 void
 mcpcia_machine_check(unsigned long vector, unsigned long la_ptr)
 {
-       struct el_common *mchk_header;
        struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
        unsigned int cpu = smp_processor_id();
        int expected;
 
-       mchk_header = (struct el_common *)la_ptr;
        mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
        expected = mcheck_expected(cpu);
 
index c3b3781a03de01045ebd270319173ae2b5d347ee..14b26c466c8996cc1e4f7e03ff4391bcbb2bc3c8 100644 (file)
@@ -533,8 +533,6 @@ static struct el_subpacket_annotation el_titan_annotations[] = {
 static struct el_subpacket *
 el_process_regatta_subpacket(struct el_subpacket *header)
 {
-       int status;
-
        if (header->class != EL_CLASS__REGATTA_FAMILY) {
                printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
                       err_print_prefix,
@@ -551,7 +549,7 @@ el_process_regatta_subpacket(struct el_subpacket *header)
                printk("%s  ** Occurred on CPU %d:\n", 
                       err_print_prefix,
                       (int)header->by_type.regatta_frame.cpuid);
-               status = privateer_process_logout_frame((struct el_common *)
+               privateer_process_logout_frame((struct el_common *)
                        header->by_type.regatta_frame.data_start, 1);
                break;
        default:
index 1479dc6ebd97a4288ee6d0dd0334ea17dbf02049..51b7fbd9e4c11406ce8950f6cecc64f1ebd7556a 100644 (file)
@@ -228,7 +228,7 @@ struct irqaction timer_irqaction = {
 void __init
 init_rtc_irq(void)
 {
-       irq_set_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
+       irq_set_chip_and_handler_name(RTC_IRQ, &dummy_irq_chip,
                                      handle_simple_irq, "RTC");
        setup_irq(RTC_IRQ, &timer_irqaction);
 }
index d2634e4476b4589f03831f575ec00751b0434ca9..edbddcbd5bc654692fbfc98572ed8277303d49db 100644 (file)
@@ -1404,8 +1404,6 @@ determine_cpu_caches (unsigned int cpu_type)
        case PCA56_CPU:
        case PCA57_CPU:
          {
-               unsigned long cbox_config, size;
-
                if (cpu_type == PCA56_CPU) {
                        L1I = CSHAPE(16*1024, 6, 1);
                        L1D = CSHAPE(8*1024, 5, 1);
@@ -1415,10 +1413,12 @@ determine_cpu_caches (unsigned int cpu_type)
                }
                L3 = -1;
 
+#if 0
+               unsigned long cbox_config, size;
+
                cbox_config = *(vulp) phys_to_virt (0xfffff00008UL);
                size = 512*1024 * (1 << ((cbox_config >> 12) & 3));
 
-#if 0
                L2 = ((cbox_config >> 31) & 1 ? CSHAPE (size, 6, 1) : -1);
 #else
                L2 = external_cache_probe(512*1024, 6);
index 3e6a2893af9f6e87122ca0e872ec95282cdf3fde..6886b834f4871f54c6eb6fd7a232a20ca12d0d0b 100644 (file)
@@ -79,7 +79,6 @@
 static unsigned long __init SMCConfigState(unsigned long baseAddr)
 {
        unsigned char devId;
-       unsigned char devRev;
 
        unsigned long configPort;
        unsigned long indexPort;
@@ -100,7 +99,7 @@ static unsigned long __init SMCConfigState(unsigned long baseAddr)
                devId = inb(dataPort);
                if (devId == VALID_DEVICE_ID) {
                        outb(DEVICE_REV, indexPort);
-                       devRev = inb(dataPort);
+                       /* unsigned char devRev = */ inb(dataPort);
                        break;
                }
                else
index d3cb28bb8eb0e450fcd4298698b944264d7b1fc0..d92cdc715c6530150563259e6fbc4c859f3e1d9f 100644 (file)
@@ -156,7 +156,6 @@ static void __init
 wildfire_init_irq_per_pca(int qbbno, int pcano)
 {
        int i, irq_bias;
-       unsigned long io_bias;
        static struct irqaction isa_enable = {
                .handler        = no_action,
                .name           = "isa_enable",
@@ -165,10 +164,12 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
        irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA)
                 + pcano * WILDFIRE_IRQ_PER_PCA;
 
+#if 0
+       unsigned long io_bias;
+
        /* Only need the following for first PCI bus per PCA. */
        io_bias = WILDFIRE_IO(qbbno, pcano<<1) - WILDFIRE_IO_BIAS;
 
-#if 0
        outb(0, DMA1_RESET_REG + io_bias);
        outb(0, DMA2_RESET_REG + io_bias);
        outb(DMA_MODE_CASCADE, DMA2_MODE_REG + io_bias);
index a58e84f1a63b76cc3e96856d10736a1c03ba6872..918e8e0b72ff1e3220845ea410277a83ff326517 100644 (file)
@@ -153,6 +153,7 @@ void read_persistent_clock(struct timespec *ts)
                year += 100;
 
        ts->tv_sec = mktime(year, mon, day, hour, min, sec);
+       ts->tv_nsec = 0;
 }
 
 
index fdc9d4dbf85b528fb70614f5ff1a199504a3df75..377a7a595b08041fdacb1dfd43d8be206578bda8 100644 (file)
@@ -1540,7 +1540,6 @@ config HIGHMEM
 config HIGHPTE
        bool "Allocate 2nd-level pagetables from highmem"
        depends on HIGHMEM
-       depends on !OUTER_CACHE
 
 config HW_PERF_EVENTS
        bool "Enable hardware performance counter support for perf events"
@@ -2012,6 +2011,8 @@ source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
        depends on !ARCH_S5P64X0 && !ARCH_S5P6442
+       depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
+               CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
        def_bool y
 
 endmenu
index 494224a9b459060f94f39aafeeae8389111d50a0..03d01d783e3bf95c72f28259aad1550b97c5cc68 100644 (file)
@@ -63,17 +63,6 @@ config DEBUG_USER
              8 - SIGSEGV faults
             16 - SIGBUS faults
 
-config DEBUG_ERRORS
-       bool "Verbose kernel error messages"
-       depends on DEBUG_KERNEL
-       help
-         This option controls verbose debugging information which can be
-         printed when the kernel detects an internal error. This debugging
-         information is useful to kernel hackers when tracking down problems,
-         but mostly meaningless to other people. It's safe to say Y unless
-         you are concerned with the code size or don't want to see these
-         messages.
-
 config DEBUG_STACK_USAGE
        bool "Enable stack utilization instrumentation"
        depends on DEBUG_KERNEL
index e7521bca2c3564eaf3d21663fbf4ae3721e43461..6ea9b6f3607af35121e2e117e1580b1d841b520d 100644 (file)
@@ -16,5 +16,4 @@ obj-$(CONFIG_SHARP_SCOOP)     += scoop.o
 obj-$(CONFIG_ARCH_IXP2000)     += uengine.o
 obj-$(CONFIG_ARCH_IXP23XX)     += uengine.o
 obj-$(CONFIG_PCI_HOST_ITE8152)  += it8152.o
-obj-$(CONFIG_COMMON_CLKDEV)    += clkdev.o
 obj-$(CONFIG_ARM_TIMER_SP804)  += timer-sp.o
diff --git a/arch/arm/configs/at91x40_defconfig b/arch/arm/configs/at91x40_defconfig
new file mode 100644 (file)
index 0000000..c55e921
--- /dev/null
@@ -0,0 +1,48 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_EMBEDDED=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_FUTEX is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91X40=y
+CONFIG_MACH_AT91EB01=y
+CONFIG_AT91_EARLY_USART0=y
+CONFIG_CPU_ARM7TDMI=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x01000000
+CONFIG_DRAM_SIZE=0x00400000
+CONFIG_FLASH_MEM_BASE=0x01400000
+CONFIG_PROCESSOR_ID=0x14000040
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_BINFMT_FLAT=y
+# CONFIG_SUSPEND is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_ENABLE_MUST_CHECK is not set
index ed5bc9e05a4e176e0c86c89762afeb770efc998c..cd4458f64171e5e40720b991e8df5ad72099b0c5 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_ARM_CPUTYPE_H
 
 #include <linux/stringify.h>
+#include <linux/kernel.h>
 
 #define CPUID_ID       0
 #define CPUID_CACHETYPE        1
index bb8a19bd58225a3ce39bf39443cfd5b74b6409fd..e46bdd0097ebd9125f7382f76048d5fc20bbbb22 100644 (file)
@@ -39,10 +39,13 @@ typedef u32 kprobe_opcode_t;
 struct kprobe;
 typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
 
+typedef unsigned long (kprobe_check_cc)(unsigned long);
+
 /* Architecture specific copy of original instruction. */
 struct arch_specific_insn {
        kprobe_opcode_t         *insn;
        kprobe_insn_handler_t   *insn_handler;
+       kprobe_check_cc         *insn_check_cc;
 };
 
 struct prev_kprobe {
index c4391ba203507a2b1c34a9634ad6fb9c4ff7eb64..1dc98067589412a8ecc42e72e5b21a5f161b4f2a 100644 (file)
@@ -43,6 +43,7 @@ static inline void thread_notify(unsigned long rc, struct thread_info *thread)
 #define THREAD_NOTIFY_FLUSH    0
 #define THREAD_NOTIFY_EXIT     1
 #define THREAD_NOTIFY_SWITCH   2
+#define THREAD_NOTIFY_COPY     3
 
 #endif
 #endif
index c891eb76c0e313406847e7b9fbe968bb1b8fa459..87dbe3e21970c224391e4f2e29e08c34157821f7 100644 (file)
 #define __NR_fanotify_init             (__NR_SYSCALL_BASE+367)
 #define __NR_fanotify_mark             (__NR_SYSCALL_BASE+368)
 #define __NR_prlimit64                 (__NR_SYSCALL_BASE+369)
+#define __NR_name_to_handle_at         (__NR_SYSCALL_BASE+370)
+#define __NR_open_by_handle_at         (__NR_SYSCALL_BASE+371)
+#define __NR_clock_adjtime             (__NR_SYSCALL_BASE+372)
+#define __NR_syncfs                    (__NR_SYSCALL_BASE+373)
 
 /*
  * The following SWIs are ARM private.
index 74554f1742d72efd2c01a639e5fd0e3460221f94..8d95446150a3e7ed0ad8fd5782f7f918529bc3d7 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES)         += armksyms.o module.o
 obj-$(CONFIG_ARTHUR)           += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o isa.o
-obj-$(CONFIG_PM)               += sleep.o
+obj-$(CONFIG_PM_SLEEP)         += sleep.o
 obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
 obj-$(CONFIG_SMP)              += smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)     += smp_scu.o
index 5c26eccef9982665b1e1672416b9bc996f3b2dae..7fbf28c35bb2b438469894bb6bc80797fd8a3cf6 100644 (file)
                CALL(sys_fanotify_init)
                CALL(sys_fanotify_mark)
                CALL(sys_prlimit64)
+/* 370 */      CALL(sys_name_to_handle_at)
+               CALL(sys_open_by_handle_at)
+               CALL(sys_clock_adjtime)
+               CALL(sys_syncfs)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index d4a0da1e48f40988bb7f92ce34664d86adb74a32..9b05c6a0dceac54615e1dfa472bf28ca946616ac 100644 (file)
@@ -40,15 +40,22 @@ EXPORT_SYMBOL(elf_check_arch);
 void elf_set_personality(const struct elf32_hdr *x)
 {
        unsigned int eflags = x->e_flags;
-       unsigned int personality = PER_LINUX_32BIT;
+       unsigned int personality = current->personality & ~PER_MASK;
+
+       /*
+        * We only support Linux ELF executables, so always set the
+        * personality to LINUX.
+        */
+       personality |= PER_LINUX;
 
        /*
         * APCS-26 is only valid for OABI executables
         */
-       if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) {
-               if (eflags & EF_ARM_APCS_26)
-                       personality = PER_LINUX;
-       }
+       if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN &&
+           (eflags & EF_ARM_APCS_26))
+               personality &= ~ADDR_LIMIT_32BIT;
+       else
+               personality |= ADDR_LIMIT_32BIT;
 
        set_personality(personality);
 
index 8dbc126f7152d992472898a639801239d49a40ac..87acc25d7a3e203646f2ee71f1d7c711304d52f2 100644 (file)
@@ -868,6 +868,13 @@ static void reset_ctrl_regs(void *info)
                 */
                asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
                isb();
+
+               /*
+                * Clear any configured vector-catch events before
+                * enabling monitor mode.
+                */
+               asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0));
+               isb();
        }
 
        if (enable_monitor_mode())
index 23891317dc4be73d083f497291525feefaf015c6..15eeff6aea0e8185d9d4b7111da60afad3ea7967 100644 (file)
@@ -34,9 +34,6 @@
  *
  *   *) If the PC is written to by the instruction, the
  *      instruction must be fully simulated in software.
- *      If it is a conditional instruction, the handler
- *      will use insn[0] to copy its condition code to
- *     set r0 to 1 and insn[1] to "mov pc, lr" to return.
  *
  *   *) Otherwise, a modified form of the instruction is
  *      directly executed.  Its handler calls the
 
 #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
 
+#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos))
+
+/*
+ * Test if load/store instructions writeback the address register.
+ * if P (bit 24) == 0 or W (bit 21) == 1
+ */
+#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
+
 #define PSR_fs (PSR_f|PSR_s)
 
 #define KPROBE_RETURN_INSTRUCTION      0xe1a0f00e      /* mov pc, lr */
-#define SET_R0_TRUE_INSTRUCTION                0xe3a00001      /* mov  r0, #1 */
-
-#define        truecc_insn(insn)       (((insn) & 0xf0000000) | \
-                                (SET_R0_TRUE_INSTRUCTION & 0x0fffffff))
 
 typedef long (insn_0arg_fn_t)(void);
 typedef long (insn_1arg_fn_t)(long);
@@ -419,14 +420,10 @@ insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
 
 static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
        long iaddr = (long)p->addr;
        int disp  = branch_displacement(insn);
 
-       if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
-               return;
-
        if (insn & (1 << 24))
                regs->ARM_lr = iaddr + 4;
 
@@ -446,14 +443,10 @@ static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
 
 static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
        int rm = insn & 0xf;
        long rmv = regs->uregs[rm];
 
-       if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
-               return;
-
        if (insn & (1 << 5))
                regs->ARM_lr = (long)p->addr + 4;
 
@@ -463,9 +456,16 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
                regs->ARM_cpsr |= PSR_T_BIT;
 }
 
+static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       int rd = (insn >> 12) & 0xf;
+       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
+       regs->uregs[rd] = regs->ARM_cpsr & mask;
+}
+
 static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
        int rn = (insn >> 16) & 0xf;
        int lbit = insn & (1 << 20);
@@ -476,9 +476,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
        int reg_bit_vector;
        int reg_count;
 
-       if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
-               return;
-
        reg_count = 0;
        reg_bit_vector = insn & 0xffff;
        while (reg_bit_vector) {
@@ -510,11 +507,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
 
 static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
-
-       if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
-               return;
-
        regs->ARM_pc = (long)p->addr + str_pc_offset;
        simulate_ldm1stm1(p, regs);
        regs->ARM_pc = (long)p->addr + 4;
@@ -525,24 +517,16 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
        regs->uregs[12] = regs->uregs[13];
 }
 
-static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs)
-{
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
-       kprobe_opcode_t insn = p->opcode;
-       int rn = (insn >> 16) & 0xf;
-       long rnv = regs->uregs[rn];
-
-       /* Save Rn in case of writeback. */
-       regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
-}
-
 static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
 {
        insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
+       long ppc = (long)p->addr + 8;
        int rd = (insn >> 12) & 0xf;
        int rn = (insn >> 16) & 0xf;
        int rm = insn & 0xf;  /* rm may be invalid, don't care. */
+       long rmv = (rm == 15) ? ppc : regs->uregs[rm];
+       long rnv = (rn == 15) ? ppc : regs->uregs[rn];
 
        /* Not following the C calling convention here, so need asm(). */
        __asm__ __volatile__ (
@@ -554,29 +538,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
                "str    r0, %[rn]       \n\t"   /* in case of writeback */
                "str    r2, %[rd0]      \n\t"
                "str    r3, %[rd1]      \n\t"
-               : [rn]  "+m" (regs->uregs[rn]),
+               : [rn]  "+m" (rnv),
                  [rd0] "=m" (regs->uregs[rd]),
                  [rd1] "=m" (regs->uregs[rd+1])
-               : [rm]   "m" (regs->uregs[rm]),
+               : [rm]   "m" (rmv),
                  [cpsr] "r" (regs->ARM_cpsr),
                  [i_fn] "r" (i_fn)
                : "r0", "r1", "r2", "r3", "lr", "cc"
        );
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
 }
 
 static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
 {
        insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
+       long ppc = (long)p->addr + 8;
        int rd = (insn >> 12) & 0xf;
        int rn = (insn >> 16) & 0xf;
        int rm  = insn & 0xf;
-       long rnv = regs->uregs[rn];
-       long rmv = regs->uregs[rm];  /* rm/rmv may be invalid, don't care. */
+       long rnv = (rn == 15) ? ppc : regs->uregs[rn];
+       /* rm/rmv may be invalid, don't care. */
+       long rmv = (rm == 15) ? ppc : regs->uregs[rm];
+       long rnv_wb;
 
-       regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
+       rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
                                               regs->uregs[rd+1],
                                               regs->ARM_cpsr, i_fn);
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv_wb;
 }
 
 static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)
@@ -630,31 +621,6 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs)
                regs->uregs[rn] = rnv_wb;  /* Save Rn in case of writeback. */
 }
 
-static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs)
-{
-       insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0];
-       kprobe_opcode_t insn = p->opcode;
-       union reg_pair fnr;
-       int rd = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-
-       fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn);
-       regs->uregs[rn] = fnr.r0;
-       regs->uregs[rd] = fnr.r1;
-}
-
-static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs)
-{
-       insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
-       kprobe_opcode_t insn = p->opcode;
-       int rd = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       long rnv = regs->uregs[rn];
-       long rdv = regs->uregs[rd];
-
-       insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn);
-}
-
 static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs)
 {
        insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
@@ -688,32 +654,32 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs)
        insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
 }
 
-static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
-       kprobe_opcode_t insn = p->opcode;
-       int rd = (insn >> 12) & 0xf;
-
-       regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
 }
 
-static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes
+emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs)
 {
        insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
-       int ird = (insn >> 12) & 0xf;
+       int rd = (insn >> 12) & 0xf;
+       long rdv = regs->uregs[rd];
 
-       insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn);
+       regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn);
 }
 
-static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes
+emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs)
 {
-       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+       insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
        kprobe_opcode_t insn = p->opcode;
-       int rn = (insn >> 16) & 0xf;
+       int rd = (insn >> 12) & 0xf;
+       int rn = insn & 0xf;
+       long rdv = regs->uregs[rd];
        long rnv = regs->uregs[rn];
 
-       insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
+       regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn);
 }
 
 static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs)
@@ -818,6 +784,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
        regs->uregs[rd] = insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
 }
 
+static void __kprobes
+emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs)
+{
+       insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+       kprobe_opcode_t insn = p->opcode;
+       int rn = (insn >> 16) & 0xf;
+       long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
+
+       insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
+}
+
 static void __kprobes
 emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs)
 {
@@ -854,14 +831,34 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
                insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
 }
 
+static void __kprobes
+emulate_alu_tests(struct kprobe *p, struct pt_regs *regs)
+{
+       insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
+       kprobe_opcode_t insn = p->opcode;
+       long ppc = (long)p->addr + 8;
+       int rn = (insn >> 16) & 0xf;
+       int rs = (insn >> 8) & 0xf;     /* rs/rsv may be invalid, don't care. */
+       int rm = insn & 0xf;
+       long rnv = (rn == 15) ? ppc : regs->uregs[rn];
+       long rmv = (rm == 15) ? ppc : regs->uregs[rm];
+       long rsv = regs->uregs[rs];
+
+       insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
+}
+
 static enum kprobe_insn __kprobes
 prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
-       int ibit = (insn & (1 << 26)) ? 25 : 22;
+       int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25))
+                                        : (~insn & (1 << 22));
+
+       if (is_writeback(insn) && is_r15(insn, 16))
+               return INSN_REJECTED;   /* Writeback to PC */
 
        insn &= 0xfff00fff;
        insn |= 0x00001000;     /* Rn = r0, Rd = r1 */
-       if (insn & (1 << ibit)) {
+       if (not_imm) {
                insn &= ~0xf;
                insn |= 2;      /* Rm = r2 */
        }
@@ -871,20 +868,40 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 }
 
 static enum kprobe_insn __kprobes
-prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
-       insn &= 0xffff0ff0;     /* Rd = r0, Rm = r0 */
+       if (is_r15(insn, 12))
+               return INSN_REJECTED;   /* Rd is PC */
+
+       insn &= 0xffff0fff;     /* Rd = r0 */
        asi->insn[0] = insn;
-       asi->insn_handler = emulate_rd12rm0;
+       asi->insn_handler = emulate_rd12_modify;
        return INSN_GOOD;
 }
 
 static enum kprobe_insn __kprobes
-prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+prep_emulate_rd12rn0_modify(kprobe_opcode_t insn,
+                           struct arch_specific_insn *asi)
 {
-       insn &= 0xffff0fff;     /* Rd = r0 */
+       if (is_r15(insn, 12))
+               return INSN_REJECTED;   /* Rd is PC */
+
+       insn &= 0xffff0ff0;     /* Rd = r0 */
+       insn |= 0x00000001;     /* Rn = r1 */
+       asi->insn[0] = insn;
+       asi->insn_handler = emulate_rd12rn0_modify;
+       return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+       if (is_r15(insn, 12))
+               return INSN_REJECTED;   /* Rd is PC */
+
+       insn &= 0xffff0ff0;     /* Rd = r0, Rm = r0 */
        asi->insn[0] = insn;
-       asi->insn_handler = emulate_rd12;
+       asi->insn_handler = emulate_rd12rm0;
        return INSN_GOOD;
 }
 
@@ -892,6 +909,9 @@ static enum kprobe_insn __kprobes
 prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn,
                                struct arch_specific_insn *asi)
 {
+       if (is_r15(insn, 12))
+               return INSN_REJECTED;   /* Rd is PC */
+
        insn &= 0xfff00ff0;     /* Rd = r0, Rn = r0 */
        insn |= 0x00000001;     /* Rm = r1 */
        asi->insn[0] = insn;
@@ -903,6 +923,9 @@ static enum kprobe_insn __kprobes
 prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn,
                               struct arch_specific_insn *asi)
 {
+       if (is_r15(insn, 16))
+               return INSN_REJECTED;   /* Rd is PC */
+
        insn &= 0xfff0f0f0;     /* Rd = r0, Rs = r0 */
        insn |= 0x00000001;     /* Rm = r1          */
        asi->insn[0] = insn;
@@ -914,6 +937,9 @@ static enum kprobe_insn __kprobes
 prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn,
                                   struct arch_specific_insn *asi)
 {
+       if (is_r15(insn, 16))
+               return INSN_REJECTED;   /* Rd is PC */
+
        insn &= 0xfff000f0;     /* Rd = r0, Rn = r0 */
        insn |= 0x00000102;     /* Rs = r1, Rm = r2 */
        asi->insn[0] = insn;
@@ -925,6 +951,9 @@ static enum kprobe_insn __kprobes
 prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
                                       struct arch_specific_insn *asi)
 {
+       if (is_r15(insn, 16) || is_r15(insn, 12))
+               return INSN_REJECTED;   /* RdHi or RdLo is PC */
+
        insn &= 0xfff000f0;     /* RdHi = r0, RdLo = r1 */
        insn |= 0x00001203;     /* Rs = r2, Rm = r3 */
        asi->insn[0] = insn;
@@ -945,20 +974,13 @@ prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
 static enum kprobe_insn __kprobes
 space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
-       /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */
-       /* RFE           : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */
-       /* SRS           : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */
-       if ((insn & 0xfff30020) == 0xf1020000 ||
-           (insn & 0xfe500f00) == 0xf8100a00 ||
-           (insn & 0xfe5f0f00) == 0xf84d0500)
-               return INSN_REJECTED;
-
-       /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */
-       if ((insn & 0xfd700000) == 0xf4500000) {
-               insn &= 0xfff0ffff;     /* Rn = r0 */
-               asi->insn[0] = insn;
-               asi->insn_handler = emulate_rn16;
-               return INSN_GOOD;
+       /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */
+       /* PLDI        : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */
+       /* PLDW        : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */
+       /* PLD         : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */
+       if ((insn & 0xfe300000) == 0xf4100000) {
+               asi->insn_handler = emulate_nop;
+               return INSN_GOOD_NO_SLOT;
        }
 
        /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */
@@ -967,41 +989,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                return INSN_GOOD_NO_SLOT;
        }
 
-       /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
-       /* CDP2   : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
-       if ((insn & 0xffff00f0) == 0xf1010000 ||
-           (insn & 0xff000010) == 0xfe000000) {
-               asi->insn[0] = insn;
-               asi->insn_handler = emulate_none;
-               return INSN_GOOD;
-       }
+       /* CPS   : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
+       /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
 
+       /* SRS   : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
+       /* RFE   : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
+
+       /* Coprocessor instructions... */
        /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
        /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
-       if ((insn & 0xffe00000) == 0xfc400000) {
-               insn &= 0xfff00fff;     /* Rn = r0 */
-               insn |= 0x00001000;     /* Rd = r1 */
-               asi->insn[0] = insn;
-               asi->insn_handler =
-                       (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
-               return INSN_GOOD;
-       }
+       /* LDC2  : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+       /* STC2  : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+       /* CDP2  : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+       /* MCR2  : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+       /* MRC2  : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
 
-       /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
-       /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
-       if ((insn & 0xfe000000) == 0xfc000000) {
-               insn &= 0xfff0ffff;      /* Rn = r0 */
-               asi->insn[0] = insn;
-               asi->insn_handler = emulate_ldcstc;
-               return INSN_GOOD;
-       }
-
-       /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
-       /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
-       insn &= 0xffff0fff;     /* Rd = r0 */
-       asi->insn[0]      = insn;
-       asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
-       return INSN_GOOD;
+       return INSN_REJECTED;
 }
 
 static enum kprobe_insn __kprobes
@@ -1010,19 +1013,18 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
        /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */
        if ((insn & 0x0f900010) == 0x01000000) {
 
-               /* BXJ  : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
-               /* MSR  : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
-               if ((insn & 0x0ff000f0) == 0x01200020 ||
-                   (insn & 0x0fb000f0) == 0x01200000)
-                       return INSN_REJECTED;
-
-               /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */
-               if ((insn & 0x0fb00010) == 0x01000000)
-                       return prep_emulate_rd12(insn, asi);
+               /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
+               if ((insn & 0x0ff000f0) == 0x01000000) {
+                       if (is_r15(insn, 12))
+                               return INSN_REJECTED;   /* Rd is PC */
+                       asi->insn_handler = simulate_mrs;
+                       return INSN_GOOD_NO_SLOT;
+               }
 
                /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
                if ((insn & 0x0ff00090) == 0x01400080)
-                       return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
+                       return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn,
+                                                                       asi);
 
                /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
                /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
@@ -1031,24 +1033,29 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                        return prep_emulate_rd16rs8rm0_wflags(insn, asi);
 
                /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */
-               /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */
-               return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+               /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */
+               if ((insn & 0x0ff00090) == 0x01000080 ||
+                   (insn & 0x0ff000b0) == 0x01200080)
+                       return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+
+               /* BXJ      : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
+               /* MSR      : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
+               /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
 
+               /* Other instruction encodings aren't yet defined */
+               return INSN_REJECTED;
        }
 
        /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */
        else if ((insn & 0x0f900090) == 0x01000010) {
 
-               /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
-               if ((insn & 0xfff000f0) == 0xe1200070)
-                       return INSN_REJECTED;
-
                /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
                /* BX     : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
                if ((insn & 0x0ff000d0) == 0x01200010) {
-                       asi->insn[0] = truecc_insn(insn);
+                       if ((insn & 0x0ff000ff) == 0x0120003f)
+                               return INSN_REJECTED; /* BLX pc */
                        asi->insn_handler = simulate_blx2bx;
-                       return INSN_GOOD;
+                       return INSN_GOOD_NO_SLOT;
                }
 
                /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
@@ -1059,17 +1066,27 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                /* QSUB    : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */
                /* QDADD   : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */
                /* QDSUB   : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */
-               return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+               if ((insn & 0x0f9000f0) == 0x01000050)
+                       return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+
+               /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
+               /* SMC  : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
+
+               /* Other instruction encodings aren't yet defined */
+               return INSN_REJECTED;
        }
 
        /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */
-       else if ((insn & 0x0f000090) == 0x00000090) {
+       else if ((insn & 0x0f0000f0) == 0x00000090) {
 
                /* MUL    : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx :   */
                /* MULS   : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */
                /* MLA    : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx :   */
                /* MLAS   : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */
                /* UMAAL  : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx :   */
+               /* undef  : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx :   */
+               /* MLS    : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx :   */
+               /* undef  : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx :   */
                /* UMULL  : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx :   */
                /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */
                /* UMLAL  : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx :   */
@@ -1078,13 +1095,15 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */
                /* SMLAL  : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx :   */
                /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */
-               if ((insn & 0x0fe000f0) == 0x00000090) {
-                      return prep_emulate_rd16rs8rm0_wflags(insn, asi);
-               } else if  ((insn & 0x0fe000f0) == 0x00200090) {
-                      return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
-               } else {
-                      return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
-               }
+               if ((insn & 0x00d00000) == 0x00500000)
+                       return INSN_REJECTED;
+               else if ((insn & 0x00e00000) == 0x00000000)
+                       return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+               else if ((insn & 0x00a00000) == 0x00200000)
+                       return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+               else
+                       return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn,
+                                                                       asi);
        }
 
        /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */
@@ -1092,23 +1111,45 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
                /* SWP   : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */
                /* SWPB  : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */
-               /* LDRD  : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
-               /* STRD  : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
+               /* ???   : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */
+               /* ???   : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */
+               /* ???   : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */
                /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */
                /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */
+               /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */
+               /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */
+               /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */
+               /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */
+               /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */
+               /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */
+
+               /* LDRD  : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
+               /* STRD  : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
                /* LDRH  : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */
                /* STRH  : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */
                /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */
                /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */
-               if ((insn & 0x0fb000f0) == 0x01000090) {
-                       /* SWP/SWPB */
-                       return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+               if ((insn & 0x0f0000f0) == 0x01000090) {
+                       if ((insn & 0x0fb000f0) == 0x01000090) {
+                               /* SWP/SWPB */
+                               return prep_emulate_rd12rn16rm0_wflags(insn,
+                                                                       asi);
+                       } else {
+                               /* STREX/LDREX variants and unallocaed space */
+                               return INSN_REJECTED;
+                       }
+
                } else if ((insn & 0x0e1000d0) == 0x00000d0) {
                        /* STRD/LDRD */
+                       if ((insn & 0x0000e000) == 0x0000e000)
+                               return INSN_REJECTED;   /* Rd is LR or PC */
+                       if (is_writeback(insn) && is_r15(insn, 16))
+                               return INSN_REJECTED;   /* Writeback to PC */
+
                        insn &= 0xfff00fff;
                        insn |= 0x00002000;     /* Rn = r0, Rd = r2 */
-                       if (insn & (1 << 22)) {
-                               /* I bit */
+                       if (!(insn & (1 << 22))) {
+                               /* Register index */
                                insn &= ~0xf;
                                insn |= 1;      /* Rm = r1 */
                        }
@@ -1118,6 +1159,9 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                        return INSN_GOOD;
                }
 
+               /* LDRH/STRH/LDRSB/LDRSH */
+               if (is_r15(insn, 12))
+                       return INSN_REJECTED;   /* Rd is PC */
                return prep_emulate_ldr_str(insn, asi);
        }
 
@@ -1125,7 +1169,7 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
        /*
         * ALU op with S bit and Rd == 15 :
-        *      cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx
+        *      cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx
         */
        if ((insn & 0x0e10f000) == 0x0010f000)
                return INSN_REJECTED;
@@ -1154,22 +1198,61 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
                insn |= 0x00000200;     /* Rs = r2 */
        }
        asi->insn[0] = insn;
-       asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
+
+       if ((insn & 0x0f900000) == 0x01100000) {
+               /*
+                * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx
+                * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx
+                * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx
+                * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx
+                */
+               asi->insn_handler = emulate_alu_tests;
+       } else {
+               /* ALU ops which write to Rd */
+               asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
                                emulate_alu_rwflags : emulate_alu_rflags;
+       }
        return INSN_GOOD;
 }
 
 static enum kprobe_insn __kprobes
 space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
+       /* MOVW  : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
+       /* MOVT  : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
+       if ((insn & 0x0fb00000) == 0x03000000)
+               return prep_emulate_rd12_modify(insn, asi);
+
+       /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
+       if ((insn & 0x0fff0000) == 0x03200000) {
+               unsigned op2 = insn & 0x000000ff;
+               if (op2 == 0x01 || op2 == 0x04) {
+                       /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
+                       /* SEV   : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
+                       asi->insn[0] = insn;
+                       asi->insn_handler = emulate_none;
+                       return INSN_GOOD;
+               } else if (op2 <= 0x03) {
+                       /* NOP   : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
+                       /* WFE   : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
+                       /* WFI   : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
+                       /*
+                        * We make WFE and WFI true NOPs to avoid stalls due
+                        * to missing events whilst processing the probe.
+                        */
+                       asi->insn_handler = emulate_nop;
+                       return INSN_GOOD_NO_SLOT;
+               }
+               /* For DBG and unallocated hints it's safest to reject them */
+               return INSN_REJECTED;
+       }
+
        /*
         * MSR   : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
-        * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx
         * ALU op with S bit and Rd == 15 :
         *         cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
         */
        if ((insn & 0x0fb00000) == 0x03200000 ||        /* MSR */
-           (insn & 0x0ff00000) == 0x03400000 ||        /* Undef */
            (insn & 0x0e10f000) == 0x0210f000)          /* ALU s-bit, R15  */
                return INSN_REJECTED;
 
@@ -1180,10 +1263,22 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
         * *S (bit 20) updates condition codes
         * ADC/SBC/RSC reads the C flag
         */
-       insn &= 0xffff0fff;     /* Rd = r0 */
+       insn &= 0xfff00fff;     /* Rn = r0 and Rd = r0 */
        asi->insn[0] = insn;
-       asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
+
+       if ((insn & 0x0f900000) == 0x03100000) {
+               /*
+                * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx
+                * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx
+                * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx
+                * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx
+                */
+               asi->insn_handler = emulate_alu_tests_imm;
+       } else {
+               /* ALU ops which write to Rd */
+               asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
                        emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
+       }
        return INSN_GOOD;
 }
 
@@ -1192,6 +1287,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
        /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */
        if ((insn & 0x0ff000f0) == 0x068000b0) {
+               if (is_r15(insn, 12))
+                       return INSN_REJECTED;   /* Rd is PC */
                insn &= 0xfff00ff0;     /* Rd = r0, Rn = r0 */
                insn |= 0x00000001;     /* Rm = r1 */
                asi->insn[0] = insn;
@@ -1205,6 +1302,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
        /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */
        if ((insn & 0x0fa00030) == 0x06a00010 ||
            (insn & 0x0fb000f0) == 0x06a00030) {
+               if (is_r15(insn, 12))
+                       return INSN_REJECTED;   /* Rd is PC */
                insn &= 0xffff0ff0;     /* Rd = r0, Rm = r0 */
                asi->insn[0] = insn;
                asi->insn_handler = emulate_sat;
@@ -1213,57 +1312,101 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
        /* REV    : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
        /* REV16  : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
+       /* RBIT   : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
        /* REVSH  : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
        if ((insn & 0x0ff00070) == 0x06b00030 ||
-           (insn & 0x0ff000f0) == 0x06f000b0)
+           (insn & 0x0ff00070) == 0x06f00030)
                return prep_emulate_rd12rm0(insn, asi);
 
+       /* ???       : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx :   */
        /* SADD16    : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */
        /* SADDSUBX  : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */
        /* SSUBADDX  : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */
        /* SSUB16    : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */
        /* SADD8     : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */
+       /* ???       : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx :   */
        /* SSUB8     : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */
        /* QADD16    : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx :   */
        /* QADDSUBX  : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx :   */
        /* QSUBADDX  : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx :   */
        /* QSUB16    : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx :   */
        /* QADD8     : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx :   */
+       /* ???       : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx :   */
        /* QSUB8     : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx :   */
        /* SHADD16   : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx :   */
        /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx :   */
        /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx :   */
        /* SHSUB16   : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx :   */
        /* SHADD8    : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx :   */
+       /* ???       : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx :   */
        /* SHSUB8    : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx :   */
+       /* ???       : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx :   */
        /* UADD16    : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */
        /* UADDSUBX  : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */
        /* USUBADDX  : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */
        /* USUB16    : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */
        /* UADD8     : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */
+       /* ???       : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx :   */
        /* USUB8     : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */
        /* UQADD16   : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx :   */
        /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx :   */
        /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx :   */
        /* UQSUB16   : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx :   */
        /* UQADD8    : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx :   */
+       /* ???       : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx :   */
        /* UQSUB8    : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx :   */
        /* UHADD16   : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx :   */
        /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx :   */
        /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx :   */
        /* UHSUB16   : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx :   */
        /* UHADD8    : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx :   */
+       /* ???       : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx :   */
+       /* ???       : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx :   */
        /* UHSUB8    : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx :   */
+       if ((insn & 0x0f800010) == 0x06000010) {
+               if ((insn & 0x00300000) == 0x00000000 ||
+                   (insn & 0x000000e0) == 0x000000a0 ||
+                   (insn & 0x000000e0) == 0x000000c0)
+                       return INSN_REJECTED;   /* Unallocated space */
+               return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+       }
+
        /* PKHBT     : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx :   */
        /* PKHTB     : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx :   */
+       if ((insn & 0x0ff00030) == 0x06800010)
+               return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+
        /* SXTAB16   : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx :   */
-       /* SXTB      : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
+       /* SXTB16    : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx :   */
+       /* ???       : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx :   */
        /* SXTAB     : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
+       /* SXTB      : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx :   */
        /* SXTAH     : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx :   */
+       /* SXTH      : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx :   */
        /* UXTAB16   : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx :   */
+       /* UXTB16    : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx :   */
+       /* ???       : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx :   */
        /* UXTAB     : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx :   */
+       /* UXTB      : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx :   */
        /* UXTAH     : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx :   */
-       return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+       /* UXTH      : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx :   */
+       if ((insn & 0x0f8000f0) == 0x06800070) {
+               if ((insn & 0x00300000) == 0x00100000)
+                       return INSN_REJECTED;   /* Unallocated space */
+
+               if ((insn & 0x000f0000) == 0x000f0000)
+                       return prep_emulate_rd12rm0(insn, asi);
+               else
+                       return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+       }
+
+       /* Other instruction encodings aren't yet defined */
+       return INSN_REJECTED;
 }
 
 static enum kprobe_insn __kprobes
@@ -1273,29 +1416,49 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
        if ((insn & 0x0ff000f0) == 0x03f000f0)
                return INSN_REJECTED;
 
-       /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
-       /* USAD8  : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
-       if ((insn & 0x0ff000f0) == 0x07800010)
-                return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
-
        /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
        /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
        if ((insn & 0x0ff00090) == 0x07400010)
                return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
 
        /* SMLAD  : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */
+       /* SMUAD  : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
        /* SMLSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */
+       /* SMUSD  : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx :  */
        /* SMMLA  : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx :  */
-       /* SMMLS  : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx :  */
+       /* SMMUL  : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx :  */
+       /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx :  */
+       /* USAD8  : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx :  */
        if ((insn & 0x0ff00090) == 0x07000010 ||
            (insn & 0x0ff000d0) == 0x07500010 ||
-           (insn & 0x0ff000d0) == 0x075000d0)
+           (insn & 0x0ff000f0) == 0x07800010) {
+
+               if ((insn & 0x0000f000) == 0x0000f000)
+                       return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+               else
+                       return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+       }
+
+       /* SMMLS  : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx :  */
+       if ((insn & 0x0ff000d0) == 0x075000d0)
                return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
 
-       /* SMUSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :  */
-       /* SMUAD  : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
-       /* SMMUL  : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx :  */
-       return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+       /* SBFX   : cccc 0111 101x xxxx xxxx xxxx x101 xxxx :  */
+       /* UBFX   : cccc 0111 111x xxxx xxxx xxxx x101 xxxx :  */
+       if ((insn & 0x0fa00070) == 0x07a00050)
+               return prep_emulate_rd12rm0(insn, asi);
+
+       /* BFI    : cccc 0111 110x xxxx xxxx xxxx x001 xxxx :  */
+       /* BFC    : cccc 0111 110x xxxx xxxx xxxx x001 1111 :  */
+       if ((insn & 0x0fe00070) == 0x07c00010) {
+
+               if ((insn & 0x0000000f) == 0x0000000f)
+                       return prep_emulate_rd12_modify(insn, asi);
+               else
+                       return prep_emulate_rd12rn0_modify(insn, asi);
+       }
+
+       return INSN_REJECTED;
 }
 
 static enum kprobe_insn __kprobes
@@ -1309,6 +1472,10 @@ space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
        /* STRB  : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */
        /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
        /* STRT  : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
+
+       if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12))
+               return INSN_REJECTED;   /* LDRB into PC */
+
        return prep_emulate_ldr_str(insn, asi);
 }
 
@@ -1323,10 +1490,9 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
        /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
        /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
-       asi->insn[0] = truecc_insn(insn);
        asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */
                                simulate_stm1_pc : simulate_ldm1stm1;
-       return INSN_GOOD;
+       return INSN_GOOD_NO_SLOT;
 }
 
 static enum kprobe_insn __kprobes
@@ -1334,58 +1500,117 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
        /* B  : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
        /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
-       asi->insn[0] = truecc_insn(insn);
        asi->insn_handler = simulate_bbl;
-       return INSN_GOOD;
+       return INSN_GOOD_NO_SLOT;
 }
 
 static enum kprobe_insn __kprobes
-space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
+       /* Coprocessor instructions... */
        /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
        /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
-       insn &= 0xfff00fff;
-       insn |= 0x00001000;     /* Rn = r0, Rd = r1 */
-       asi->insn[0] = insn;
-       asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
-       return INSN_GOOD;
+       /* LDC  : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+       /* STC  : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+       /* CDP  : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+       /* MCR  : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+       /* MRC  : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
+
+       /* SVC  : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
+
+       return INSN_REJECTED;
 }
 
-static enum kprobe_insn __kprobes
-space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+static unsigned long __kprobes __check_eq(unsigned long cpsr)
 {
-       /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
-       /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
-       insn &= 0xfff0ffff;     /* Rn = r0 */
-       asi->insn[0] = insn;
-       asi->insn_handler = emulate_ldcstc;
-       return INSN_GOOD;
+       return cpsr & PSR_Z_BIT;
 }
 
-static enum kprobe_insn __kprobes
-space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+static unsigned long __kprobes __check_ne(unsigned long cpsr)
 {
-       /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
-       /* SWI  : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
-       if ((insn & 0xfff000f0) == 0xe1200070 ||
-           (insn & 0x0f000000) == 0x0f000000)
-               return INSN_REJECTED;
+       return (~cpsr) & PSR_Z_BIT;
+}
 
-       /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
-       if ((insn & 0x0f000010) == 0x0e000000) {
-               asi->insn[0] = insn;
-               asi->insn_handler = emulate_none;
-               return INSN_GOOD;
-       }
+static unsigned long __kprobes __check_cs(unsigned long cpsr)
+{
+       return cpsr & PSR_C_BIT;
+}
 
-       /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
-       /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
-       insn &= 0xffff0fff;     /* Rd = r0 */
-       asi->insn[0] = insn;
-       asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
-       return INSN_GOOD;
+static unsigned long __kprobes __check_cc(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_mi(unsigned long cpsr)
+{
+       return cpsr & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_pl(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_vs(unsigned long cpsr)
+{
+       return cpsr & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_vc(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_hi(unsigned long cpsr)
+{
+       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return cpsr & PSR_C_BIT;
 }
 
+static unsigned long __kprobes __check_ls(unsigned long cpsr)
+{
+       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (~cpsr) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ge(unsigned long cpsr)
+{
+       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       return (~cpsr) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_lt(unsigned long cpsr)
+{
+       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       return cpsr & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_gt(unsigned long cpsr)
+{
+       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
+       return (~temp) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_le(unsigned long cpsr)
+{
+       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
+       return temp & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_al(unsigned long cpsr)
+{
+       return true;
+}
+
+static kprobe_check_cc * const condition_checks[16] = {
+       &__check_eq, &__check_ne, &__check_cs, &__check_cc,
+       &__check_mi, &__check_pl, &__check_vs, &__check_vc,
+       &__check_hi, &__check_ls, &__check_ge, &__check_lt,
+       &__check_gt, &__check_le, &__check_al, &__check_al
+};
+
 /* Return:
  *   INSN_REJECTED     If instruction is one not allowed to kprobe,
  *   INSN_GOOD         If instruction is supported and uses instruction slot,
@@ -1401,133 +1626,45 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 {
+       asi->insn_check_cc = condition_checks[insn>>28];
        asi->insn[1] = KPROBE_RETURN_INSTRUCTION;
 
-       if ((insn & 0xf0000000) == 0xf0000000) {
+       if ((insn & 0xf0000000) == 0xf0000000)
 
                return space_1111(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x00000000) {
+       else if ((insn & 0x0e000000) == 0x00000000)
 
                return space_cccc_000x(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x02000000) {
+       else if ((insn & 0x0e000000) == 0x02000000)
 
                return space_cccc_001x(insn, asi);
 
-       } else if ((insn & 0x0f000010) == 0x06000010) {
+       else if ((insn & 0x0f000010) == 0x06000010)
 
                return space_cccc_0110__1(insn, asi);
 
-       } else if ((insn & 0x0f000010) == 0x07000010) {
+       else if ((insn & 0x0f000010) == 0x07000010)
 
                return space_cccc_0111__1(insn, asi);
 
-       } else if ((insn & 0x0c000000) == 0x04000000) {
+       else if ((insn & 0x0c000000) == 0x04000000)
 
                return space_cccc_01xx(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x08000000) {
+       else if ((insn & 0x0e000000) == 0x08000000)
 
                return space_cccc_100x(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x0a000000) {
+       else if ((insn & 0x0e000000) == 0x0a000000)
 
                return space_cccc_101x(insn, asi);
 
-       } else if ((insn & 0x0fe00000) == 0x0c400000) {
-
-               return space_cccc_1100_010x(insn, asi);
-
-       } else if ((insn & 0x0e000000) == 0x0c000000) {
-
-               return space_cccc_110x(insn, asi);
-
-       }
-
-       return space_cccc_111x(insn, asi);
+       return space_cccc_11xx(insn, asi);
 }
 
 void __init arm_kprobe_decode_init(void)
 {
        find_str_pc_offset();
 }
-
-
-/*
- * All ARM instructions listed below.
- *
- * Instructions and their general purpose registers are given.
- * If a particular register may not use R15, it is prefixed with a "!".
- * If marked with a "*" means the value returned by reading R15
- * is implementation defined.
- *
- * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ
- *     TST: Rd, Rn, Rm, !Rs
- * BX: Rm
- * BLX(2): !Rm
- * BX: Rm (R15 legal, but discouraged)
- * BXJ: !Rm,
- * CLZ: !Rd, !Rm
- * CPY: Rd, Rm
- * LDC/2,STC/2 immediate offset & unindex: Rn
- * LDC/2,STC/2 immediate pre/post-indexed: !Rn
- * LDM(1/3): !Rn, register_list
- * LDM(2): !Rn, !register_list
- * LDR,STR,PLD immediate offset: Rd, Rn
- * LDR,STR,PLD register offset: Rd, Rn, !Rm
- * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm
- * LDR,STR immediate pre/post-indexed: Rd, !Rn
- * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm
- * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm
- * LDRB,STRB immediate offset: !Rd, Rn
- * LDRB,STRB register offset: !Rd, Rn, !Rm
- * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm
- * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn
- * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm
- * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm
- * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn
- * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm
- * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm
- * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn
- * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm
- * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn
- * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm
- * LDREX: !Rd, !Rn
- * MCR/2: !Rd
- * MCRR/2,MRRC/2: !Rd, !Rn
- * MLA: !Rd, !Rn, !Rm, !Rs
- * MOV: Rd
- * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register)
- * MRS,MSR: !Rd
- * MUL: !Rd, !Rm, !Rs
- * PKH{BT,TB}: !Rd, !Rn, !Rm
- * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn
- * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn
- * REV/16/SH: !Rd, !Rm
- * RFE: !Rn
- * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm
- * SEL: !Rd, !Rn, !Rm
- * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs
- * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs
- * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs
- * SSAT/16: !Rd, !Rm
- * STM(1/2): !Rn, register_list* (R15 in reg list not recommended)
- * STRT immediate pre/post-indexed: Rd*, !Rn
- * STRT register pre/post-indexed: Rd*, !Rn, !Rm
- * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm
- * STREX: !Rd, !Rn, !Rm
- * SWP/B: !Rd, !Rn, !Rm
- * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm
- * {S,U}XT{B,B16,H}: !Rd, !Rm
- * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs
- * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs
- *
- * May transfer control by writing R15 (possible mode changes or alternate
- * mode accesses marked by "*"):
- * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY,
- * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI*
- *
- * Instructions that do not take general registers, nor transfer control:
- * CDP/2, SETEND, SRS*
- */
index 2ba7deb3072e5962c6cd3de55d4a2ed2594c1589..1656c87501c0f5bee77ebaab931e8249d70ce451 100644 (file)
@@ -134,7 +134,8 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
                                 struct kprobe_ctlblk *kcb)
 {
        regs->ARM_pc += 4;
-       p->ainsn.insn_handler(p, regs);
+       if (p->ainsn.insn_check_cc(regs->ARM_cpsr))
+               p->ainsn.insn_handler(p, regs);
 }
 
 /*
index 69cfee0fe00f1cbc38eb7f789ef23aae51688dd6..139e3c8273696198fa0995a761a5368875961b51 100644 (file)
@@ -221,7 +221,7 @@ again:
        prev_raw_count &= armpmu->max_period;
 
        if (overflow)
-               delta = armpmu->max_period - prev_raw_count + new_raw_count;
+               delta = armpmu->max_period - prev_raw_count + new_raw_count + 1;
        else
                delta = new_raw_count - prev_raw_count;
 
@@ -746,7 +746,8 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 
        tail = (struct frame_tail __user *)regs->ARM_fp - 1;
 
-       while (tail && !((unsigned long)tail & 0x3))
+       while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+              tail && !((unsigned long)tail & 0x3))
                tail = user_backtrace(tail, entry);
 }
 
index 94bbedbed6394cf147e2b73bce3b6629d0dbbd9f..5e1e541972277f38a123d7964fca081629584d50 100644 (file)
@@ -372,6 +372,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        if (clone_flags & CLONE_SETTLS)
                thread->tp_value = regs->ARM_r3;
 
+       thread_notify(THREAD_NOTIFY_COPY, thread);
+
        return 0;
 }
 
index 2bf27f364d098c210ed7cca9ece5edca613a9f2b..8182f45ca493724f732f59cfe38e69a7c45afe44 100644 (file)
@@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request,
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
                case PTRACE_GETHBPREGS:
+                       if (ptrace_get_breakpoints(child) < 0)
+                               return -ESRCH;
+
                        ret = ptrace_gethbpregs(child, addr,
                                                (unsigned long __user *)data);
+                       ptrace_put_breakpoints(child);
                        break;
                case PTRACE_SETHBPREGS:
+                       if (ptrace_get_breakpoints(child) < 0)
+                               return -ESRCH;
+
                        ret = ptrace_sethbpregs(child, addr,
                                                (unsigned long __user *)data);
+                       ptrace_put_breakpoints(child);
                        break;
 #endif
 
index 8fe05ad932e4bd0b113c11c19f7e816650ace696..f29b8a29b17436f80f3b960a8be0337aa91811c7 100644 (file)
@@ -479,7 +479,7 @@ static void broadcast_timer_set_mode(enum clock_event_mode mode,
 {
 }
 
-static void broadcast_timer_setup(struct clock_event_device *evt)
+static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
 {
        evt->name       = "dummy_timer";
        evt->features   = CLOCK_EVT_FEAT_ONESHOT |
index 4ad8da15ef2b3972f4412631ceb1a5cf1d63eba2..af0aaebf4de62e16e70fcfcad8ccafece2879217 100644 (file)
@@ -311,7 +311,7 @@ asmlinkage long sys_oabi_semtimedop(int semid,
        long err;
        int i;
 
-       if (nsops < 1)
+       if (nsops < 1 || nsops > SEMOPM)
                return -EINVAL;
        sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
        if (!sops)
index f0000e188c8c8c5a14be6f21c37b961739ecfad6..3b54ad19d4890c40752905af84a345b21ba56b62 100644 (file)
@@ -410,8 +410,7 @@ static int bad_syscall(int n, struct pt_regs *regs)
        struct thread_info *thread = current_thread_info();
        siginfo_t info;
 
-       if (current->personality != PER_LINUX &&
-           current->personality != PER_LINUX_32BIT &&
+       if ((current->personality & PER_MASK) != PER_LINUX &&
            thread->exec_domain->handler) {
                thread->exec_domain->handler(n, regs);
                return regs->ARM_r0;
index 19390231a0e98d5e792c64e487269e5f75a2ba23..2d299bf5d72fc05085dacf6ce5bcb20d9c02e1ea 100644 (file)
@@ -83,6 +83,7 @@ config ARCH_AT91CAP9
        select CPU_ARM926T
        select GENERIC_CLOCKEVENTS
        select HAVE_FB_ATMEL
+       select HAVE_NET_MACB
 
 config ARCH_AT572D940HF
        bool "AT572D940HF"
index 1f9d3cb64c50d66aa7f10f48cdd5fc532eb36a90..d8df59a3426d82a75de3255bf586292659072616 100644 (file)
 #include <mach/board.h>
 #include "generic.h"
 
+static void __init at91eb01_init_irq(void)
+{
+       at91x40_init_interrupts(NULL);
+}
+
 static void __init at91eb01_map_io(void)
 {
        at91x40_initialize(40000000);
@@ -38,7 +43,7 @@ static void __init at91eb01_map_io(void)
 MACHINE_START(AT91EB01, "Atmel AT91 EB01")
        /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
        .timer          = &at91x40_timer,
-       .init_irq       = at91x40_init_interrupts,
+       .init_irq       = at91eb01_init_irq,
        .map_io         = at91eb01_map_io,
 MACHINE_END
 
index 3bef931d0b1c915b5de540ee860dcf37cf27cba6..0700f2125305d99fd769f46726fe1e09afaa3dcc 100644 (file)
@@ -27,6 +27,7 @@
 #define ARCH_ID_AT91SAM9G45    0x819b05a0
 #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2      /* aka 9G45-ES2 & non ES lots */
 #define ARCH_ID_AT91SAM9G45ES  0x819b05a1      /* 9G45-ES (Engineering Sample) */
+#define ARCH_ID_AT91SAM9X5     0x819a05a0
 #define ARCH_ID_AT91CAP9       0x039A03A0
 
 #define ARCH_ID_AT91SAM9XE128  0x329973a0
@@ -55,6 +56,12 @@ static inline unsigned long at91_cpu_fully_identify(void)
 #define ARCH_EXID_AT91SAM9G46  0x00000003
 #define ARCH_EXID_AT91SAM9G45  0x00000004
 
+#define ARCH_EXID_AT91SAM9G15  0x00000000
+#define ARCH_EXID_AT91SAM9G35  0x00000001
+#define ARCH_EXID_AT91SAM9X35  0x00000002
+#define ARCH_EXID_AT91SAM9G25  0x00000003
+#define ARCH_EXID_AT91SAM9X25  0x00000004
+
 static inline unsigned long at91_exid_identify(void)
 {
        return at91_sys_read(AT91_DBGU_EXID);
@@ -143,6 +150,27 @@ static inline unsigned long at91cap9_rev_identify(void)
 #define cpu_is_at91sam9m11()   (0)
 #endif
 
+#ifdef CONFIG_ARCH_AT91SAM9X5
+#define cpu_is_at91sam9x5()    (at91_cpu_identify() == ARCH_ID_AT91SAM9X5)
+#define cpu_is_at91sam9g15()   (cpu_is_at91sam9x5() && \
+                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G15))
+#define cpu_is_at91sam9g35()   (cpu_is_at91sam9x5() && \
+                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G35))
+#define cpu_is_at91sam9x35()   (cpu_is_at91sam9x5() && \
+                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X35))
+#define cpu_is_at91sam9g25()   (cpu_is_at91sam9x5() && \
+                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G25))
+#define cpu_is_at91sam9x25()   (cpu_is_at91sam9x5() && \
+                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X25))
+#else
+#define cpu_is_at91sam9x5()    (0)
+#define cpu_is_at91sam9g15()   (0)
+#define cpu_is_at91sam9g35()   (0)
+#define cpu_is_at91sam9x35()   (0)
+#define cpu_is_at91sam9g25()   (0)
+#define cpu_is_at91sam9x25()   (0)
+#endif
+
 #ifdef CONFIG_ARCH_AT91CAP9
 #define cpu_is_at91cap9()      (at91_cpu_identify() == ARCH_ID_AT91CAP9)
 #define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
index 32f147998cd9536b7daf47236da1b75e9029087f..c0deacae778d28c3ef8ff50c004ac65f01ef3ce6 100644 (file)
@@ -63,6 +63,7 @@ config MACH_DAVINCI_EVM
        depends on ARCH_DAVINCI_DM644x
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Configure this option to specify the whether the board used
          for development is a DM644x EVM
@@ -72,6 +73,7 @@ config MACH_SFFSDR
        depends on ARCH_DAVINCI_DM644x
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Say Y here to select the Lyrtech Small Form Factor
          Software Defined Radio (SFFSDR) board.
@@ -105,6 +107,7 @@ config MACH_DAVINCI_DM6467_EVM
        select MACH_DAVINCI_DM6467TEVM
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Configure this option to specify the whether the board used
          for development is a DM6467 EVM
@@ -118,6 +121,7 @@ config MACH_DAVINCI_DM365_EVM
        depends on ARCH_DAVINCI_DM365
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Configure this option to specify whether the board used
          for development is a DM365 EVM
@@ -129,6 +133,7 @@ config MACH_DAVINCI_DA830_EVM
        select GPIO_PCF857X
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module.
 
@@ -205,6 +210,7 @@ config MACH_MITYOMAPL138
        depends on ARCH_DAVINCI_DA850
        select MISC_DEVICES
        select EEPROM_AT24
+       select I2C
        help
          Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
          System on Module.  Information on this SoM may be found at
index 2aa79c54f98e664d5a48701fdf0cec553090c9aa..606a6f27ed6c20e4e38034c180e592a407e68eea 100644 (file)
@@ -29,7 +29,7 @@
 #include <mach/mux.h>
 #include <mach/spi.h>
 
-#define MITYOMAPL138_PHY_ID            "0:03"
+#define MITYOMAPL138_PHY_ID            ""
 
 #define FACTORY_CONFIG_MAGIC   0x012C0138
 #define FACTORY_CONFIG_VERSION 0x00010001
@@ -414,7 +414,7 @@ static struct resource mityomapl138_nandflash_resource[] = {
 
 static struct platform_device mityomapl138_nandflash_device = {
        .name           = "davinci_nand",
-       .id             = 0,
+       .id             = 1,
        .dev            = {
                .platform_data  = &mityomapl138_nandflash_data,
        },
index 625d4b66718ba89bc3062c8b9b7b9189b13cc0c5..58a02dc7b15a5b76f8deb2f540e55f030d484d55 100644 (file)
@@ -39,7 +39,8 @@
 #define DA8XX_GPIO_BASE                        0x01e26000
 #define DA8XX_I2C1_BASE                        0x01e28000
 #define DA8XX_SPI0_BASE                        0x01c41000
-#define DA8XX_SPI1_BASE                        0x01f0e000
+#define DA830_SPI1_BASE                        0x01e12000
+#define DA850_SPI1_BASE                        0x01f0e000
 
 #define DA8XX_EMAC_CTRL_REG_OFFSET     0x3000
 #define DA8XX_EMAC_MOD_REG_OFFSET      0x2000
@@ -762,8 +763,8 @@ static struct resource da8xx_spi0_resources[] = {
 
 static struct resource da8xx_spi1_resources[] = {
        [0] = {
-               .start  = DA8XX_SPI1_BASE,
-               .end    = DA8XX_SPI1_BASE + SZ_4K - 1,
+               .start  = DA830_SPI1_BASE,
+               .end    = DA830_SPI1_BASE + SZ_4K - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -832,5 +833,10 @@ int __init da8xx_register_spi(int instance, struct spi_board_info *info,
 
        da8xx_spi_pdata[instance].num_chipselect = len;
 
+       if (instance == 1 && cpu_is_davinci_da850()) {
+               da8xx_spi1_resources[0].start = DA850_SPI1_BASE;
+               da8xx_spi1_resources[0].end = DA850_SPI1_BASE + SZ_4K - 1;
+       }
+
        return platform_device_register(&da8xx_spi_device[instance]);
 }
index f6801223964157084a7442939364ab255d0c8e39..a3a94e9c93784b10a6d98c3b379a680def7641e2 100644 (file)
@@ -314,7 +314,7 @@ static struct clk timer2_clk = {
        .name = "timer2",
        .parent = &pll1_aux_clk,
        .lpsc = DAVINCI_LPSC_TIMER2,
-       .usecount = 1,              /* REVISIT: why can't' this be disabled? */
+       .usecount = 1,              /* REVISIT: why can't this be disabled? */
 };
 
 static struct clk timer3_clk = {
index 5f8a6542418421147e84e31c18a54afc22728380..4c82c2716293a6e750f242c128fb14e66c2ce636 100644 (file)
@@ -274,7 +274,7 @@ static struct clk timer2_clk = {
        .name = "timer2",
        .parent = &pll1_aux_clk,
        .lpsc = DAVINCI_LPSC_TIMER2,
-       .usecount = 1,              /* REVISIT: why can't' this be disabled? */
+       .usecount = 1,              /* REVISIT: why can't this be disabled? */
 };
 
 static struct clk_lookup dm644x_clks[] = {
index 9f1befc5ac387d2d0124c080c88458a67dc0b30f..f8b7ea4f6235f6f5dc66aa15d9bfe203523f4486 100644 (file)
@@ -24,6 +24,9 @@
 
 #define UART_SHIFT     2
 
+#define davinci_uart_v2p(x)    ((x) - PAGE_OFFSET + PLAT_PHYS_OFFSET)
+#define davinci_uart_p2v(x)    ((x) - PLAT_PHYS_OFFSET + PAGE_OFFSET)
+
                .pushsection .data
 davinci_uart_phys:     .word   0
 davinci_uart_virt:     .word   0
@@ -34,7 +37,7 @@ davinci_uart_virt:    .word   0
                /* Use davinci_uart_phys/virt if already configured */
 10:            mrc     p15, 0, \rp, c1, c0
                tst     \rp, #1                 @ MMU enabled?
-               ldreq   \rp, =__virt_to_phys(davinci_uart_phys)
+               ldreq   \rp, =davinci_uart_v2p(davinci_uart_phys)
                ldrne   \rp, =davinci_uart_phys
                add     \rv, \rp, #4            @ davinci_uart_virt
                ldr     \rp, [\rp, #0]
@@ -48,18 +51,18 @@ davinci_uart_virt:  .word   0
                tst     \rp, #1                 @ MMU enabled?
 
                /* Copy uart phys address from decompressor uart info */
-               ldreq   \rv, =__virt_to_phys(davinci_uart_phys)
+               ldreq   \rv, =davinci_uart_v2p(davinci_uart_phys)
                ldrne   \rv, =davinci_uart_phys
                ldreq   \rp, =DAVINCI_UART_INFO
-               ldrne   \rp, =__phys_to_virt(DAVINCI_UART_INFO)
+               ldrne   \rp, =davinci_uart_p2v(DAVINCI_UART_INFO)
                ldr     \rp, [\rp, #0]
                str     \rp, [\rv]
 
                /* Copy uart virt address from decompressor uart info */
-               ldreq   \rv, =__virt_to_phys(davinci_uart_virt)
+               ldreq   \rv, =davinci_uart_v2p(davinci_uart_virt)
                ldrne   \rv, =davinci_uart_virt
                ldreq   \rp, =DAVINCI_UART_INFO
-               ldrne   \rp, =__phys_to_virt(DAVINCI_UART_INFO)
+               ldrne   \rp, =davinci_uart_p2v(DAVINCI_UART_INFO)
                ldr     \rp, [\rp, #4]
                str     \rp, [\rv]
 
index 8051110b8ac3417cf2817878204f9f1f1e28da42..c9e6ce185a66fa62a6a028613413e582894d6896 100644 (file)
@@ -22,7 +22,7 @@
  *
  * This area sits just below the page tables (see arch/arm/kernel/head.S).
  */
-#define DAVINCI_UART_INFO      (PHYS_OFFSET + 0x3ff8)
+#define DAVINCI_UART_INFO      (PLAT_PHYS_OFFSET + 0x3ff8)
 
 #define DAVINCI_UART0_BASE     (IO_PHYS + 0x20000)
 #define DAVINCI_UART1_BASE     (IO_PHYS + 0x20400)
index ee8b02ed8011dfa615603045a22c5a98956635e4..7bfb827f3fe36a8d71fc874b1a45e446be1d3bac 100644 (file)
@@ -10,7 +10,7 @@
 #define BANK_OFF(n)    (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
 #define GPIO_REG(x)    (*((volatile u32 *)(GPIO_REGS_VIRT + (x))))
 
-#define NR_BUILTIN_GPIO        (192)
+#define NR_BUILTIN_GPIO                IRQ_GPIO_NUM
 
 #define gpio_to_bank(gpio)     ((gpio) >> 5)
 #define gpio_to_irq(gpio)      (IRQ_GPIO_START + (gpio))
index 4621067c7720f457b311faff80e19dddc87ecd3e..713be155a44d716df91aeb74c2d043630f543564 100644 (file)
@@ -8,6 +8,15 @@
 #define MFP_DRIVE_MEDIUM       (0x2 << 13)
 #define MFP_DRIVE_FAST         (0x3 << 13)
 
+#undef MFP_CFG
+#undef MFP_CFG_DRV
+
+#define MFP_CFG(pin, af)               \
+       (MFP_LPM_INPUT | MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_DRIVE_MEDIUM)
+
+#define MFP_CFG_DRV(pin, af, drv)      \
+       (MFP_LPM_INPUT | MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_DRIVE_##drv)
+
 /* GPIO */
 #define GPIO0_GPIO             MFP_CFG(GPIO0, AF5)
 #define GPIO1_GPIO             MFP_CFG(GPIO1, AF5)
index 7f568611547e94d5343db7d174712dc732ea0f2c..6a96911b0ad508cdde70e79359a8e3480ce10c16 100644 (file)
@@ -160,10 +160,7 @@ static struct msm_mmc_platform_data qsd8x50_sdc1_data = {
 
 static void __init qsd8x50_init_mmc(void)
 {
-       if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa())
-               vreg_mmc = vreg_get(NULL, "gp6");
-       else
-               vreg_mmc = vreg_get(NULL, "gp5");
+       vreg_mmc = vreg_get(NULL, "gp5");
 
        if (IS_ERR(vreg_mmc)) {
                pr_err("vreg get for vreg_mmc failed (%ld)\n",
index 56f920c55b6aaaaa45737aeeddffadfa1b1a12d2..38b95e949d13b0a87d83a3274b0369e98c8321ed 100644 (file)
@@ -269,7 +269,7 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
 
        /* Use existing clock_event for cpu 0 */
        if (!smp_processor_id())
-               return;
+               return 0;
 
        writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 
index 2cf390fbd9809876a55a2b9dd6687e40cea41d60..47a69cbc31a873dbc19fc9f69d4b231095f3d356 100644 (file)
@@ -257,11 +257,16 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .workaround     = FLS_USB2_WORKAROUND_ENGCM09152,
 };
 
+static int vpr200_usbh_init(struct platform_device *pdev)
+{
+       return mx35_initialize_usb_hw(pdev->id,
+                       MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY);
+}
+
 /* USB HOST config */
 static const struct mxc_usbh_platform_data usb_host_pdata __initconst = {
-       .portsc         = MXC_EHCI_MODE_SERIAL,
-       .flags          = MXC_EHCI_INTERFACE_SINGLE_UNI |
-                         MXC_EHCI_INTERNAL_PHY,
+       .init = vpr200_usbh_init,
+       .portsc = MXC_EHCI_MODE_SERIAL,
 };
 
 static struct platform_device *devices[] __initdata = {
index 10a1bea1054888ecfe0a24689722090a2bc778c0..6206b1191fe8e574efe7c480864fd8201060244c 100644 (file)
@@ -193,7 +193,7 @@ static iomux_v3_cfg_t mx53_loco_pads[] = {
        .wakeup         = wake,                                 \
 }
 
-static const struct gpio_keys_button loco_buttons[] __initconst = {
+static struct gpio_keys_button loco_buttons[] = {
        GPIO_BUTTON(MX53_LOCO_POWER, KEY_POWER, 1, "power", 0),
        GPIO_BUTTON(MX53_LOCO_UI1, KEY_VOLUMEUP, 1, "volume-up", 0),
        GPIO_BUTTON(MX53_LOCO_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0),
index 1ad97fed1e948ccecf16db4562ad54c80252fadb..5dcc59d5b9ec9feab991fc34302273702388b21e 100644 (file)
@@ -295,11 +295,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)           \
        unsigned long diff, parent_rate, calc_rate;                     \
        int i;                                                          \
                                                                        \
-       parent_rate = clk_get_rate(clk->parent);                        \
        div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;       \
        bm_busy = BM_CLKCTRL_##dr##_BUSY;                               \
                                                                        \
        if (clk->parent == &ref_xtal_clk) {                             \
+               parent_rate = clk_get_rate(clk->parent);                \
                div = DIV_ROUND_UP(parent_rate, rate);                  \
                if (clk == &cpu_clk) {                                  \
                        div_max = BM_CLKCTRL_CPU_DIV_XTAL >>            \
@@ -309,6 +309,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)            \
                if (div == 0 || div > div_max)                          \
                        return -EINVAL;                                 \
        } else {                                                        \
+               /*                                                      \
+                * hack alert: this block modifies clk->parent, too,    \
+                * so the base to use it the grand parent.              \
+                */                                                     \
+               parent_rate = clk_get_rate(clk->parent->parent);        \
                rate >>= PARENT_RATE_SHIFT;                             \
                parent_rate >>= PARENT_RATE_SHIFT;                      \
                diff = parent_rate;                                     \
index a45cd6409686f7eadfd6cc85e24e010c628c6d0d..512b15204450417c88a7040b0302eccb3f8fdfdc 100644 (file)
@@ -68,7 +68,7 @@ obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
 obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
 
 AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
-AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a
+AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
 
 ifeq ($(CONFIG_PM_VERBOSE),y)
 CFLAGS_pm_bus.o                                += -DDEBUG
index e964895b80e8f95bbf8544a840e4598062c96a88..f8ba20a14e625554f95fded51abc2177e7326b96 100644 (file)
@@ -141,14 +141,19 @@ static void __init rx51_init(void)
 static void __init rx51_map_io(void)
 {
        omap2_set_globals_3xxx();
-       rx51_video_mem_init();
        omap34xx_map_common_io();
 }
 
+static void __init rx51_reserve(void)
+{
+       rx51_video_mem_init();
+       omap_reserve();
+}
+
 MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
        /* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
        .boot_params    = 0x80000100,
-       .reserve        = omap_reserve,
+       .reserve        = rx51_reserve,
        .map_io         = rx51_map_io,
        .init_early     = rx51_init_early,
        .init_irq       = omap_init_irq,
index 276992d3b7fba19b8873e2ff3cae068424b441e0..8c965671b4d486aae235439483204ccef4d2fbe7 100644 (file)
@@ -3116,14 +3116,9 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "dsp_fck",                      &dsp_fck,       CK_443X),
        CLK("omapdss_dss",      "sys_clk",                      &dss_sys_clk,   CK_443X),
        CLK("omapdss_dss",      "tv_clk",                       &dss_tv_clk,    CK_443X),
-       CLK("omapdss_dss",      "dss_clk",                      &dss_dss_clk,   CK_443X),
        CLK("omapdss_dss",      "video_clk",                    &dss_48mhz_clk, CK_443X),
-       CLK("omapdss_dss",      "fck",                          &dss_fck,       CK_443X),
-       /*
-        * On OMAP4, DSS ick is a dummy clock; this is needed for compatibility
-        * with OMAP2/3.
-        */
-       CLK("omapdss_dss",      "ick",                          &dummy_ck,      CK_443X),
+       CLK("omapdss_dss",      "fck",                          &dss_dss_clk,   CK_443X),
+       CLK("omapdss_dss",      "ick",                          &dss_fck,       CK_443X),
        CLK(NULL,       "efuse_ctrl_cust_fck",          &efuse_ctrl_cust_fck,   CK_443X),
        CLK(NULL,       "emif1_fck",                    &emif1_fck,     CK_443X),
        CLK(NULL,       "emif2_fck",                    &emif2_fck,     CK_443X),
index 9d0dec806e9294e721294149550a8746960e4d4f..38830d8d47835d30db060b77c49d4beb385ded4a 100644 (file)
@@ -247,6 +247,7 @@ struct omap3_cm_regs {
        u32 per_cm_clksel;
        u32 emu_cm_clksel;
        u32 emu_cm_clkstctrl;
+       u32 pll_cm_autoidle;
        u32 pll_cm_autoidle2;
        u32 pll_cm_clksel4;
        u32 pll_cm_clksel5;
@@ -319,6 +320,15 @@ void omap3_cm_save_context(void)
                omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1);
        cm_context.emu_cm_clkstctrl =
                omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL);
+       /*
+        * As per erratum i671, ROM code does not respect the PER DPLL
+        * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1.
+        * In this case, even though this register has been saved in
+        * scratchpad contents, we need to restore AUTO_PERIPH_DPLL
+        * by ourselves. So, we need to save it anyway.
+        */
+       cm_context.pll_cm_autoidle =
+               omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
        cm_context.pll_cm_autoidle2 =
                omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2);
        cm_context.pll_cm_clksel4 =
@@ -441,6 +451,13 @@ void omap3_cm_restore_context(void)
                               CM_CLKSEL1);
        omap2_cm_write_mod_reg(cm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD,
                               OMAP2_CM_CLKSTCTRL);
+       /*
+        * As per erratum i671, ROM code does not respect the PER DPLL
+        * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1.
+        * In this case, we need to restore AUTO_PERIPH_DPLL by ourselves.
+        */
+       omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle, PLL_MOD,
+                              CM_AUTOIDLE);
        omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle2, PLL_MOD,
                               CM_AUTOIDLE2);
        omap2_cm_write_mod_reg(cm_context.pll_cm_clksel4, PLL_MOD,
index 695279419020372cf16d2be18465734308d2c5c4..da53ba3917cae5df365b34bcb8f314e4142a2471 100644 (file)
@@ -316,8 +316,14 @@ void omap3_save_scratchpad_contents(void)
                        omap2_cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
        prcm_block_contents.cm_clken_pll =
                        omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN);
+       /*
+        * As per erratum i671, ROM code does not respect the PER DPLL
+        * programming scheme if CM_AUTOIDLE_PLL..AUTO_PERIPH_DPLL == 1.
+        * Then,  in anycase, clear these bits to avoid extra latencies.
+        */
        prcm_block_contents.cm_autoidle_pll =
-                       omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+                       omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE) &
+                       ~OMAP3430_AUTO_PERIPH_DPLL_MASK;
        prcm_block_contents.cm_clksel1_pll =
                        omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL);
        prcm_block_contents.cm_clksel2_pll =
index 8eb3ce1bbfbe3b26ab9612fb015ca366ffd6bdb0..c4d0ae87d62a98596475c74853a6ed0503d6df7f 100644 (file)
@@ -1639,6 +1639,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio1_slaves[] = {
 
 static struct omap_hwmod omap2420_gpio1_hwmod = {
        .name           = "gpio1",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap242x_gpio1_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap242x_gpio1_irqs),
        .main_clk       = "gpios_fck",
@@ -1669,6 +1670,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio2_slaves[] = {
 
 static struct omap_hwmod omap2420_gpio2_hwmod = {
        .name           = "gpio2",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap242x_gpio2_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap242x_gpio2_irqs),
        .main_clk       = "gpios_fck",
@@ -1699,6 +1701,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio3_slaves[] = {
 
 static struct omap_hwmod omap2420_gpio3_hwmod = {
        .name           = "gpio3",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap242x_gpio3_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap242x_gpio3_irqs),
        .main_clk       = "gpios_fck",
@@ -1729,6 +1732,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio4_slaves[] = {
 
 static struct omap_hwmod omap2420_gpio4_hwmod = {
        .name           = "gpio4",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap242x_gpio4_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap242x_gpio4_irqs),
        .main_clk       = "gpios_fck",
@@ -1782,7 +1786,7 @@ static struct omap_hwmod_irq_info omap2420_dma_system_irqs[] = {
 static struct omap_hwmod_addr_space omap2420_dma_system_addrs[] = {
        {
                .pa_start       = 0x48056000,
-               .pa_end         = 0x4a0560ff,
+               .pa_end         = 0x48056fff,
                .flags          = ADDR_TYPE_RT
        },
 };
index e6e3810db77f1036c5237d62f27c161dfdf3acdd..9682dd519f8dd9d1dd0e84a788212c778672cf30 100644 (file)
@@ -1742,6 +1742,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio1_slaves[] = {
 
 static struct omap_hwmod omap2430_gpio1_hwmod = {
        .name           = "gpio1",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap243x_gpio1_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap243x_gpio1_irqs),
        .main_clk       = "gpios_fck",
@@ -1772,6 +1773,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio2_slaves[] = {
 
 static struct omap_hwmod omap2430_gpio2_hwmod = {
        .name           = "gpio2",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap243x_gpio2_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap243x_gpio2_irqs),
        .main_clk       = "gpios_fck",
@@ -1802,6 +1804,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio3_slaves[] = {
 
 static struct omap_hwmod omap2430_gpio3_hwmod = {
        .name           = "gpio3",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap243x_gpio3_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap243x_gpio3_irqs),
        .main_clk       = "gpios_fck",
@@ -1832,6 +1835,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio4_slaves[] = {
 
 static struct omap_hwmod omap2430_gpio4_hwmod = {
        .name           = "gpio4",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap243x_gpio4_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap243x_gpio4_irqs),
        .main_clk       = "gpios_fck",
@@ -1862,6 +1866,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio5_slaves[] = {
 
 static struct omap_hwmod omap2430_gpio5_hwmod = {
        .name           = "gpio5",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap243x_gpio5_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap243x_gpio5_irqs),
        .main_clk       = "gpio5_fck",
@@ -1915,7 +1920,7 @@ static struct omap_hwmod_irq_info omap2430_dma_system_irqs[] = {
 static struct omap_hwmod_addr_space omap2430_dma_system_addrs[] = {
        {
                .pa_start       = 0x48056000,
-               .pa_end         = 0x4a0560ff,
+               .pa_end         = 0x48056fff,
                .flags          = ADDR_TYPE_RT
        },
 };
index b98e2dfcba28c8b7a57f228472205b9266f4464b..909a84de6682d8673d7f04d1fbe47bc745a77b14 100644 (file)
@@ -2141,6 +2141,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio1_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio1_hwmod = {
        .name           = "gpio1",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio1_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio1_irqs),
        .main_clk       = "gpio1_ick",
@@ -2177,6 +2178,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio2_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio2_hwmod = {
        .name           = "gpio2",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio2_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio2_irqs),
        .main_clk       = "gpio2_ick",
@@ -2213,6 +2215,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio3_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio3_hwmod = {
        .name           = "gpio3",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio3_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio3_irqs),
        .main_clk       = "gpio3_ick",
@@ -2249,6 +2252,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio4_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio4_hwmod = {
        .name           = "gpio4",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio4_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio4_irqs),
        .main_clk       = "gpio4_ick",
@@ -2285,6 +2289,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio5_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio5_hwmod = {
        .name           = "gpio5",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio5_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio5_irqs),
        .main_clk       = "gpio5_ick",
@@ -2321,6 +2326,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio6_slaves[] = {
 
 static struct omap_hwmod omap3xxx_gpio6_hwmod = {
        .name           = "gpio6",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .mpu_irqs       = omap3xxx_gpio6_irqs,
        .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_gpio6_irqs),
        .main_clk       = "gpio6_ick",
@@ -2386,7 +2392,7 @@ static struct omap_hwmod_irq_info omap3xxx_dma_system_irqs[] = {
 static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = {
        {
                .pa_start       = 0x48056000,
-               .pa_end         = 0x4a0560ff,
+               .pa_end         = 0x48056fff,
                .flags          = ADDR_TYPE_RT
        },
 };
index 3e88dd3f8ef3f452f814b617d35274a1490a38cb..abc548a0c98dacae4bd6c5fc7d8eb615dde9b4c5 100644 (file)
@@ -885,7 +885,7 @@ static struct omap_hwmod_ocp_if *omap44xx_dma_system_masters[] = {
 static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = {
        {
                .pa_start       = 0x4a056000,
-               .pa_end         = 0x4a0560ff,
+               .pa_end         = 0x4a056fff,
                .flags          = ADDR_TYPE_RT
        },
 };
index 5f2da7565b68b917dd439c4574ab98402ed1790c..4321e79389291c9695e4695d91132f64b48cc803 100644 (file)
@@ -196,11 +196,11 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
                /* No timeout error for debug sources */
        }
 
-       base = ((l3->rt) + (*(omap3_l3_bases[int_type] + err_source)));
-
        /* identify the error source */
        for (err_source = 0; !(status & (1 << err_source)); err_source++)
                                                                        ;
+
+       base = l3->rt + *(omap3_l3_bases[int_type] + err_source);
        error = omap3_l3_readll(base, L3_ERROR_LOG);
 
        if (error) {
index 30af3351c2d68d4f42df644696dbe478cb2dc8f1..49486f522dca55b05fc55f74523a2053f8df54e0 100644 (file)
@@ -89,6 +89,7 @@ static void omap2_init_processor_devices(void)
        if (cpu_is_omap44xx()) {
                _init_omap_device("l3_main_1", &l3_dev);
                _init_omap_device("dsp", &dsp_dev);
+               _init_omap_device("iva", &iva_dev);
        } else {
                _init_omap_device("l3_main", &l3_dev);
        }
index 6fb520999b6e770bb12e376042ef0fc15da5b7ed..0c1552d9d99508c3bc0d2a3aaf4ae5038becc089 100644 (file)
@@ -114,7 +114,6 @@ static int __init _config_common_vdd_data(struct omap_vdd_info *vdd)
        sys_clk_speed /= 1000;
 
        /* Generic voltage parameters */
-       vdd->curr_volt = 1200000;
        vdd->volt_scale = vp_forceupdate_scale_voltage;
        vdd->vp_enabled = false;
 
index 6de0ad0eea654f7c5ef4148005b69ead76871f7b..9cdcca59792455ede51f2046fcf66df898561779 100644 (file)
@@ -711,7 +711,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = {
 static struct regulator_init_data bq24022_init_data = {
        .constraints = {
                .max_uA         = 500000,
-               .valid_ops_mask = REGULATOR_CHANGE_CURRENT,
+               .valid_ops_mask = REGULATOR_CHANGE_CURRENT|REGULATOR_CHANGE_STATUS,
        },
        .num_consumer_supplies  = ARRAY_SIZE(bq24022_consumers),
        .consumer_supplies      = bq24022_consumers,
index b024a8b374394ac2731596ba39bba462309f04a6..c4639502efcac4d236f5752172bfe2f29f7af27f 100644 (file)
 #define GAFR(x)                GPIO_REG(0x54 + (((x) & 0x70) >> 2))
 
 
-#define NR_BUILTIN_GPIO 128
+#define NR_BUILTIN_GPIO                PXA_GPIO_IRQ_NUM
 
 #define gpio_to_bank(gpio)     ((gpio) >> 5)
 #define gpio_to_irq(gpio)      IRQ_GPIO(gpio)
-#define irq_to_gpio(irq)       IRQ_TO_GPIO(irq)
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       int gpio;
+
+       if (irq == IRQ_GPIO0 || irq == IRQ_GPIO1)
+               return irq - IRQ_GPIO0;
+
+       gpio = irq - PXA_GPIO_IRQ_BASE;
+       if (gpio >= 2 && gpio < NR_BUILTIN_GPIO)
+               return gpio;
+
+       return -1;
+}
 
 #ifdef CONFIG_CPU_PXA26x
 /* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
index a4285fc0087841ad0c48902a2ae5d664f1205745..038402404e3932e78c702181c6d62cd4e4d145a7 100644 (file)
@@ -93,9 +93,6 @@
 #define GPIO_2_x_TO_IRQ(x)     (PXA_GPIO_IRQ_BASE + (x))
 #define IRQ_GPIO(x)    (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_x_TO_IRQ(x))
 
-#define IRQ_TO_GPIO_2_x(i)     ((i) - PXA_GPIO_IRQ_BASE)
-#define IRQ_TO_GPIO(i) (((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
-
 /*
  * The following interrupts are for board specific purposes. Since
  * the kernel can only run on one machine at a time, we can re-use
index a72993dde2b301f301a9c4caab8d98dd2f3e1388..9984ef70bd794ff8e5a97ffff07ebc08eebb0988 100644 (file)
@@ -599,7 +599,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = {
 static struct regulator_init_data bq24022_init_data = {
        .constraints = {
                .max_uA         = 500000,
-               .valid_ops_mask = REGULATOR_CHANGE_CURRENT,
+               .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS,
        },
        .num_consumer_supplies  = ARRAY_SIZE(bq24022_consumers),
        .consumer_supplies      = bq24022_consumers,
index 6bde5956358d88ceef7c23641bb92c77e3a44154..a4af8c52d7ee297b49246be5246aa0e055e1c970 100644 (file)
@@ -285,7 +285,7 @@ static inline void pxa25x_init_pm(void) {}
 
 static int pxa25x_set_wake(struct irq_data *d, unsigned int on)
 {
-       int gpio = IRQ_TO_GPIO(d->irq);
+       int gpio = irq_to_gpio(d->irq);
        uint32_t mask = 0;
 
        if (gpio >= 0 && gpio < 85)
index 1cb5d0f9723fb28ea9c5c1dabe441646c3dfcf25..909756eaf4b72a3b32a36f444517d1748604767a 100644 (file)
@@ -345,7 +345,7 @@ static inline void pxa27x_init_pm(void) {}
  */
 static int pxa27x_set_wake(struct irq_data *d, unsigned int on)
 {
-       int gpio = IRQ_TO_GPIO(d->irq);
+       int gpio = irq_to_gpio(d->irq);
        uint32_t mask;
 
        if (gpio >= 0 && gpio < 128)
index 3cdeffc97b4452f7e1abb34c34b02f40f25cbadf..5ec1846aa1d0d13c17b143cd72235919b8bc5f26 100644 (file)
@@ -27,12 +27,14 @@ comment "Tegra board type"
 
 config MACH_HARMONY
        bool "Harmony board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
          Support for nVidia Harmony development platform
 
 config MACH_KAEN
        bool "Kaen board"
        select MACH_SEABOARD
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
          Support for the Kaen version of Seaboard
 
@@ -43,6 +45,7 @@ config MACH_PAZ00
 
 config MACH_SEABOARD
        bool "Seaboard board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
          Support for nVidia Seaboard development platform. It will
         also be included for some of the derivative boards that
index 75c918a86a31d44605b87569ccbe22bda237070d..30e18bc60647b35e78bc914703de41af0ecc8e44 100644 (file)
@@ -34,7 +34,7 @@
 #include <asm/mach/time.h>
 #include <asm/setup.h>
 
-#include <mach/harmony_audio.h>
+#include <mach/tegra_wm8903_pdata.h>
 #include <mach/iomap.h>
 #include <mach/irqs.h>
 #include <mach/sdhci.h>
@@ -67,15 +67,16 @@ static struct platform_device debug_uart = {
        },
 };
 
-static struct harmony_audio_platform_data harmony_audio_pdata = {
+static struct tegra_wm8903_platform_data harmony_audio_pdata = {
        .gpio_spkr_en           = TEGRA_GPIO_SPKR_EN,
        .gpio_hp_det            = TEGRA_GPIO_HP_DET,
+       .gpio_hp_mute           = -1,
        .gpio_int_mic_en        = TEGRA_GPIO_INT_MIC_EN,
        .gpio_ext_mic_en        = TEGRA_GPIO_EXT_MIC_EN,
 };
 
 static struct platform_device harmony_audio_device = {
-       .name   = "tegra-snd-harmony",
+       .name   = "tegra-snd-wm8903",
        .id     = 0,
        .dev    = {
                .platform_data  = &harmony_audio_pdata,
index 76a3f654220f2f012b842b9e2794811fba2a4710..65a1aba6823db6be97b9b87115be7caab4e8f2f9 100644 (file)
@@ -257,7 +257,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 void tegra_gpio_resume(void)
 {
        unsigned long flags;
-       int b, p, i;
+       int b;
+       int p;
 
        local_irq_save(flags);
 
@@ -280,7 +281,8 @@ void tegra_gpio_resume(void)
 void tegra_gpio_suspend(void)
 {
        unsigned long flags;
-       int b, p, i;
+       int b;
+       int p;
 
        local_irq_save(flags);
        for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
diff --git a/arch/arm/mach-tegra/include/mach/harmony_audio.h b/arch/arm/mach-tegra/include/mach/harmony_audio.h
deleted file mode 100644 (file)
index af08650..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/harmony_audio.h
- *
- * Copyright 2011 NVIDIA, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-struct harmony_audio_platform_data {
-       int gpio_spkr_en;
-       int gpio_hp_det;
-       int gpio_int_mic_en;
-       int gpio_ext_mic_en;
-};
diff --git a/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
new file mode 100644 (file)
index 0000000..9d29334
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
+ *
+ * Copyright 2011 NVIDIA, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+struct tegra_wm8903_platform_data {
+       int gpio_spkr_en;
+       int gpio_hp_det;
+       int gpio_hp_mute;
+       int gpio_int_mic_en;
+       int gpio_ext_mic_en;
+};
index 6d7c4eea4dcbcd95a567635667d2ccf557878808..4459470c052de3f97ea29ec138c0a2006787328b 100644 (file)
@@ -1362,14 +1362,15 @@ static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
 {
        unsigned long flags;
        int ret;
+       long new_rate = rate;
 
-       rate = clk_round_rate(c->parent, rate);
-       if (rate < 0)
-               return rate;
+       new_rate = clk_round_rate(c->parent, new_rate);
+       if (new_rate < 0)
+               return new_rate;
 
        spin_lock_irqsave(&c->parent->spinlock, flags);
 
-       c->u.shared_bus_user.rate = rate;
+       c->u.shared_bus_user.rate = new_rate;
        ret = tegra_clk_shared_bus_update(c->parent);
 
        spin_unlock_irqrestore(&c->parent->spinlock, flags);
index af913741e6ec760e775f3028c4304aa1d4b7609a..6e1907fa94f0405a788acd8896b9202a8a4c67c0 100644 (file)
@@ -178,16 +178,15 @@ static struct i2c_board_info __initdata mop500_i2c0_devices[] = {
                .irq            = NOMADIK_GPIO_TO_IRQ(217),
                .platform_data  = &mop500_tc35892_data,
        },
-};
-
-/* I2C0 devices only available prior to HREFv60 */
-static struct i2c_board_info __initdata mop500_i2c0_old_devices[] = {
+       /* I2C0 devices only available prior to HREFv60 */
        {
                I2C_BOARD_INFO("tps61052", 0x33),
                .platform_data  = &mop500_tps61052_data,
        },
 };
 
+#define NUM_PRE_V60_I2C0_DEVICES 1
+
 static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        {
                /* lp5521 LED driver, 1st device */
@@ -425,6 +424,8 @@ static void __init mop500_uart_init(void)
 
 static void __init mop500_init_machine(void)
 {
+       int i2c0_devs;
+
        /*
         * The HREFv60 board removed a GPIO expander and routed
         * all these GPIO pins to the internal GPIO controller
@@ -448,11 +449,11 @@ static void __init mop500_init_machine(void)
 
        platform_device_register(&ab8500_device);
 
-       i2c_register_board_info(0, mop500_i2c0_devices,
-                               ARRAY_SIZE(mop500_i2c0_devices));
-       if (!machine_is_hrefv60())
-               i2c_register_board_info(0, mop500_i2c0_old_devices,
-                                       ARRAY_SIZE(mop500_i2c0_old_devices));
+       i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+       if (machine_is_hrefv60())
+               i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
+
+       i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
        i2c_register_board_info(2, mop500_i2c2_devices,
                                ARRAY_SIZE(mop500_i2c2_devices));
 }
index afe209e1e1f85fb299e9822ea07a49b13cc29ecf..74be05f3e03ac58be921aff208c6f6aa460ab683 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/shm.h>
 #include <linux/sched.h>
 #include <linux/io.h>
+#include <linux/personality.h>
 #include <linux/random.h>
 #include <asm/cputype.h>
 #include <asm/system.h>
@@ -82,7 +83,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
                mm->cached_hole_size = 0;
        }
        /* 8 bits of randomness in 20 address space bits */
-       if (current->flags & PF_RANDOMIZE)
+       if ((current->flags & PF_RANDOMIZE) &&
+           !(current->personality & ADDR_NO_RANDOMIZE))
                addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
index b46eb21f05c7edf8d53c474a54791ea8ea8a922b..bf8a1d1cccb6c33b26412264a2f05228657e49aa 100644 (file)
@@ -390,7 +390,7 @@ ENTRY(cpu_arm920_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
 .globl cpu_arm920_suspend_size
 .equ   cpu_arm920_suspend_size, 4 * 3
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_arm920_do_suspend)
        stmfd   sp!, {r4 - r7, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ PID
index 6a4bdb2c94a7ba0f856bf06c00f95049ab638dc1..0ed85d930c095e3280f7f029973e1530a7fcd4aa 100644 (file)
@@ -404,7 +404,7 @@ ENTRY(cpu_arm926_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
 .globl cpu_arm926_suspend_size
 .equ   cpu_arm926_suspend_size, 4 * 3
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_arm926_do_suspend)
        stmfd   sp!, {r4 - r7, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ PID
index 74483d1977fe788ac2b4b8d42e32952da9e7ed0e..184a9c997e36616dcc6819418d380f9d9e439291 100644 (file)
@@ -171,7 +171,7 @@ ENTRY(cpu_sa1100_set_pte_ext)
 
 .globl cpu_sa1100_suspend_size
 .equ   cpu_sa1100_suspend_size, 4*4
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_sa1100_do_suspend)
        stmfd   sp!, {r4 - r7, lr}
        mrc     p15, 0, r4, c3, c0, 0           @ domain ID
index bfa0c9f611c537c85db433da446f791e2f8ba851..7c99cb4c8e4fb8663158caf9832d6df6e9e27ef4 100644 (file)
@@ -124,7 +124,7 @@ ENTRY(cpu_v6_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
 .globl cpu_v6_suspend_size
 .equ   cpu_v6_suspend_size, 4 * 8
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_v6_do_suspend)
        stmfd   sp!, {r4 - r11, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
index c35618e42f6fcbd7808f36474518aed226dba7e1..babfba09c89ff390deb7ddfd0496e813f442e047 100644 (file)
@@ -211,7 +211,7 @@ cpu_v7_name:
 /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
 .globl cpu_v7_suspend_size
 .equ   cpu_v7_suspend_size, 4 * 8
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_v7_do_suspend)
        stmfd   sp!, {r4 - r11, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
index 63d8b2044e84114c4401c7851e14b659a39821f2..596213699f37ac8a52d580ae70df8303bc344c94 100644 (file)
@@ -417,7 +417,7 @@ ENTRY(cpu_xsc3_set_pte_ext)
 
 .globl cpu_xsc3_suspend_size
 .equ   cpu_xsc3_suspend_size, 4 * 8
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_xsc3_do_suspend)
        stmfd   sp!, {r4 - r10, lr}
        mrc     p14, 0, r4, c6, c0, 0   @ clock configuration, for turbo mode
index 086038cd86abc1e32ffb0c6552d8fdc85c5a3bd2..42af97664c9d844f156789f23a8c1fac7a643b68 100644 (file)
@@ -395,7 +395,7 @@ ENTRY(xscale_dma_a0_map_area)
        teq     r2, #DMA_TO_DEVICE
        beq     xscale_dma_clean_range
        b       xscale_dma_flush_range
-ENDPROC(xscsale_dma_a0_map_area)
+ENDPROC(xscale_dma_a0_map_area)
 
 /*
  *     dma_unmap_area(start, size, dir)
@@ -518,7 +518,7 @@ ENTRY(cpu_xscale_set_pte_ext)
 
 .globl cpu_xscale_suspend_size
 .equ   cpu_xscale_suspend_size, 4 * 7
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_xscale_do_suspend)
        stmfd   sp!, {r4 - r10, lr}
        mrc     p14, 0, r4, c6, c0, 0   @ clock configuration, for turbo mode
index 7a107246fd98849b6f8efe34316d977629f4bef8..6cd6d7f686f639623da2c10b0bcc6e9213d4b4a1 100644 (file)
@@ -295,6 +295,12 @@ static int mxc_gpio_direction_output(struct gpio_chip *chip,
        return 0;
 }
 
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
 int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
 {
        int i, j;
@@ -311,6 +317,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                __raw_writel(~0, port[i].base + GPIO_ISR);
                for (j = port[i].virtual_irq_start;
                        j < port[i].virtual_irq_start + 32; j++) {
+                       irq_set_lockdep_class(j, &gpio_lock_class);
                        irq_set_chip_and_handler(j, &gpio_irq_chip,
                                                 handle_level_irq);
                        set_irq_flags(j, IRQF_VALID);
index 4ddce565b353745d32f31b0023ff1df1ad93f02d..8397a2dd19f2d6caad2adb5824ca13537c8d19fd 100644 (file)
@@ -124,6 +124,8 @@ imx_ssi_fiq_start:
 1:
                @ return from FIQ
                subs    pc, lr, #4
+
+               .align
 imx_ssi_fiq_base:
                .word 0x0
 imx_ssi_fiq_rx_buffer:
index d592b6304b48cf5825b22fe0298d8a2db21b4d52..d15dc47b0e3db50c2c87535aca5f5ff153e4c6b0 100644 (file)
 
 #define PFX "s5p pm: "
 
-/* s3c_pm_check_resume_pin
- *
- * check to see if the pin is configured correctly for sleep mode, and
- * make any necessary adjustments if it is not
-*/
-
-static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
-{
-       /* nothing here yet */
-}
-
 /* s3c_pm_configure_extint
  *
  * configure all external interrupt pins
index e4baf76f374ada34260e37dc88916207ad75abf2..6b733fafe7cda41815d88115fa866d1a6976a71b 100644 (file)
@@ -164,7 +164,6 @@ static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
  */
 static u32 *s3c_pm_runcheck(struct resource *res, u32 *val)
 {
-       void *save_at = phys_to_virt(s3c_sleep_save_phys);
        unsigned long addr;
        unsigned long left;
        void *stkpage;
@@ -192,11 +191,6 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val)
                        goto skip_check;
                }
 
-               if (in_region(ptr, left, save_at, 32*4 )) {
-                       S3C_PMDBG("skipping %08lx, has save block in\n", addr);
-                       goto skip_check;
-               }
-
                /* calculate and check the checksum */
 
                calc = crc32_le(~0, ptr, left);
index d5b58d31903c740d2a0328a67e3d536adcc832d8..5c0a440d6e16741f34f547b7aa6583a16997b5c4 100644 (file)
@@ -214,8 +214,9 @@ void s3c_pm_do_restore_core(struct sleep_save *ptr, int count)
  *
  * print any IRQs asserted at resume time (ie, we woke from)
 */
-static void s3c_pm_show_resume_irqs(int start, unsigned long which,
-                                   unsigned long mask)
+static void __maybe_unused s3c_pm_show_resume_irqs(int start,
+                                                  unsigned long which,
+                                                  unsigned long mask)
 {
        int i;
 
index bbf3da012afdf6ab1233f7b6e0bf9eaa7c96194a..f74695075e641ec72562e1c8194a8220327e8bc8 100644 (file)
@@ -78,6 +78,14 @@ static void vfp_thread_exit(struct thread_info *thread)
        put_cpu();
 }
 
+static void vfp_thread_copy(struct thread_info *thread)
+{
+       struct thread_info *parent = current_thread_info();
+
+       vfp_sync_hwstate(parent);
+       thread->vfpstate = parent->vfpstate;
+}
+
 /*
  * When this function is called with the following 'cmd's, the following
  * is true while this function is being run:
@@ -104,12 +112,17 @@ static void vfp_thread_exit(struct thread_info *thread)
 static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
 {
        struct thread_info *thread = v;
+       u32 fpexc;
+#ifdef CONFIG_SMP
+       unsigned int cpu;
+#endif
 
-       if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
-               u32 fpexc = fmrx(FPEXC);
+       switch (cmd) {
+       case THREAD_NOTIFY_SWITCH:
+               fpexc = fmrx(FPEXC);
 
 #ifdef CONFIG_SMP
-               unsigned int cpu = thread->cpu;
+               cpu = thread->cpu;
 
                /*
                 * On SMP, if VFP is enabled, save the old state in
@@ -134,13 +147,20 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 * old state.
                 */
                fmxr(FPEXC, fpexc & ~FPEXC_EN);
-               return NOTIFY_DONE;
-       }
+               break;
 
-       if (cmd == THREAD_NOTIFY_FLUSH)
+       case THREAD_NOTIFY_FLUSH:
                vfp_thread_flush(thread);
-       else
+               break;
+
+       case THREAD_NOTIFY_EXIT:
                vfp_thread_exit(thread);
+               break;
+
+       case THREAD_NOTIFY_COPY:
+               vfp_thread_copy(thread);
+               break;
+       }
 
        return NOTIFY_DONE;
 }
index ff5b7cf6be4dd8065bffb566065de245a3f4020e..160543dbec7eb1c9725c6edf3ba9259e5fd9bd9d 100644 (file)
@@ -94,6 +94,13 @@ struct tag_ethernet {
 
 #define ETH_INVALID_PHY        0xff
 
+/* board information */
+#define ATAG_BOARDINFO 0x54410008
+
+struct tag_boardinfo {
+       u32     board_number;
+};
+
 struct tag {
        struct tag_header hdr;
        union {
@@ -102,6 +109,7 @@ struct tag {
                struct tag_cmdline cmdline;
                struct tag_clock clock;
                struct tag_ethernet ethernet;
+               struct tag_boardinfo boardinfo;
        } u;
 };
 
@@ -128,6 +136,7 @@ extern struct tag *bootloader_tags;
 
 extern resource_size_t fbmem_start;
 extern resource_size_t fbmem_size;
+extern u32 board_number;
 
 void setup_processor(void);
 
index 5c7083916c33c14792728da5a08295476daebc17..bb0974cce4accf3c0a0d01cdfce08d7533d86ab7 100644 (file)
@@ -390,6 +390,21 @@ static int __init parse_tag_clock(struct tag *tag)
 }
 __tagtable(ATAG_CLOCK, parse_tag_clock);
 
+/*
+ * The board_number correspond to the bd->bi_board_number in U-Boot. This
+ * parameter is only available during initialisation and can be used in some
+ * kind of board identification.
+ */
+u32 __initdata board_number;
+
+static int __init parse_tag_boardinfo(struct tag *tag)
+{
+       board_number = tag->u.boardinfo.board_number;
+
+       return 0;
+}
+__tagtable(ATAG_BOARDINFO, parse_tag_boardinfo);
+
 /*
  * Scan the tag table for this tag, and call its parse function. The
  * tag table is built by the linker from all the __tagtable
index b91b2044af9c9660210bb9efd5f11ab60a08dcbc..7aa25756412f16299b69cccfcd1d1c9851aaaec7 100644 (file)
@@ -95,28 +95,6 @@ void _exception(long signr, struct pt_regs *regs, int code,
        info.si_code = code;
        info.si_addr = (void __user *)addr;
        force_sig_info(signr, &info, current);
-
-       /*
-        * Init gets no signals that it doesn't have a handler for.
-        * That's all very well, but if it has caused a synchronous
-        * exception and we ignore the resulting signal, it will just
-        * generate the same exception over and over again and we get
-        * nowhere.  Better to kill it and let the kernel panic.
-        */
-       if (is_global_init(current)) {
-               __sighandler_t handler;
-
-               spin_lock_irq(&current->sighand->siglock);
-               handler = current->sighand->action[signr-1].sa.sa_handler;
-               spin_unlock_irq(&current->sighand->siglock);
-               if (handler == SIG_DFL) {
-                       /* init has generated a synchronous exception
-                          and it doesn't have a handler for the signal */
-                       printk(KERN_CRIT "init has generated signal %ld "
-                              "but has no handler for it\n", signr);
-                       do_exit(signr);
-               }
-       }
 }
 
 asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
index 442f08c5e6415f198df5c7843b69d144fa336ed6..86925fd6ea5bb3daf34eb039858ff69f2bb02ec6 100644 (file)
@@ -35,22 +35,30 @@ void at32_clk_register(struct clk *clk)
        spin_unlock(&clk_list_lock);
 }
 
-struct clk *clk_get(struct device *dev, const char *id)
+static struct clk *__clk_get(struct device *dev, const char *id)
 {
        struct clk *clk;
 
-       spin_lock(&clk_list_lock);
-
        list_for_each_entry(clk, &at32_clock_list, list) {
                if (clk->dev == dev && strcmp(id, clk->name) == 0) {
-                       spin_unlock(&clk_list_lock);
                        return clk;
                }
        }
 
-       spin_unlock(&clk_list_lock);
        return ERR_PTR(-ENOENT);
 }
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       struct clk *clk;
+
+       spin_lock(&clk_list_lock);
+       clk = __clk_get(dev, id);
+       spin_unlock(&clk_list_lock);
+
+       return clk;
+}
+
 EXPORT_SYMBOL(clk_get);
 
 void clk_put(struct clk *clk)
@@ -257,15 +265,15 @@ static int clk_show(struct seq_file *s, void *unused)
        spin_lock(&clk_list_lock);
 
        /* show clock tree as derived from the three oscillators */
-       clk = clk_get(NULL, "osc32k");
+       clk = __clk_get(NULL, "osc32k");
        dump_clock(clk, &r);
        clk_put(clk);
 
-       clk = clk_get(NULL, "osc0");
+       clk = __clk_get(NULL, "osc0");
        dump_clock(clk, &r);
        clk_put(clk);
 
-       clk = clk_get(NULL, "osc1");
+       clk = __clk_get(NULL, "osc1");
        dump_clock(clk, &r);
        clk_put(clk);
 
index 47ba4b9b6db16b5852a0f857236e3d73e5349e75..fbc2aeaebddbde6023bb4853814f2e598436a1bd 100644 (file)
@@ -61,34 +61,34 @@ struct eic {
 static struct eic *nmi_eic;
 static bool nmi_enabled;
 
-static void eic_ack_irq(struct irq_chip *d)
+static void eic_ack_irq(struct irq_data *d)
 {
-       struct eic *eic = irq_data_get_irq_chip_data(data);
+       struct eic *eic = irq_data_get_irq_chip_data(d);
        eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_mask_irq(struct irq_chip *d)
+static void eic_mask_irq(struct irq_data *d)
 {
-       struct eic *eic = irq_data_get_irq_chip_data(data);
+       struct eic *eic = irq_data_get_irq_chip_data(d);
        eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_mask_ack_irq(struct irq_chip *d)
+static void eic_mask_ack_irq(struct irq_data *d)
 {
-       struct eic *eic = irq_data_get_irq_chip_data(data);
+       struct eic *eic = irq_data_get_irq_chip_data(d);
        eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
        eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_unmask_irq(struct irq_chip *d)
+static void eic_unmask_irq(struct irq_data *d)
 {
-       struct eic *eic = irq_data_get_irq_chip_data(data);
+       struct eic *eic = irq_data_get_irq_chip_data(d);
        eic_writel(eic, IER, 1 << (d->irq - eic->first_irq));
 }
 
-static int eic_set_irq_type(struct irq_chip *d, unsigned int flow_type)
+static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type)
 {
-       struct eic *eic = irq_data_get_irq_chip_data(data);
+       struct eic *eic = irq_data_get_irq_chip_data(d);
        unsigned int irq = d->irq;
        unsigned int i = irq - eic->first_irq;
        u32 mode, edge, level;
@@ -191,7 +191,7 @@ static int __init eic_probe(struct platform_device *pdev)
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int_irq = platform_get_irq(pdev, 0);
-       if (!regs || !int_irq) {
+       if (!regs || (int)int_irq <= 0) {
                dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
                return -ENXIO;
        }
index f308e1ddc629310ef882c04361b92ae4cef51622..2e0aa853a4bcecec88339d30b22d112114edc5be 100644 (file)
@@ -257,7 +257,7 @@ static void gpio_irq_mask(struct irq_data *d)
        pio_writel(pio, IDR, 1 << (gpio & 0x1f));
 }
 
-static void gpio_irq_unmask(struct irq_data *d))
+static void gpio_irq_unmask(struct irq_data *d)
 {
        unsigned                gpio = irq_to_gpio(d->irq);
        struct pio_device       *pio = &pio_dev[gpio >> 5];
index 17503b0ed6c9b3f5865406fb0d5f44241ce6bab7..f868f4ce761ba6f37a7b63617fba356410263ff1 100644 (file)
@@ -53,7 +53,7 @@ cpu_enter_idle:
        st.w    r8[TI_flags], r9
        unmask_interrupts
        sleep   CPU_SLEEP_IDLE
-       .size   cpu_idle_sleep, . - cpu_idle_sleep
+       .size   cpu_enter_idle, . - cpu_enter_idle
 
        /*
         * Common return path for PM functions that don't run from
index 19e2c7c3e63ac41bf62f2e55a4db10d6bf97a13f..44bd0cced7256dc1a04eb78242b8ad5fb8ca882c 100644 (file)
  * Force strict CPU ordering.
  */
 #define nop()  __asm__ __volatile__ ("nop;\n\t" : : )
-#define mb()   __asm__ __volatile__ (""   : : : "memory")
-#define rmb()  __asm__ __volatile__ (""   : : : "memory")
-#define wmb()  __asm__ __volatile__ (""   : : : "memory")
-#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
-#define read_barrier_depends()                 do { } while(0)
+#define smp_mb()  mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define smp_read_barrier_depends()     read_barrier_depends()
 
 #ifdef CONFIG_SMP
 asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value);
@@ -37,16 +37,16 @@ asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr,
                                        unsigned long new, unsigned long old);
 
 #ifdef __ARCH_SYNC_CORE_DCACHE
-# define smp_mb()      do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0)
-# define smp_rmb()     do { barrier(); smp_check_barrier(); } while (0)
-# define smp_wmb()     do { barrier(); smp_mark_barrier(); } while (0)
-#define smp_read_barrier_depends()     do { barrier(); smp_check_barrier(); } while (0)
-
+/* Force Core data cache coherence */
+# define mb()  do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0)
+# define rmb() do { barrier(); smp_check_barrier(); } while (0)
+# define wmb() do { barrier(); smp_mark_barrier(); } while (0)
+# define read_barrier_depends()        do { barrier(); smp_check_barrier(); } while (0)
 #else
-# define smp_mb()      barrier()
-# define smp_rmb()     barrier()
-# define smp_wmb()     barrier()
-#define smp_read_barrier_depends()     barrier()
+# define mb()  barrier()
+# define rmb() barrier()
+# define wmb() barrier()
+# define read_barrier_depends()        do { } while (0)
 #endif
 
 static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
@@ -99,10 +99,10 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 
 #else /* !CONFIG_SMP */
 
-#define smp_mb()       barrier()
-#define smp_rmb()      barrier()
-#define smp_wmb()      barrier()
-#define smp_read_barrier_depends()     do { } while(0)
+#define mb()   barrier()
+#define rmb()  barrier()
+#define wmb()  barrier()
+#define read_barrier_depends() do { } while (0)
 
 struct __xchg_dummy {
        unsigned long a[100];
index cdbe075de1dc6841411310ef481ed26a4210c2f2..8b81dc04488aa6864aeb23236cadb65cc1cda676 100644 (file)
@@ -268,7 +268,7 @@ void disable_gptimers(uint16_t mask)
        _disable_gptimers(mask);
        for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i)
                if (mask & (1 << i))
-                       group_regs[BFIN_TIMER_OCTET(i)]->status |= trun_mask[i];
+                       group_regs[BFIN_TIMER_OCTET(i)]->status = trun_mask[i];
        SSYNC();
 }
 EXPORT_SYMBOL(disable_gptimers);
index 8c9a43daf80fad1f4ecaec62f25ea0778cc2be94..cdb4beb6bc8fc9507bf0531317b8b834eca9d4c8 100644 (file)
@@ -206,8 +206,14 @@ irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *evt = dev_id;
        smp_mb();
-       evt->event_handler(evt);
+       /*
+        * We want to ACK before we handle so that we can handle smaller timer
+        * intervals.  This way if the timer expires again while we're handling
+        * things, we're more likely to see that 2nd int rather than swallowing
+        * it by ACKing the int at the end of this handler.
+        */
        bfin_gptmr0_ack();
+       evt->event_handler(evt);
        return IRQ_HANDLED;
 }
 
index 6e17a265c4d3158761450463b3c5a66e63a39bab..8bce5ed031e448ed0a51d9e77c947864eed2e2bf 100644 (file)
@@ -109,10 +109,23 @@ static void ipi_flush_icache(void *info)
        struct blackfin_flush_data *fdata = info;
 
        /* Invalidate the memory holding the bounds of the flushed region. */
-       invalidate_dcache_range((unsigned long)fdata,
-               (unsigned long)fdata + sizeof(*fdata));
+       blackfin_dcache_invalidate_range((unsigned long)fdata,
+                                        (unsigned long)fdata + sizeof(*fdata));
+
+       /* Make sure all write buffers in the data side of the core
+        * are flushed before trying to invalidate the icache.  This
+        * needs to be after the data flush and before the icache
+        * flush so that the SSYNC does the right thing in preventing
+        * the instruction prefetcher from hitting things in cached
+        * memory at the wrong time -- it runs much further ahead than
+        * the pipeline.
+        */
+       SSYNC();
 
-       flush_icache_range(fdata->start, fdata->end);
+       /* ipi_flaush_icache is invoked by generic flush_icache_range,
+        * so call blackfin arch icache flush directly here.
+        */
+       blackfin_icache_flush_range(fdata->start, fdata->end);
 }
 
 static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
index 26d851d385bb190a81f271f49fe89c74778e3c06..29e17907d9f2c2af079df6e5b8e0b032de792562 100644 (file)
 #define __NR_fanotify_init     337
 #define __NR_fanotify_mark     338
 #define __NR_prlimit64         339
+#define __NR_name_to_handle_at 340
+#define __NR_open_by_handle_at 341
+#define __NR_clock_adjtime     342
+#define __NR_syncfs            343
 
 #ifdef __KERNEL__
 
-#define NR_syscalls            340
+#define NR_syscalls            344
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 1559dea36e5581f62bf2d8b4b1fe6c6da37308f4..1359ee659574135d440deea4495728c1cbb872d2 100644 (file)
@@ -750,4 +750,8 @@ sys_call_table:
        .long sys_fanotify_init
        .long sys_fanotify_mark
        .long sys_prlimit64
+       .long sys_name_to_handle_at     /* 340 */
+       .long sys_open_by_handle_at
+       .long sys_clock_adjtime
+       .long sys_syncfs
 
index 79b1ed198c070dd40dbb3cf4f03dd6f24b79cb71..9b8393d8adb89dae4ada43f66c6d63c8670589f6 100644 (file)
@@ -358,6 +358,10 @@ ENTRY(sys_call_table)
        .long sys_fanotify_init
        .long sys_fanotify_mark
        .long sys_prlimit64
+       .long sys_name_to_handle_at     /* 340 */
+       .long sys_open_by_handle_at
+       .long sys_clock_adjtime
+       .long sys_syncfs
 
        .rept NR_syscalls-(.-sys_call_table)/4
                .long sys_ni_syscall
index 02b7a03e422681032b1a62ebf45183e1ed629b21..8b3db1c587fcad15de15d585d33d66534ca4b00a 100644 (file)
@@ -300,6 +300,8 @@ void __init paging_init(void)
                zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT;
                free_area_init_node(i, zones_size,
                                    m68k_memory[i].addr >> PAGE_SHIFT, NULL);
+               if (node_present_pages(i))
+                       node_set_state(i, N_NORMAL_MEMORY);
        }
 }
 
index 851b3bf6e962eb3b6e95d5459645f5dfc4ea80b6..eccdefe70d4e4ba1b4874df00228faff583e948b 100644 (file)
@@ -6,7 +6,6 @@ config MICROBLAZE
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
-       select USB_ARCH_HAS_EHCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB
index b7ed8d7a9b33a10e784722a3fa5b8a55f7eabbcb..b1d126258dee10612054ac3bb1a472c562b37cbc 100644 (file)
@@ -266,8 +266,10 @@ static void __init setup_bootmem(void)
        }
        memset(pfnnid_map, 0xff, sizeof(pfnnid_map));
 
-       for (i = 0; i < npmem_ranges; i++)
+       for (i = 0; i < npmem_ranges; i++) {
+               node_set_state(i, N_NORMAL_MEMORY);
                node_set_online(i);
+       }
 #endif
 
        /*
index b6ff882f695bbac53e95b2f6b1a1a00a9bf97ac6..8f4d50b0adfa9ce21bf8dd68158df455ef242af3 100644 (file)
@@ -209,7 +209,7 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
        depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-                  PPC_85xx || PPC_86xx || PPC_PSERIES || 44x || 40x
+                  (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
 
 config PPC_DCR_NATIVE
        bool
index 6b6dc20b0bebab9b1154e7cd5bab13ebd669c85a..bdf0563ba423886a5cde9ff2a63a47e8a3365604 100644 (file)
@@ -393,8 +393,8 @@ typedef struct fec {
        uint    fec_addr_low;           /* lower 32 bits of station address     */
        ushort  fec_addr_high;          /* upper 16 bits of station address     */
        ushort  res1;                   /* reserved                             */
-       uint    fec_hash_table_high;    /* upper 32-bits of hash table          */
-       uint    fec_hash_table_low;     /* lower 32-bits of hash table          */
+       uint    fec_grp_hash_table_high;        /* upper 32-bits of hash table          */
+       uint    fec_grp_hash_table_low; /* lower 32-bits of hash table          */
        uint    fec_r_des_start;        /* beginning of Rx descriptor ring      */
        uint    fec_x_des_start;        /* beginning of Tx descriptor ring      */
        uint    fec_r_buff_size;        /* Rx buffer size                       */
index be3cdf9134ce8727b9a7787250fb6ba3dfdb8e44..1833d1a07e797eab6c9f174585b42e456d19f559 100644 (file)
@@ -382,10 +382,12 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_E500_2        (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
            CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | \
            CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
-#define CPU_FTRS_E500MC        (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
-           CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \
+#define CPU_FTRS_E500MC        (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
            CPU_FTR_DBELL)
+#define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
+           CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
+           CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
 #define CPU_FTRS_GENERIC_32    (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
@@ -435,11 +437,15 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_COMPATIBLE    (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2)
 
 #ifdef __powerpc64__
+#ifdef CONFIG_PPC_BOOK3E
+#define CPU_FTRS_POSSIBLE      (CPU_FTRS_E5500)
+#else
 #define CPU_FTRS_POSSIBLE      \
            (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |        \
            CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 |       \
            CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T |           \
            CPU_FTR_1T_SEGMENT | CPU_FTR_VSX)
+#endif
 #else
 enum {
        CPU_FTRS_POSSIBLE =
@@ -473,16 +479,21 @@ enum {
 #endif
 #ifdef CONFIG_E500
            CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC |
+           CPU_FTRS_E5500 |
 #endif
            0,
 };
 #endif /* __powerpc64__ */
 
 #ifdef __powerpc64__
+#ifdef CONFIG_PPC_BOOK3E
+#define CPU_FTRS_ALWAYS                (CPU_FTRS_E5500)
+#else
 #define CPU_FTRS_ALWAYS                \
            (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &        \
            CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_POWER6 &       \
            CPU_FTRS_POWER7 & CPU_FTRS_CELL & CPU_FTRS_PA6T & CPU_FTRS_POSSIBLE)
+#endif
 #else
 enum {
        CPU_FTRS_ALWAYS =
@@ -513,6 +524,7 @@ enum {
 #endif
 #ifdef CONFIG_E500
            CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC &
+           CPU_FTRS_E5500 &
 #endif
            CPU_FTRS_POSSIBLE,
 };
index 811f04ac3660842baf72973b3786c3d8f9b92c6c..8d1569c290428e82db7d03cec9bca66c66dcf35b 100644 (file)
@@ -162,7 +162,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
  * on platforms where such control is possible.
  */
 #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\
-       defined(CONFIG_KPROBES)
+       defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE)
 #define PAGE_KERNEL_TEXT       PAGE_KERNEL_X
 #else
 #define PAGE_KERNEL_TEXT       PAGE_KERNEL_ROX
index ae9c899c8a6d119526ded6d78f883c6fdf452c88..d12b11d7641e662286d3ef1d2a3e306a352388b0 100644 (file)
@@ -60,7 +60,7 @@
  *
  * Obviously, the GART is not cache coherent and so any change to it
  * must be flushed to memory (or maybe just make the GART space non
- * cachable). AGP memory itself does't seem to be cache coherent neither.
+ * cachable). AGP memory itself doesn't seem to be cache coherent neither.
  *
  * In order to invalidate the GART (which is probably necessary to inval
  * the bridge internal TLBs), the following sequence has to be written,
index c9b68d07ac4fca3cdd8996e8a43d850034efb407..b9602ee06deb11ee4c80c8eeeb63a2757f587841 100644 (file)
@@ -1973,7 +1973,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x80240000,
                .cpu_name               = "e5500",
-               .cpu_features           = CPU_FTRS_E500MC,
+               .cpu_features           = CPU_FTRS_E5500,
                .cpu_user_features      = COMMON_USER_BOOKE,
                .mmu_features           = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
                        MMU_FTR_USE_TLBILX,
index 3d3d416339dd1294ae31380ce0c8474c6eaa3b52..5b5e1f002a8ea2ef2053bb16ba20e1e110edd348 100644 (file)
@@ -163,7 +163,7 @@ static void crash_kexec_prepare_cpus(int cpu)
 }
 
 /* wait for all the CPUs to hit real mode but timeout if they don't come in */
-#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP)
+#ifdef CONFIG_PPC_STD_MMU_64
 static void crash_kexec_wait_realmode(int cpu)
 {
        unsigned int msecs;
@@ -188,9 +188,7 @@ static void crash_kexec_wait_realmode(int cpu)
        }
        mb();
 }
-#else
-static inline void crash_kexec_wait_realmode(int cpu) {}
-#endif
+#endif /* CONFIG_PPC_STD_MMU_64 */
 
 /*
  * This function will be called by secondary cpus or by kexec cpu
@@ -235,7 +233,9 @@ void crash_kexec_secondary(struct pt_regs *regs)
        crash_ipi_callback(regs);
 }
 
-#else
+#else  /* ! CONFIG_SMP */
+static inline void crash_kexec_wait_realmode(int cpu) {}
+
 static void crash_kexec_prepare_cpus(int cpu)
 {
        /*
@@ -255,7 +255,7 @@ void crash_kexec_secondary(struct pt_regs *regs)
 {
        cpus_in_sr = CPU_MASK_NONE;
 }
-#endif
+#endif /* CONFIG_SMP */
 
 /*
  * Register a function to be called on shutdown.  Only use this if you
index c00d4ca1ee157fc995629825b95af4b8b232a5bb..28581f1ad2c08a8494502e2335cfeef2a295577e 100644 (file)
@@ -527,7 +527,7 @@ static int ibmebus_bus_pm_resume_noirq(struct device *dev)
 
 #endif /* !CONFIG_SUSPEND */
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 
 static int ibmebus_bus_pm_freeze(struct device *dev)
 {
@@ -665,7 +665,7 @@ static int ibmebus_bus_pm_restore_noirq(struct device *dev)
        return ret;
 }
 
-#else /* !CONFIG_HIBERNATION */
+#else /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #define ibmebus_bus_pm_freeze          NULL
 #define ibmebus_bus_pm_thaw            NULL
@@ -676,7 +676,7 @@ static int ibmebus_bus_pm_restore_noirq(struct device *dev)
 #define ibmebus_bus_pm_poweroff_noirq  NULL
 #define ibmebus_bus_pm_restore_noirq   NULL
 
-#endif /* !CONFIG_HIBERNATION */
+#endif /* !CONFIG_HIBERNATE_CALLBACKS */
 
 static struct dev_pm_ops ibmebus_bus_dev_pm_ops = {
        .prepare = ibmebus_bus_pm_prepare,
index c834757bebc07663ba44f2c779f210a4f308637d..2b97b80d6d7d65911f951276eec81029cda748e6 100644 (file)
@@ -330,9 +330,11 @@ void __init find_legacy_serial_ports(void)
                if (!parent)
                        continue;
                if (of_match_node(legacy_serial_parents, parent) != NULL) {
-                       index = add_legacy_soc_port(np, np);
-                       if (index >= 0 && np == stdout)
-                               legacy_serial_console = index;
+                       if (of_device_is_available(np)) {
+                               index = add_legacy_soc_port(np, np);
+                               if (index >= 0 && np == stdout)
+                                       legacy_serial_console = index;
+                       }
                }
                of_node_put(parent);
        }
index c4063b7f49a0e5536ac441834a755cbe5840a7dd..822f63008ae11642b570986c7faf8ca61478ae10 100644 (file)
@@ -398,6 +398,25 @@ static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
        return 0;
 }
 
+static u64 check_and_compute_delta(u64 prev, u64 val)
+{
+       u64 delta = (val - prev) & 0xfffffffful;
+
+       /*
+        * POWER7 can roll back counter values, if the new value is smaller
+        * than the previous value it will cause the delta and the counter to
+        * have bogus values unless we rolled a counter over.  If a coutner is
+        * rolled back, it will be smaller, but within 256, which is the maximum
+        * number of events to rollback at once.  If we dectect a rollback
+        * return 0.  This can lead to a small lack of precision in the
+        * counters.
+        */
+       if (prev > val && (prev - val) < 256)
+               delta = 0;
+
+       return delta;
+}
+
 static void power_pmu_read(struct perf_event *event)
 {
        s64 val, delta, prev;
@@ -416,10 +435,11 @@ static void power_pmu_read(struct perf_event *event)
                prev = local64_read(&event->hw.prev_count);
                barrier();
                val = read_pmc(event->hw.idx);
+               delta = check_and_compute_delta(prev, val);
+               if (!delta)
+                       return;
        } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
 
-       /* The counters are only 32 bits wide */
-       delta = (val - prev) & 0xfffffffful;
        local64_add(delta, &event->count);
        local64_sub(delta, &event->hw.period_left);
 }
@@ -449,8 +469,9 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
                val = (event->hw.idx == 5) ? pmc5 : pmc6;
                prev = local64_read(&event->hw.prev_count);
                event->hw.idx = 0;
-               delta = (val - prev) & 0xfffffffful;
-               local64_add(delta, &event->count);
+               delta = check_and_compute_delta(prev, val);
+               if (delta)
+                       local64_add(delta, &event->count);
        }
 }
 
@@ -458,14 +479,16 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
                                  unsigned long pmc5, unsigned long pmc6)
 {
        struct perf_event *event;
-       u64 val;
+       u64 val, prev;
        int i;
 
        for (i = 0; i < cpuhw->n_limited; ++i) {
                event = cpuhw->limited_counter[i];
                event->hw.idx = cpuhw->limited_hwidx[i];
                val = (event->hw.idx == 5) ? pmc5 : pmc6;
-               local64_set(&event->hw.prev_count, val);
+               prev = local64_read(&event->hw.prev_count);
+               if (check_and_compute_delta(prev, val))
+                       local64_set(&event->hw.prev_count, val);
                perf_event_update_userpage(event);
        }
 }
@@ -1197,7 +1220,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
 
        /* we don't have to worry about interrupts here */
        prev = local64_read(&event->hw.prev_count);
-       delta = (val - prev) & 0xfffffffful;
+       delta = check_and_compute_delta(prev, val);
        local64_add(delta, &event->count);
 
        /*
index 55613e33e263ac7abb3b1d478f4a27bb9912b86f..a6ae1cfad86ce86040553fa94346ad2043c3a0bb 100644 (file)
@@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
        if (data && !(data & DABR_TRANSLATION))
                return -EIO;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
+       if (ptrace_get_breakpoints(task) < 0)
+               return -ESRCH;
+
        bp = thread->ptrace_bps[0];
        if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
                if (bp) {
                        unregister_hw_breakpoint(bp);
                        thread->ptrace_bps[0] = NULL;
                }
+               ptrace_put_breakpoints(task);
                return 0;
        }
        if (bp) {
@@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
                                        (DABR_DATA_WRITE | DABR_DATA_READ),
                                                        &attr.bp_type);
                ret =  modify_user_hw_breakpoint(bp, &attr);
-               if (ret)
+               if (ret) {
+                       ptrace_put_breakpoints(task);
                        return ret;
+               }
                thread->ptrace_bps[0] = bp;
+               ptrace_put_breakpoints(task);
                thread->dabr = data;
                return 0;
        }
@@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
                                                        ptrace_triggered, task);
        if (IS_ERR(bp)) {
                thread->ptrace_bps[0] = NULL;
+               ptrace_put_breakpoints(task);
                return PTR_ERR(bp);
        }
 
+       ptrace_put_breakpoints(task);
+
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
        /* Move contents to the DABR register */
index 375480c56eb9fd6699c90e385dd1877affb3d052..f33acfd872ad31ef73df610b07a507d2e6bb78a1 100644 (file)
@@ -229,6 +229,9 @@ static u64 scan_dispatch_log(u64 stop_tb)
        u64 stolen = 0;
        u64 dtb;
 
+       if (!dtl)
+               return 0;
+
        if (i == vpa->dtl_idx)
                return 0;
        while (i < vpa->dtl_idx) {
index a830c5e806577b4c3f443e6617b3964dbf8ae62f..bc5f0dc6ae1e7686f7dd7a10823025d0e138fa13 100644 (file)
@@ -842,6 +842,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
        mpic_setup_this_cpu();
 }
 
+#ifdef CONFIG_PPC64
 #ifdef CONFIG_HOTPLUG_CPU
 static int smp_core99_cpu_notify(struct notifier_block *self,
                                 unsigned long action, void *hcpu)
@@ -879,7 +880,6 @@ static struct notifier_block __cpuinitdata smp_core99_cpu_nb = {
 
 static void __init smp_core99_bringup_done(void)
 {
-#ifdef CONFIG_PPC64
        extern void g5_phy_disable_cpu1(void);
 
        /* Close i2c bus if it was used for tb sync */
@@ -894,14 +894,14 @@ static void __init smp_core99_bringup_done(void)
                set_cpu_present(1, false);
                g5_phy_disable_cpu1();
        }
-#endif /* CONFIG_PPC64 */
-
 #ifdef CONFIG_HOTPLUG_CPU
        register_cpu_notifier(&smp_core99_cpu_nb);
 #endif
+
        if (ppc_md.progress)
                ppc_md.progress("smp_core99_bringup_done", 0x349);
 }
+#endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_HOTPLUG_CPU
 
@@ -975,7 +975,9 @@ static void pmac_cpu_die(void)
 struct smp_ops_t core99_smp_ops = {
        .message_pass   = smp_mpic_message_pass,
        .probe          = smp_core99_probe,
+#ifdef CONFIG_PPC64
        .bringup_done   = smp_core99_bringup_done,
+#endif
        .kick_cpu       = smp_core99_kick_cpu,
        .setup_cpu      = smp_core99_setup_cpu,
        .give_timebase  = smp_core99_give_timebase,
index 000724149089c032c45e375b30a0128e449d6e41..6c42cfde8415f31dacd0a981cee09535da581667 100644 (file)
@@ -287,14 +287,22 @@ static int alloc_dispatch_logs(void)
        int cpu, ret;
        struct paca_struct *pp;
        struct dtl_entry *dtl;
+       struct kmem_cache *dtl_cache;
 
        if (!firmware_has_feature(FW_FEATURE_SPLPAR))
                return 0;
 
+       dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
+                                               DISPATCH_LOG_BYTES, 0, NULL);
+       if (!dtl_cache) {
+               pr_warn("Failed to create dispatch trace log buffer cache\n");
+               pr_warn("Stolen time statistics will be unreliable\n");
+               return 0;
+       }
+
        for_each_possible_cpu(cpu) {
                pp = &paca[cpu];
-               dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL,
-                                  cpu_to_node(cpu));
+               dtl = kmem_cache_alloc(dtl_cache, GFP_KERNEL);
                if (!dtl) {
                        pr_warn("Failed to allocate dispatch trace log for cpu %d\n",
                                cpu);
index f8f7f28c6343682bc9b00ac7f4a754fe1d00cc47..68ca9290df9451886e74d24fa4834c15780979f5 100644 (file)
@@ -324,6 +324,11 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
        struct resource rsrc;
        const int *bus_range;
 
+       if (!of_device_is_available(dev)) {
+               pr_warning("%s: disabled\n", dev->full_name);
+               return -ENODEV;
+       }
+
        pr_debug("Adding PCI host bridge %s\n", dev->full_name);
 
        /* Fetch host bridge registers address */
index 14232d57369c4de4f373f76e095ec95bb559345e..49798532b477b8630c77a203dfb76c62ad3caf46 100644 (file)
@@ -1457,7 +1457,6 @@ int fsl_rio_setup(struct platform_device *dev)
        port->ops = ops;
        port->priv = priv;
        port->phys_efptr = 0x100;
-       rio_register_mport(port);
 
        priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
        rio_regs_win = priv->regs_win;
@@ -1504,6 +1503,9 @@ int fsl_rio_setup(struct platform_device *dev)
        dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
                        port->sys_size ? 65536 : 256);
 
+       if (rio_register_mport(port))
+               goto err;
+
        if (port->host_deviceid >= 0)
                out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
                        RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
index 975e3ab13cb5477b29ac4ffd504d34e6cacd4325..8b16c479585b271db83330e68529634e5e5e4735 100644 (file)
@@ -76,7 +76,7 @@ static void prng_seed(int nbytes)
 
        /* Add the entropy */
        while (nbytes >= 8) {
-               *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+               *((__u64 *)parm_block) ^= *((__u64 *)(buf+i));
                prng_add_entropy();
                i += 8;
                nbytes -= 8;
index 7e9d30d567b0ab21265b669f1f343018d10de080..ab0e041ac54cf2b17fc0b631bf0ed6cd4f59fd53 100644 (file)
@@ -48,10 +48,10 @@ sie_irq_handler:
        tm      __TI_flags+7(%r2),_TIF_EXIT_SIE
        jz      0f
        larl    %r2,sie_exit                    # work pending, leave sie
-       stg     %r2,__LC_RETURN_PSW+8
+       stg     %r2,SPI_PSW+8(0,%r15)
        br      %r14
 0:     larl    %r2,sie_reenter                 # re-enter with guest id
-       stg     %r2,__LC_RETURN_PSW+8
+       stg     %r2,SPI_PSW+8(0,%r15)
 1:     br      %r14
 
 /*
index 9217e332b1183a061fd5ca8423e811d8692627e3..ab988135e5c682a90370f998d5d72956fd40961c 100644 (file)
@@ -543,7 +543,6 @@ static void pfault_interrupt(unsigned int ext_int_code,
        struct task_struct *tsk;
        __u16 subcode;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
        /*
         * Get the external interruption subcode & pfault
         * initial/completion signal bit. VM stores this 
@@ -553,14 +552,15 @@ static void pfault_interrupt(unsigned int ext_int_code,
        subcode = ext_int_code >> 16;
        if ((subcode & 0xff00) != __SUBCODE_MASK)
                return;
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
 
        /*
         * Get the token (= address of the task structure of the affected task).
         */
 #ifdef CONFIG_64BIT
-       tsk = *(struct task_struct **) param64;
+       tsk = (struct task_struct *) param64;
 #else
-       tsk = *(struct task_struct **) param32;
+       tsk = (struct task_struct *) param32;
 #endif
 
        if (subcode & 0x0080) {
index 122ffbd08ce016e4c87d744adcdf9b9cbf2c3c7f..0607e4b14b2742798e36b957c7f17e1451bc0bf0 100644 (file)
@@ -24,12 +24,13 @@ static void change_page_attr(unsigned long addr, int numpages,
                        WARN_ON_ONCE(1);
                        continue;
                }
-               ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE);
+               ptep = pte_offset_kernel(pmdp, addr);
 
                pte = *ptep;
                pte = set(pte);
-               ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep);
+               ptep_invalidate(&init_mm, addr, ptep);
                *ptep = pte;
+               addr += PAGE_SIZE;
        }
 }
 
index 2130ca674e9bdd1674a22d339011a7f364bf0ec5..3d7b209b2178cc63c520975a35d4146c99042ba4 100644 (file)
@@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child)
 
        set_tsk_thread_flag(child, TIF_SINGLESTEP);
 
+       if (ptrace_get_breakpoints(child) < 0)
+               return;
+
        set_single_step(child, pc);
+       ptrace_put_breakpoints(child);
 }
 
 void user_disable_single_step(struct task_struct *child)
index 90a438acbfafcf00aa8281f03ca44228250189e4..b5e675e370c67203ef301ee0c0766d2babd5a330 100644 (file)
@@ -47,7 +47,7 @@ config HOSTFS
 
 config HPPFS
        tristate "HoneyPot ProcFS (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       depends on EXPERIMENTAL && PROC_FS
        help
          hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
          entries to be overridden, removed, or fabricated from the host.
index 02fb017fed472ed96d66aa1a4252b17b2f5bd677..a9da516a527416e12cfdc887939e2eb8cbd5020f 100644 (file)
@@ -4,6 +4,10 @@ menu "UML-specific options"
 
 menu "Host processor type and features"
 
+config CMPXCHG_LOCAL
+       bool
+       default n
+
 source "arch/x86/Kconfig.cpu"
 
 endmenu
diff --git a/arch/um/include/asm/bug.h b/arch/um/include/asm/bug.h
new file mode 100644 (file)
index 0000000..9e33b86
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __UM_BUG_H
+#define __UM_BUG_H
+
+#include <asm-generic/bug.h>
+
+#endif
index e2cf786bda0a28c43a8173ab40ec62ee2ab8a6de..5bd1bad33fab65fdd8f8857c3452768377e88290 100644 (file)
@@ -49,7 +49,10 @@ static inline struct thread_info *current_thread_info(void)
 {
        struct thread_info *ti;
        unsigned long mask = THREAD_SIZE - 1;
-       ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
+       void *p;
+
+       asm volatile ("" : "=r" (p) : "0" (&ti));
+       ti = (struct thread_info *) (((unsigned long)p) & ~mask);
        return ti;
 }
 
index 804b28dd0328a30088e122a1dcd984bf1464ba75..b1da91c1b200d4f14ff60fcbdbd3b203b595dbe4 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
        ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \
-       sys_call_table.o tls.o
+       sys_call_table.o tls.o atomic64_cx8_32.o
 
 obj-$(CONFIG_BINFMT_ELF) += elfcore.o
 
diff --git a/arch/um/sys-i386/atomic64_cx8_32.S b/arch/um/sys-i386/atomic64_cx8_32.S
new file mode 100644 (file)
index 0000000..1e901d3
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * atomic64_t for 586+
+ *
+ * Copied from arch/x86/lib/atomic64_cx8_32.S
+ *
+ * Copyright Â© 2010  Luca Barbieri
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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>
+#include <asm/alternative-asm.h>
+#include <asm/dwarf2.h>
+
+.macro SAVE reg
+       pushl_cfi %\reg
+       CFI_REL_OFFSET \reg, 0
+.endm
+
+.macro RESTORE reg
+       popl_cfi %\reg
+       CFI_RESTORE \reg
+.endm
+
+.macro read64 reg
+       movl %ebx, %eax
+       movl %ecx, %edx
+/* we need LOCK_PREFIX since otherwise cmpxchg8b always does the write */
+       LOCK_PREFIX
+       cmpxchg8b (\reg)
+.endm
+
+ENTRY(atomic64_read_cx8)
+       CFI_STARTPROC
+
+       read64 %ecx
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_read_cx8)
+
+ENTRY(atomic64_set_cx8)
+       CFI_STARTPROC
+
+1:
+/* we don't need LOCK_PREFIX since aligned 64-bit writes
+ * are atomic on 586 and newer */
+       cmpxchg8b (%esi)
+       jne 1b
+
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_set_cx8)
+
+ENTRY(atomic64_xchg_cx8)
+       CFI_STARTPROC
+
+       movl %ebx, %eax
+       movl %ecx, %edx
+1:
+       LOCK_PREFIX
+       cmpxchg8b (%esi)
+       jne 1b
+
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_xchg_cx8)
+
+.macro addsub_return func ins insc
+ENTRY(atomic64_\func\()_return_cx8)
+       CFI_STARTPROC
+       SAVE ebp
+       SAVE ebx
+       SAVE esi
+       SAVE edi
+
+       movl %eax, %esi
+       movl %edx, %edi
+       movl %ecx, %ebp
+
+       read64 %ebp
+1:
+       movl %eax, %ebx
+       movl %edx, %ecx
+       \ins\()l %esi, %ebx
+       \insc\()l %edi, %ecx
+       LOCK_PREFIX
+       cmpxchg8b (%ebp)
+       jne 1b
+
+10:
+       movl %ebx, %eax
+       movl %ecx, %edx
+       RESTORE edi
+       RESTORE esi
+       RESTORE ebx
+       RESTORE ebp
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_\func\()_return_cx8)
+.endm
+
+addsub_return add add adc
+addsub_return sub sub sbb
+
+.macro incdec_return func ins insc
+ENTRY(atomic64_\func\()_return_cx8)
+       CFI_STARTPROC
+       SAVE ebx
+
+       read64 %esi
+1:
+       movl %eax, %ebx
+       movl %edx, %ecx
+       \ins\()l $1, %ebx
+       \insc\()l $0, %ecx
+       LOCK_PREFIX
+       cmpxchg8b (%esi)
+       jne 1b
+
+10:
+       movl %ebx, %eax
+       movl %ecx, %edx
+       RESTORE ebx
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_\func\()_return_cx8)
+.endm
+
+incdec_return inc add adc
+incdec_return dec sub sbb
+
+ENTRY(atomic64_dec_if_positive_cx8)
+       CFI_STARTPROC
+       SAVE ebx
+
+       read64 %esi
+1:
+       movl %eax, %ebx
+       movl %edx, %ecx
+       subl $1, %ebx
+       sbb $0, %ecx
+       js 2f
+       LOCK_PREFIX
+       cmpxchg8b (%esi)
+       jne 1b
+
+2:
+       movl %ebx, %eax
+       movl %ecx, %edx
+       RESTORE ebx
+       ret
+       CFI_ENDPROC
+ENDPROC(atomic64_dec_if_positive_cx8)
+
+ENTRY(atomic64_add_unless_cx8)
+       CFI_STARTPROC
+       SAVE ebp
+       SAVE ebx
+/* these just push these two parameters on the stack */
+       SAVE edi
+       SAVE esi
+
+       movl %ecx, %ebp
+       movl %eax, %esi
+       movl %edx, %edi
+
+       read64 %ebp
+1:
+       cmpl %eax, 0(%esp)
+       je 4f
+2:
+       movl %eax, %ebx
+       movl %edx, %ecx
+       addl %esi, %ebx
+       adcl %edi, %ecx
+       LOCK_PREFIX
+       cmpxchg8b (%ebp)
+       jne 1b
+
+       movl $1, %eax
+3:
+       addl $8, %esp
+       CFI_ADJUST_CFA_OFFSET -8
+       RESTORE ebx
+       RESTORE ebp
+       ret
+4:
+       cmpl %edx, 4(%esp)
+       jne 2b
+       xorl %eax, %eax
+       jmp 3b
+       CFI_ENDPROC
+ENDPROC(atomic64_add_unless_cx8)
+
+ENTRY(atomic64_inc_not_zero_cx8)
+       CFI_STARTPROC
+       SAVE ebx
+
+       read64 %esi
+1:
+       testl %eax, %eax
+       je 4f
+2:
+       movl %eax, %ebx
+       movl %edx, %ecx
+       addl $1, %ebx
+       adcl $0, %ecx
+       LOCK_PREFIX
+       cmpxchg8b (%esi)
+       jne 1b
+
+       movl $1, %eax
+3:
+       RESTORE ebx
+       ret
+4:
+       testl %edx, %edx
+       jne 2b
+       jmp 3b
+       CFI_ENDPROC
+ENDPROC(atomic64_inc_not_zero_cx8)
index cae3feb1035e3da73826b518de4d47c15ad4e58d..db75d07c3645c0375090596ae29d1085f0f8a38a 100644 (file)
@@ -91,7 +91,7 @@ static int detect_memory_e801(void)
        if (oreg.ax > 15*1024) {
                return -1;      /* Bogus! */
        } else if (oreg.ax == 15*1024) {
-               boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
+               boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax;
        } else {
                /*
                 * This ignores memory above 16MB if we have a memory
index 43085bfc99c30f963b929a9c7afdcff932ad9236..156cd5d18d2abeabb26a0587cfffd15c52aa6f13 100644 (file)
@@ -66,7 +66,7 @@ static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order)
         * Don't enable translation but enable GART IO and CPU accesses.
         * Also, set DISTLBWALKPRB since GART tables memory is UC.
         */
-       ctl = DISTLBWALKPRB | order << 1;
+       ctl = order << 1;
 
        pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
 }
@@ -75,17 +75,17 @@ static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
 {
        u32 tmp, ctl;
 
-        /* address of the mappings table */
-        addr >>= 12;
-        tmp = (u32) addr<<4;
-        tmp &= ~0xf;
-        pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp);
-
-        /* Enable GART translation for this hammer. */
-        pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
-        ctl |= GARTEN;
-        ctl &= ~(DISGARTCPU | DISGARTIO);
-        pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
+       /* address of the mappings table */
+       addr >>= 12;
+       tmp = (u32) addr<<4;
+       tmp &= ~0xf;
+       pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp);
+
+       /* Enable GART translation for this hammer. */
+       pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
+       ctl |= GARTEN | DISTLBWALKPRB;
+       ctl &= ~(DISGARTCPU | DISGARTIO);
+       pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
 }
 
 static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size)
index c4bd267dfc50842e73ea02c562549717c47fb80a..a97a240f67f3158f79c112fffcd0b8dd1e3f4847 100644 (file)
@@ -150,7 +150,7 @@ void setup_IO_APIC_irq_extra(u32 gsi);
 extern void ioapic_and_gsi_init(void);
 extern void ioapic_insert_resources(void);
 
-int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr);
+int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
 
 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
 extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
index fd5a1f365c95105ebe095c33df1dfbf91e1715a1..3cce71413d0be86278a7037eccc692d3d205b4e8 100644 (file)
 #define MSR_IA32_MC0_ADDR              0x00000402
 #define MSR_IA32_MC0_MISC              0x00000403
 
+#define MSR_AMD64_MC0_MASK             0xc0010044
+
 #define MSR_IA32_MCx_CTL(x)            (MSR_IA32_MC0_CTL + 4*(x))
 #define MSR_IA32_MCx_STATUS(x)         (MSR_IA32_MC0_STATUS + 4*(x))
 #define MSR_IA32_MCx_ADDR(x)           (MSR_IA32_MC0_ADDR + 4*(x))
 #define MSR_IA32_MCx_MISC(x)           (MSR_IA32_MC0_MISC + 4*(x))
 
+#define MSR_AMD64_MCx_MASK(x)          (MSR_AMD64_MC0_MASK + (x))
+
 /* These are consecutive and not in the normal 4er MCE bank block */
 #define MSR_IA32_MC0_CTL2              0x00000280
 #define MSR_IA32_MCx_CTL2(x)           (MSR_IA32_MC0_CTL2 + (x))
index 3d4dab43c99469b6d917f0ba4f4bebd7cdc25bb6..a50fc9f493b3d68a4750a085d48d98b4e4ba72ea 100644 (file)
@@ -51,7 +51,7 @@ static inline void numa_remove_cpu(int cpu)           { }
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_DEBUG_PER_CPU_MAPS
-struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable);
+void debug_cpumask_set_cpu(int cpu, int node, bool enable);
 #endif
 
 #endif /* _ASM_X86_NUMA_H */
index 86d1ad4962a73a352ec22625658bec7deca21d7c..73fb469908c6852476c10a75a05aa49329f386b8 100644 (file)
@@ -499,7 +499,7 @@ out:
                 * Don't enable translation yet but enable GART IO and CPU
                 * accesses and set DISTLBWALKPRB since GART table memory is UC.
                 */
-               u32 ctl = DISTLBWALKPRB | aper_order << 1;
+               u32 ctl = aper_order << 1;
 
                bus = amd_nb_bus_dev_ranges[i].bus;
                dev_base = amd_nb_bus_dev_ranges[i].dev_base;
index 68df09bba92ee902dabdd2e37acdd29d9ae67007..45fd33d1fd3a01951184feca64ed476178d34922 100644 (file)
@@ -128,8 +128,8 @@ static int __init parse_noapic(char *str)
 }
 early_param("noapic", parse_noapic);
 
-static int io_apic_setup_irq_pin_once(unsigned int irq, int node,
-                                     struct io_apic_irq_attr *attr);
+static int io_apic_setup_irq_pin(unsigned int irq, int node,
+                                struct io_apic_irq_attr *attr);
 
 /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */
 void mp_save_irq(struct mpc_intsrc *m)
@@ -3570,7 +3570,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 }
 #endif /* CONFIG_HT_IRQ */
 
-int
+static int
 io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
 {
        struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node);
@@ -3585,8 +3585,8 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
        return ret;
 }
 
-static int io_apic_setup_irq_pin_once(unsigned int irq, int node,
-                                     struct io_apic_irq_attr *attr)
+int io_apic_setup_irq_pin_once(unsigned int irq, int node,
+                              struct io_apic_irq_attr *attr)
 {
        unsigned int id = attr->ioapic, pin = attr->ioapic_pin;
        int ret;
index 0b4be431c620ab30ac0bd348888fdf3e9dd3a5b8..adee12e0da1fcaf6e1c8f9ad3ff1e362e2ec736b 100644 (file)
 #include <linux/kthread.h>
 #include <linux/jiffies.h>
 #include <linux/acpi.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -1238,6 +1239,7 @@ static int suspend(int vetoable)
 
        local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
+       syscore_suspend();
 
        local_irq_enable();
 
@@ -1255,6 +1257,7 @@ static int suspend(int vetoable)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
 
+       syscore_resume();
        sysdev_resume();
        local_irq_enable();
 
@@ -1280,6 +1283,7 @@ static void standby(void)
 
        local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
+       syscore_suspend();
        local_irq_enable();
 
        err = set_system_power_state(APM_STATE_STANDBY);
@@ -1287,6 +1291,7 @@ static void standby(void)
                apm_error("standby", err);
 
        local_irq_disable();
+       syscore_resume();
        sysdev_resume();
        local_irq_enable();
 
index 3ecece0217ef1c10e4bcab2a9cd64b9d10f94833..bb9eb29a52dd155d97deb653170270a058575727 100644 (file)
@@ -615,6 +615,25 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        /* As a rule processors have APIC timer running in deep C states */
        if (c->x86 >= 0xf && !cpu_has_amd_erratum(amd_erratum_400))
                set_cpu_cap(c, X86_FEATURE_ARAT);
+
+       /*
+        * Disable GART TLB Walk Errors on Fam10h. We do this here
+        * because this is always needed when GART is enabled, even in a
+        * kernel which has no MCE support built in.
+        */
+       if (c->x86 == 0x10) {
+               /*
+                * BIOS should disable GartTlbWlk Errors themself. If
+                * it doesn't do it here as suggested by the BKDG.
+                *
+                * Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
+                */
+               u64 mask;
+
+               rdmsrl(MSR_AMD64_MCx_MASK(4), mask);
+               mask |= (1 << 10);
+               wrmsrl(MSR_AMD64_MCx_MASK(4), mask);
+       }
 }
 
 #ifdef CONFIG_X86_32
@@ -679,7 +698,7 @@ cpu_dev_register(amd_cpu_dev);
  */
 
 const int amd_erratum_400[] =
-       AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
+       AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf),
                            AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
 EXPORT_SYMBOL_GPL(amd_erratum_400);
 
index eed3673a8656f5688d54f6b4d72fd9774c831fcb..e638689279d3ec183867b2946309f92b3d4d9415 100644 (file)
@@ -586,8 +586,12 @@ static int x86_setup_perfctr(struct perf_event *event)
                        return -EOPNOTSUPP;
        }
 
+       /*
+        * Do not allow config1 (extended registers) to propagate,
+        * there's no sane user-space generalization yet:
+        */
        if (attr->type == PERF_TYPE_RAW)
-               return x86_pmu_extra_regs(event->attr.config, event);
+               return 0;
 
        if (attr->type == PERF_TYPE_HW_CACHE)
                return set_ext_hw_attr(hwc, event);
@@ -609,8 +613,8 @@ static int x86_setup_perfctr(struct perf_event *event)
        /*
         * Branch tracing:
         */
-       if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
-           (hwc->sample_period == 1)) {
+       if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS &&
+           !attr->freq && hwc->sample_period == 1) {
                /* BTS is not supported by this architecture. */
                if (!x86_pmu.bts_active)
                        return -EOPNOTSUPP;
@@ -1284,6 +1288,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
 
        cpuc = &__get_cpu_var(cpu_hw_events);
 
+       /*
+        * Some chipsets need to unmask the LVTPC in a particular spot
+        * inside the nmi handler.  As a result, the unmasking was pushed
+        * into all the nmi handlers.
+        *
+        * This generic handler doesn't seem to have any issues where the
+        * unmasking occurs so it was left at the top.
+        */
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
+
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
                if (!test_bit(idx, cpuc->active_mask)) {
                        /*
@@ -1370,8 +1384,6 @@ perf_event_nmi_handler(struct notifier_block *self,
                return NOTIFY_DONE;
        }
 
-       apic_write(APIC_LVTPC, APIC_DM_NMI);
-
        handled = x86_pmu.handle_irq(args->regs);
        if (!handled)
                return NOTIFY_DONE;
index 461f62bbd774a0adec028334f8c723e5a33bea1d..cf4e369cea6793ab3b4eac82fcdcd594547cd019 100644 (file)
@@ -8,7 +8,7 @@ static __initconst const u64 amd_hw_cache_event_ids
  [ C(L1D) ] = {
        [ C(OP_READ) ] = {
                [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses        */
-               [ C(RESULT_MISS)   ] = 0x0041, /* Data Cache Misses          */
+               [ C(RESULT_MISS)   ] = 0x0141, /* Data Cache Misses          */
        },
        [ C(OP_WRITE) ] = {
                [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
@@ -427,7 +427,9 @@ static __initconst const struct x86_pmu amd_pmu = {
  *
  * Exceptions:
  *
+ * 0x000       FP      PERF_CTL[3], PERF_CTL[5:3] (*)
  * 0x003       FP      PERF_CTL[3]
+ * 0x004       FP      PERF_CTL[3], PERF_CTL[5:3] (*)
  * 0x00B       FP      PERF_CTL[3]
  * 0x00D       FP      PERF_CTL[3]
  * 0x023       DE      PERF_CTL[2:0]
@@ -448,6 +450,8 @@ static __initconst const struct x86_pmu amd_pmu = {
  * 0x0DF       LS      PERF_CTL[5:0]
  * 0x1D6       EX      PERF_CTL[5:0]
  * 0x1D8       EX      PERF_CTL[5:0]
+ *
+ * (*) depending on the umask all FPU counters may be used
  */
 
 static struct event_constraint amd_f15_PMC0  = EVENT_CONSTRAINT(0, 0x01, 0);
@@ -460,18 +464,28 @@ static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
 static struct event_constraint *
 amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-       unsigned int event_code = amd_get_event_code(&event->hw);
+       struct hw_perf_event *hwc = &event->hw;
+       unsigned int event_code = amd_get_event_code(hwc);
 
        switch (event_code & AMD_EVENT_TYPE_MASK) {
        case AMD_EVENT_FP:
                switch (event_code) {
+               case 0x000:
+                       if (!(hwc->config & 0x0000F000ULL))
+                               break;
+                       if (!(hwc->config & 0x00000F00ULL))
+                               break;
+                       return &amd_f15_PMC3;
+               case 0x004:
+                       if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+                               break;
+                       return &amd_f15_PMC3;
                case 0x003:
                case 0x00B:
                case 0x00D:
                        return &amd_f15_PMC3;
-               default:
-                       return &amd_f15_PMC53;
                }
+               return &amd_f15_PMC53;
        case AMD_EVENT_LS:
        case AMD_EVENT_DC:
        case AMD_EVENT_EX_LS:
index 8fc2b2cee1da32713746cc7e871aab075deaee41..447a28de6f097784aba7591f1856225671748084 100644 (file)
@@ -25,7 +25,7 @@ struct intel_percore {
 /*
  * Intel PerfMon, used on Core and later.
  */
-static const u64 intel_perfmon_event_map[] =
+static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
 {
   [PERF_COUNT_HW_CPU_CYCLES]           = 0x003c,
   [PERF_COUNT_HW_INSTRUCTIONS]         = 0x00c0,
@@ -184,26 +184,23 @@ static __initconst const u64 snb_hw_cache_event_ids
        },
  },
  [ C(LL  ) ] = {
-       /*
-        * TBD: Need Off-core Response Performance Monitoring support
-        */
        [ C(OP_READ) ] = {
-               /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
+               /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01bb,
+               /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_WRITE) ] = {
-               /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */
+               /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01bb,
+               /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_PREFETCH) ] = {
-               /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
+               /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01bb,
+               /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
  },
  [ C(DTLB) ] = {
@@ -285,26 +282,26 @@ static __initconst const u64 westmere_hw_cache_event_ids
  },
  [ C(LL  ) ] = {
        [ C(OP_READ) ] = {
-               /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
+               /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01bb,
+               /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        /*
         * Use RFO, not WRITEBACK, because a write miss would typically occur
         * on RFO.
         */
        [ C(OP_WRITE) ] = {
-               /* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */
-               [ C(RESULT_ACCESS) ] = 0x01bb,
-               /* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */
+               /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
                [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_PREFETCH) ] = {
-               /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
+               /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
                [ C(RESULT_ACCESS) ] = 0x01b7,
-               /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
-               [ C(RESULT_MISS)   ] = 0x01bb,
+               /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
  },
  [ C(DTLB) ] = {
@@ -352,16 +349,36 @@ static __initconst const u64 westmere_hw_cache_event_ids
 };
 
 /*
- * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3
+ * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits;
+ * See IA32 SDM Vol 3B 30.6.1.3
  */
 
-#define DMND_DATA_RD     (1 << 0)
-#define DMND_RFO         (1 << 1)
-#define DMND_WB          (1 << 3)
-#define PF_DATA_RD       (1 << 4)
-#define PF_DATA_RFO      (1 << 5)
-#define RESP_UNCORE_HIT  (1 << 8)
-#define RESP_MISS        (0xf600) /* non uncore hit */
+#define NHM_DMND_DATA_RD       (1 << 0)
+#define NHM_DMND_RFO           (1 << 1)
+#define NHM_DMND_IFETCH                (1 << 2)
+#define NHM_DMND_WB            (1 << 3)
+#define NHM_PF_DATA_RD         (1 << 4)
+#define NHM_PF_DATA_RFO                (1 << 5)
+#define NHM_PF_IFETCH          (1 << 6)
+#define NHM_OFFCORE_OTHER      (1 << 7)
+#define NHM_UNCORE_HIT         (1 << 8)
+#define NHM_OTHER_CORE_HIT_SNP (1 << 9)
+#define NHM_OTHER_CORE_HITM    (1 << 10)
+                               /* reserved */
+#define NHM_REMOTE_CACHE_FWD   (1 << 12)
+#define NHM_REMOTE_DRAM                (1 << 13)
+#define NHM_LOCAL_DRAM         (1 << 14)
+#define NHM_NON_DRAM           (1 << 15)
+
+#define NHM_ALL_DRAM           (NHM_REMOTE_DRAM|NHM_LOCAL_DRAM)
+
+#define NHM_DMND_READ          (NHM_DMND_DATA_RD)
+#define NHM_DMND_WRITE         (NHM_DMND_RFO|NHM_DMND_WB)
+#define NHM_DMND_PREFETCH      (NHM_PF_DATA_RD|NHM_PF_DATA_RFO)
+
+#define NHM_L3_HIT     (NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM)
+#define NHM_L3_MISS    (NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_L3_ACCESS  (NHM_L3_HIT|NHM_L3_MISS)
 
 static __initconst const u64 nehalem_hw_cache_extra_regs
                                [PERF_COUNT_HW_CACHE_MAX]
@@ -370,16 +387,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs
 {
  [ C(LL  ) ] = {
        [ C(OP_READ) ] = {
-               [ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT,
-               [ C(RESULT_MISS)   ] = DMND_DATA_RD|RESP_MISS,
+               [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_L3_MISS,
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT,
-               [ C(RESULT_MISS)   ] = DMND_RFO|DMND_WB|RESP_MISS,
+               [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_L3_MISS,
        },
        [ C(OP_PREFETCH) ] = {
-               [ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT,
-               [ C(RESULT_MISS)   ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS,
+               [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_L3_MISS,
        },
  }
 };
@@ -391,12 +408,12 @@ static __initconst const u64 nehalem_hw_cache_event_ids
 {
  [ C(L1D) ] = {
        [ C(OP_READ) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI            */
-               [ C(RESULT_MISS)   ] = 0x0140, /* L1D_CACHE_LD.I_STATE         */
+               [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS       */
+               [ C(RESULT_MISS)   ] = 0x0151, /* L1D.REPL                     */
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI            */
-               [ C(RESULT_MISS)   ] = 0x0141, /* L1D_CACHE_ST.I_STATE         */
+               [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES      */
+               [ C(RESULT_MISS)   ] = 0x0251, /* L1D.M_REPL                   */
        },
        [ C(OP_PREFETCH) ] = {
                [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS        */
@@ -933,6 +950,16 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
 
        cpuc = &__get_cpu_var(cpu_hw_events);
 
+       /*
+        * Some chipsets need to unmask the LVTPC in a particular spot
+        * inside the nmi handler.  As a result, the unmasking was pushed
+        * into all the nmi handlers.
+        *
+        * This handler doesn't seem to have any issues with the unmasking
+        * so it was left at the top.
+        */
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
+
        intel_pmu_disable_all();
        handled = intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
@@ -998,6 +1025,9 @@ intel_bts_constraints(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        unsigned int hw_event, bts_event;
 
+       if (event->attr.freq)
+               return NULL;
+
        hw_event = hwc->config & INTEL_ARCH_EVENT_MASK;
        bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
 
@@ -1305,7 +1335,7 @@ static void intel_clovertown_quirks(void)
         * AJ106 could possibly be worked around by not allowing LBR
         *       usage from PEBS, including the fixup.
         * AJ68  could possibly be worked around by always programming
-        *       a pebs_event_reset[0] value and coping with the lost events.
+        *       a pebs_event_reset[0] value and coping with the lost events.
         *
         * But taken together it might just make sense to not enable PEBS on
         * these chips.
@@ -1409,6 +1439,18 @@ static __init int intel_pmu_init(void)
                x86_pmu.percore_constraints = intel_nehalem_percore_constraints;
                x86_pmu.enable_all = intel_pmu_nhm_enable_all;
                x86_pmu.extra_regs = intel_nehalem_extra_regs;
+
+               if (ebx & 0x40) {
+                       /*
+                        * Erratum AAJ80 detected, we work it around by using
+                        * the BR_MISP_EXEC.ANY event. This will over-count
+                        * branch-misses, but it's still much better than the
+                        * architectural event which is often completely bogus:
+                        */
+                       intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
+
+                       pr_cont("erratum AAJ80 worked around, ");
+               }
                pr_cont("Nehalem events, ");
                break;
 
@@ -1425,6 +1467,7 @@ static __init int intel_pmu_init(void)
 
        case 37: /* 32 nm nehalem, "Clarkdale" */
        case 44: /* 32 nm nehalem, "Gulftown" */
+       case 47: /* 32 nm Xeon E7 */
                memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
index c2520e178d32147fd9e2acd954d59e4217115add..e93fcd55fae16f8bc5e5b3c14e5c1e4c56a9426c 100644 (file)
@@ -947,14 +947,23 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
                if (!x86_perf_event_set_period(event))
                        continue;
                if (perf_event_overflow(event, 1, &data, regs))
-                       p4_pmu_disable_event(event);
+                       x86_pmu_stop(event, 0);
        }
 
-       if (handled) {
-               /* p4 quirk: unmask it again */
-               apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
+       if (handled)
                inc_irq_stat(apic_perf_irqs);
-       }
+
+       /*
+        * When dealing with the unmasking of the LVTPC on P4 perf hw, it has
+        * been observed that the OVF bit flag has to be cleared first _before_
+        * the LVTPC can be unmasked.
+        *
+        * The reason is the NMI line will continue to be asserted while the OVF
+        * bit is set.  This causes a second NMI to generate if the LVTPC is
+        * unmasked before the OVF bit is cleared, leading to unknown NMI
+        * messages.
+        */
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
 
        return handled;
 }
index 706a9fb46a58785edef3632d2dcfc5d02ac6404f..e90f08458e6ba5879c033388945fbec7963f677c 100644 (file)
@@ -391,7 +391,7 @@ static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
 
        set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
 
-       return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr);
+       return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr);
 }
 
 static void __init ioapic_add_ofnode(struct device_node *np)
index 82ada01625b98c111a41fbecf72fdd026c08e5f1..b117efd24f71f589286aac56e0b50fb235dac0cc 100644 (file)
@@ -81,6 +81,9 @@ static u32 gart_unmapped_entry;
 #define AGPEXTERN
 #endif
 
+/* GART can only remap to physical addresses < 1TB */
+#define GART_MAX_PHYS_ADDR     (1ULL << 40)
+
 /* backdoor interface to AGP driver */
 AGPEXTERN int agp_memory_reserved;
 AGPEXTERN __u32 *agp_gatt_table;
@@ -212,9 +215,13 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
                                size_t size, int dir, unsigned long align_mask)
 {
        unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE);
-       unsigned long iommu_page = alloc_iommu(dev, npages, align_mask);
+       unsigned long iommu_page;
        int i;
 
+       if (unlikely(phys_mem + size > GART_MAX_PHYS_ADDR))
+               return bad_dma_addr;
+
+       iommu_page = alloc_iommu(dev, npages, align_mask);
        if (iommu_page == -1) {
                if (!nonforced_iommu(dev, phys_mem, size))
                        return phys_mem;
index 45892dc4b72a37f01627725db2654591fc4dad6b..f65e5b521dbd4b3d28c8dc30faecec02073e56fb 100644 (file)
@@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
        unsigned len, type;
        struct perf_event *bp;
 
+       if (ptrace_get_breakpoints(tsk) < 0)
+               return -ESRCH;
+
        data &= ~DR_CONTROL_RESERVED;
        old_dr7 = ptrace_get_dr7(thread->ptrace_bps);
 restore:
@@ -655,6 +658,9 @@ restore:
                }
                goto restore;
        }
+
+       ptrace_put_breakpoints(tsk);
+
        return ((orig_ret < 0) ? orig_ret : rc);
 }
 
@@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
 
        if (n < HBP_NUM) {
                struct perf_event *bp;
+
+               if (ptrace_get_breakpoints(tsk) < 0)
+                       return -ESRCH;
+
                bp = thread->ptrace_bps[n];
                if (!bp)
-                       return 0;
-               val = bp->hw.info.address;
+                       val = 0;
+               else
+                       val = bp->hw.info.address;
+
+               ptrace_put_breakpoints(tsk);
        } else if (n == 6) {
                val = thread->debugreg6;
         } else if (n == 7) {
@@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
        struct perf_event *bp;
        struct thread_struct *t = &tsk->thread;
        struct perf_event_attr attr;
+       int err = 0;
+
+       if (ptrace_get_breakpoints(tsk) < 0)
+               return -ESRCH;
 
        if (!t->ptrace_bps[nr]) {
                ptrace_breakpoint_init(&attr);
@@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
                 * writing for the user. And anyway this is the previous
                 * behaviour.
                 */
-               if (IS_ERR(bp))
-                       return PTR_ERR(bp);
+               if (IS_ERR(bp)) {
+                       err = PTR_ERR(bp);
+                       goto put;
+               }
 
                t->ptrace_bps[nr] = bp;
        } else {
-               int err;
-
                bp = t->ptrace_bps[nr];
 
                attr = bp->attr;
                attr.bp_addr = addr;
                err = modify_user_hw_breakpoint(bp, &attr);
-               if (err)
-                       return err;
        }
 
-
-       return 0;
+put:
+       ptrace_put_breakpoints(tsk);
+       return err;
 }
 
 /*
index 29092b38d816ee2577e5e89fb74cc023dbafc411..1d5c46df0d787abc497a1d025a9a8fd2cd347026 100644 (file)
@@ -21,26 +21,26 @@ r_base = .
        /* Get our own relocated address */
        call    1f
 1:     popl    %ebx
-       subl    $1b, %ebx
+       subl    $(1b - r_base), %ebx
 
        /* Compute the equivalent real-mode segment */
        movl    %ebx, %ecx
        shrl    $4, %ecx
        
        /* Patch post-real-mode segment jump */
-       movw    dispatch_table(%ebx,%eax,2),%ax
-       movw    %ax, 101f(%ebx)
-       movw    %cx, 102f(%ebx)
+       movw    (dispatch_table - r_base)(%ebx,%eax,2),%ax
+       movw    %ax, (101f - r_base)(%ebx)
+       movw    %cx, (102f - r_base)(%ebx)
 
        /* Set up the IDT for real mode. */
-       lidtl   machine_real_restart_idt(%ebx)
+       lidtl   (machine_real_restart_idt - r_base)(%ebx)
 
        /*
         * Set up a GDT from which we can load segment descriptors for real
         * mode.  The GDT is not used in real mode; it is just needed here to
         * prepare the descriptors.
         */
-       lgdtl   machine_real_restart_gdt(%ebx)
+       lgdtl   (machine_real_restart_gdt - r_base)(%ebx)
 
        /*
         * Load the data segment registers with 16-bit compatible values
index 9559d360fde79b8373d042fb48e24c98b836684d..745258dfc4dc1cc93afdd96e6944aac4d9c4a0ec 100644 (file)
@@ -213,53 +213,48 @@ int early_cpu_to_node(int cpu)
        return per_cpu(x86_cpu_to_node_map, cpu);
 }
 
-struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable)
+void debug_cpumask_set_cpu(int cpu, int node, bool enable)
 {
-       int node = early_cpu_to_node(cpu);
        struct cpumask *mask;
        char buf[64];
 
        if (node == NUMA_NO_NODE) {
                /* early_cpu_to_node() already emits a warning and trace */
-               return NULL;
+               return;
        }
        mask = node_to_cpumask_map[node];
        if (!mask) {
                pr_err("node_to_cpumask_map[%i] NULL\n", node);
                dump_stack();
-               return NULL;
+               return;
        }
 
+       if (enable)
+               cpumask_set_cpu(cpu, mask);
+       else
+               cpumask_clear_cpu(cpu, mask);
+
        cpulist_scnprintf(buf, sizeof(buf), mask);
        printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n",
                enable ? "numa_add_cpu" : "numa_remove_cpu",
                cpu, node, buf);
-       return mask;
+       return;
 }
 
 # ifndef CONFIG_NUMA_EMU
-static void __cpuinit numa_set_cpumask(int cpu, int enable)
+static void __cpuinit numa_set_cpumask(int cpu, bool enable)
 {
-       struct cpumask *mask;
-
-       mask = debug_cpumask_set_cpu(cpu, enable);
-       if (!mask)
-               return;
-
-       if (enable)
-               cpumask_set_cpu(cpu, mask);
-       else
-               cpumask_clear_cpu(cpu, mask);
+       debug_cpumask_set_cpu(cpu, early_cpu_to_node(cpu), enable);
 }
 
 void __cpuinit numa_add_cpu(int cpu)
 {
-       numa_set_cpumask(cpu, 1);
+       numa_set_cpumask(cpu, true);
 }
 
 void __cpuinit numa_remove_cpu(int cpu)
 {
-       numa_set_cpumask(cpu, 0);
+       numa_set_cpumask(cpu, false);
 }
 # endif        /* !CONFIG_NUMA_EMU */
 
index e8c00cc72033cbf4ee5e4f44a3a59a10386596fe..85b52fc03084c57601fe619d7f6fb126d7a177fd 100644 (file)
@@ -306,7 +306,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
                bi->end = min(bi->end, high);
 
                /* and there's no empty block */
-               if (bi->start == bi->end) {
+               if (bi->start >= bi->end) {
                        numa_remove_memblk_from(i--, mi);
                        continue;
                }
index ad091e4cff17f01a598c7a2c1b3a5a541e9d96a1..de84cc140379ea0b3688d4815577b8c7548e8a44 100644 (file)
@@ -454,10 +454,9 @@ void __cpuinit numa_remove_cpu(int cpu)
                cpumask_clear_cpu(cpu, node_to_cpumask_map[i]);
 }
 #else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
-static void __cpuinit numa_set_cpumask(int cpu, int enable)
+static void __cpuinit numa_set_cpumask(int cpu, bool enable)
 {
-       struct cpumask *mask;
-       int nid, physnid, i;
+       int nid, physnid;
 
        nid = early_cpu_to_node(cpu);
        if (nid == NUMA_NO_NODE) {
@@ -467,28 +466,21 @@ static void __cpuinit numa_set_cpumask(int cpu, int enable)
 
        physnid = emu_nid_to_phys[nid];
 
-       for_each_online_node(i) {
+       for_each_online_node(nid) {
                if (emu_nid_to_phys[nid] != physnid)
                        continue;
 
-               mask = debug_cpumask_set_cpu(cpu, enable);
-               if (!mask)
-                       return;
-
-               if (enable)
-                       cpumask_set_cpu(cpu, mask);
-               else
-                       cpumask_clear_cpu(cpu, mask);
+               debug_cpumask_set_cpu(cpu, nid, enable);
        }
 }
 
 void __cpuinit numa_add_cpu(int cpu)
 {
-       numa_set_cpumask(cpu, 1);
+       numa_set_cpumask(cpu, true);
 }
 
 void __cpuinit numa_remove_cpu(int cpu)
 {
-       numa_set_cpumask(cpu, 0);
+       numa_set_cpumask(cpu, false);
 }
 #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
index dc701ea585461a3735085447b8e13af6f77b178b..e70be38ce03920d4d8210a98ef1038c9ec471745 100644 (file)
@@ -74,6 +74,7 @@
                                compatible = "intel,ce4100-pci", "pci";
                                device_type = "pci";
                                bus-range = <1 1>;
+                               reg = <0x0800 0x0 0x0 0x0 0x0>;
                                ranges = <0x2000000 0 0xdffe0000 0x2000000 0 0xdffe0000 0 0x1000>;
 
                                interrupt-parent = <&ioapic2>;
                                                   "pciclass0c03";
 
                                        reg = <0x16800 0x0 0x0 0x0 0x0>;
-                                       interrupts = <22 3>;
+                                       interrupts = <22 1>;
                                };
 
                                usb@d,1 {
                                                   "pciclass0c03";
 
                                        reg = <0x16900 0x0 0x0 0x0 0x0>;
-                                       interrupts = <22 3>;
+                                       interrupts = <22 1>;
                                };
 
                                sata@e,0 {
                                                   "pciclass0106";
 
                                        reg = <0x17000 0x0 0x0 0x0 0x0>;
-                                       interrupts = <23 3>;
+                                       interrupts = <23 1>;
                                };
 
                                flash@f,0 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                compatible = "isa";
+                               reg = <0xf800 0x0 0x0 0x0 0x0>;
                                ranges = <1 0 0 0 0 0x100>;
 
                                rtc@70 {
index 5c0207bf959bc4a8490347d775eba452c13f2684..275dbc19e2cf55f2e7cb55f1c3ad861cb976c8a6 100644 (file)
@@ -97,11 +97,11 @@ static int __init sfi_parse_mtmr(struct sfi_table_header *table)
                        pentry->freq_hz, pentry->irq);
                        if (!pentry->irq)
                                continue;
-                       mp_irq.type = MP_IOAPIC;
+                       mp_irq.type = MP_INTSRC;
                        mp_irq.irqtype = mp_INT;
 /* triggering mode edge bit 2-3, active high polarity bit 0-1 */
                        mp_irq.irqflag = 5;
-                       mp_irq.srcbus = 0;
+                       mp_irq.srcbus = MP_BUS_ISA;
                        mp_irq.srcbusirq = pentry->irq; /* IRQ */
                        mp_irq.dstapic = MP_APIC_ALL;
                        mp_irq.dstirq = pentry->irq;
@@ -168,10 +168,10 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
        for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
                pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n",
                        totallen, (u32)pentry->phys_addr, pentry->irq);
-               mp_irq.type = MP_IOAPIC;
+               mp_irq.type = MP_INTSRC;
                mp_irq.irqtype = mp_INT;
                mp_irq.irqflag = 0xf;   /* level trigger and active low */
-               mp_irq.srcbus = 0;
+               mp_irq.srcbus = MP_BUS_ISA;
                mp_irq.srcbusirq = pentry->irq; /* IRQ */
                mp_irq.dstapic = MP_APIC_ALL;
                mp_irq.dstirq = pentry->irq;
@@ -282,7 +282,7 @@ void __init x86_mrst_early_setup(void)
        /* Avoid searching for BIOS MP tables */
        x86_init.mpparse.find_smp_config = x86_init_noop;
        x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-
+       set_bit(MP_BUS_ISA, mp_bus_not_pci);
 }
 
 /*
index 1c7121ba18ffdc902740c396427e448ae62250d4..5cc821cb2e0968090501e8c6e5af36353d5e2f87 100644 (file)
@@ -39,6 +39,7 @@ config XEN_MAX_DOMAIN_MEMORY
 config XEN_SAVE_RESTORE
        bool
        depends on XEN
+       select HIBERNATE_CALLBACKS
        default y
 
 config XEN_DEBUG_FS
index 49dbd78ec3cb0d4481e72e96cdb041507b5ae686..e3c6a06cf725ef08b87a5961b33043bbf493acf3 100644 (file)
@@ -238,6 +238,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
 static __init void xen_init_cpuid_mask(void)
 {
        unsigned int ax, bx, cx, dx;
+       unsigned int xsave_mask;
 
        cpuid_leaf1_edx_mask =
                ~((1 << X86_FEATURE_MCE)  |  /* disable MCE */
@@ -249,24 +250,16 @@ static __init void xen_init_cpuid_mask(void)
                cpuid_leaf1_edx_mask &=
                        ~((1 << X86_FEATURE_APIC) |  /* disable local APIC */
                          (1 << X86_FEATURE_ACPI));  /* disable ACPI */
-
        ax = 1;
-       cx = 0;
        xen_cpuid(&ax, &bx, &cx, &dx);
 
-       /* cpuid claims we support xsave; try enabling it to see what happens */
-       if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
-               unsigned long cr4;
-
-               set_in_cr4(X86_CR4_OSXSAVE);
-               
-               cr4 = read_cr4();
+       xsave_mask =
+               (1 << (X86_FEATURE_XSAVE % 32)) |
+               (1 << (X86_FEATURE_OSXSAVE % 32));
 
-               if ((cr4 & X86_CR4_OSXSAVE) == 0)
-                       cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
-
-               clear_in_cr4(X86_CR4_OSXSAVE);
-       }
+       /* Xen will set CR4.OSXSAVE if supported and not disabled by force */
+       if ((cx & xsave_mask) != xsave_mask)
+               cpuid_leaf1_ecx_mask &= ~xsave_mask; /* disable XSAVE & OSXSAVE */
 }
 
 static void xen_set_debugreg(int reg, unsigned long val)
index c82df6c9c0f0a4a1bbc61f1ea881ebdd37fecdef..55c965b38c27c76769ecde61a9b5041c6969003b 100644 (file)
@@ -565,13 +565,13 @@ pte_t xen_make_pte_debug(pteval_t pte)
        if (io_page &&
            (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
                other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
-               WARN(addr != other_addr,
+               WARN_ONCE(addr != other_addr,
                        "0x%lx is using VM_IO, but it is 0x%lx!\n",
                        (unsigned long)addr, (unsigned long)other_addr);
        } else {
                pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
                other_addr = (_pte.pte & PTE_PFN_MASK);
-               WARN((addr == other_addr) && (!io_page) && (!iomap_set),
+               WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set),
                        "0x%lx is missing VM_IO (and wasn't fixed)!\n",
                        (unsigned long)addr);
        }
@@ -1463,6 +1463,119 @@ static int xen_pgd_alloc(struct mm_struct *mm)
        return ret;
 }
 
+#ifdef CONFIG_X86_64
+static __initdata u64 __last_pgt_set_rw = 0;
+static __initdata u64 __pgt_buf_start = 0;
+static __initdata u64 __pgt_buf_end = 0;
+static __initdata u64 __pgt_buf_top = 0;
+/*
+ * As a consequence of the commit:
+ * 
+ * commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e
+ * Author: Yinghai Lu <yinghai@kernel.org>
+ * Date:   Fri Dec 17 16:58:28 2010 -0800
+ * 
+ *     x86-64, mm: Put early page table high
+ * 
+ * at some point init_memory_mapping is going to reach the pagetable pages
+ * area and map those pages too (mapping them as normal memory that falls
+ * in the range of addresses passed to init_memory_mapping as argument).
+ * Some of those pages are already pagetable pages (they are in the range
+ * pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and
+ * everything is fine.
+ * Some of these pages are not pagetable pages yet (they fall in the range
+ * pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they
+ * are going to be mapped RW.  When these pages become pagetable pages and
+ * are hooked into the pagetable, xen will find that the guest has already
+ * a RW mapping of them somewhere and fail the operation.
+ * The reason Xen requires pagetables to be RO is that the hypervisor needs
+ * to verify that the pagetables are valid before using them. The validation
+ * operations are called "pinning".
+ * 
+ * In order to fix the issue we mark all the pages in the entire range
+ * pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation
+ * is completed only the range pgt_buf_start-pgt_buf_end is reserved by
+ * init_memory_mapping. Hence the kernel is going to crash as soon as one
+ * of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those
+ * ranges are RO).
+ * 
+ * For this reason, 'mark_rw_past_pgt' is introduced which is called _after_
+ * the init_memory_mapping has completed (in a perfect world we would
+ * call this function from init_memory_mapping, but lets ignore that).
+ * 
+ * Because we are called _after_ init_memory_mapping the pgt_buf_[start,
+ * end,top] have all changed to new values (b/c init_memory_mapping
+ * is called and setting up another new page-table). Hence, the first time
+ * we enter this function, we save away the pgt_buf_start value and update
+ * the pgt_buf_[end,top].
+ * 
+ * When we detect that the "old" pgt_buf_start through pgt_buf_end
+ * PFNs have been reserved (so memblock_x86_reserve_range has been called),
+ * we immediately set out to RW the "old" pgt_buf_end through pgt_buf_top.
+ * 
+ * And then we update those "old" pgt_buf_[end|top] with the new ones
+ * so that we can redo this on the next pagetable.
+ */
+static __init void mark_rw_past_pgt(void) {
+
+       if (pgt_buf_end > pgt_buf_start) {
+               u64 addr, size;
+
+               /* Save it away. */
+               if (!__pgt_buf_start) {
+                       __pgt_buf_start = pgt_buf_start;
+                       __pgt_buf_end = pgt_buf_end;
+                       __pgt_buf_top = pgt_buf_top;
+                       return;
+               }
+               /* If we get the range that starts at __pgt_buf_end that means
+                * the range is reserved, and that in 'init_memory_mapping'
+                * the 'memblock_x86_reserve_range' has been called with the
+                * outdated __pgt_buf_start, __pgt_buf_end (the "new"
+                * pgt_buf_[start|end|top] refer now to a new pagetable.
+                * Note: we are called _after_ the pgt_buf_[..] have been
+                * updated.*/
+
+               addr = memblock_x86_find_in_range_size(PFN_PHYS(__pgt_buf_start),
+                                                      &size, PAGE_SIZE);
+
+               /* Still not reserved, meaning 'memblock_x86_reserve_range'
+                * hasn't been called yet. Update the _end and _top.*/
+               if (addr == PFN_PHYS(__pgt_buf_start)) {
+                       __pgt_buf_end = pgt_buf_end;
+                       __pgt_buf_top = pgt_buf_top;
+                       return;
+               }
+
+               /* OK, the area is reserved, meaning it is time for us to
+                * set RW for the old end->top PFNs. */
+
+               /* ..unless we had already done this. */
+               if (__pgt_buf_end == __last_pgt_set_rw)
+                       return;
+
+               addr = PFN_PHYS(__pgt_buf_end);
+               
+               /* set as RW the rest */
+               printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n",
+                       PFN_PHYS(__pgt_buf_end), PFN_PHYS(__pgt_buf_top));
+               
+               while (addr < PFN_PHYS(__pgt_buf_top)) {
+                       make_lowmem_page_readwrite(__va(addr));
+                       addr += PAGE_SIZE;
+               }
+               /* And update everything so that we are ready for the next
+                * pagetable (the one created for regions past 4GB) */
+               __last_pgt_set_rw = __pgt_buf_end;
+               __pgt_buf_start = pgt_buf_start;
+               __pgt_buf_end = pgt_buf_end;
+               __pgt_buf_top = pgt_buf_top;
+       }
+       return;
+}
+#else
+static __init void mark_rw_past_pgt(void) { }
+#endif
 static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
 #ifdef CONFIG_X86_64
@@ -1473,17 +1586,29 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
 #endif
 }
 
+#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
-       unsigned long pfn = pte_pfn(pte);
-
-#ifdef CONFIG_X86_32
        /* If there's an existing pte, then don't allow _PAGE_RW to be set */
        if (pte_val_ma(*ptep) & _PAGE_PRESENT)
                pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
                               pte_val_ma(pte));
-#endif
+
+       return pte;
+}
+#else /* CONFIG_X86_64 */
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+       unsigned long pfn = pte_pfn(pte);
 
+       /*
+        * A bit of optimization. We do not need to call the workaround
+        * when xen_set_pte_init is called with a PTE with 0 as PFN.
+        * That is b/c the pagetable at that point are just being populated
+        * with empty values and we can save some cycles by not calling
+        * the 'memblock' code.*/
+       if (pfn)
+               mark_rw_past_pgt();
        /*
         * If the new pfn is within the range of the newly allocated
         * kernel pagetable, and it isn't being mapped into an
@@ -1491,12 +1616,13 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
         * it is RO.
         */
        if (((!is_early_ioremap_ptep(ptep) &&
-                       pfn >= pgt_buf_start && pfn < pgt_buf_end)) ||
+                       pfn >= pgt_buf_start && pfn < pgt_buf_top)) ||
                        (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1)))
                pte = pte_wrprotect(pte);
 
        return pte;
 }
+#endif /* CONFIG_X86_64 */
 
 /* Init-time set_pte while constructing initial pagetables, which
    doesn't allow RO pagetable pages to be remapped RW */
@@ -1992,6 +2118,8 @@ __init void xen_ident_map_ISA(void)
 
 static __init void xen_post_allocator_init(void)
 {
+       mark_rw_past_pgt();
+
 #ifdef CONFIG_XEN_DEBUG
        pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
 #endif
index fa0269a993773f8488f765c3a1e255ba59fd4e3f..90bac0aac3a5d42f3c45b48c3980e0fb432eee03 100644 (file)
@@ -227,7 +227,7 @@ char * __init xen_memory_setup(void)
 
        memcpy(map_raw, map, sizeof(map));
        e820.nr_map = 0;
-       xen_extra_mem_start = mem_end;
+       xen_extra_mem_start = max((1ULL << 32), mem_end);
        for (i = 0; i < memmap.nr_entries; i++) {
                unsigned long long end;
 
index d77089df412e156fb4784f7d3913af0b21d68980..4340ee076bd522f88229aae7f474ce4a59493a40 100644 (file)
@@ -64,47 +64,41 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
 
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
-       int j;
-
-       seq_printf(p, "%*s: ", prec, "NMI");
-       for_each_online_cpu(j)
-               seq_printf(p, "%10u ", nmi_count(j));
-       seq_putc(p, '\n');
        seq_printf(p, "%*s: ", prec, "ERR");
        seq_printf(p, "%10u\n", atomic_read(&irq_err_count));
        return 0;
 }
 
-static void xtensa_irq_mask(struct irq_chip *d)
+static void xtensa_irq_mask(struct irq_data *d)
 {
        cached_irq_mask &= ~(1 << d->irq);
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static void xtensa_irq_unmask(struct irq_chip *d)
+static void xtensa_irq_unmask(struct irq_data *d)
 {
        cached_irq_mask |= 1 << d->irq;
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static void xtensa_irq_enable(struct irq_chip *d)
+static void xtensa_irq_enable(struct irq_data *d)
 {
        variant_irq_enable(d->irq);
        xtensa_irq_unmask(d->irq);
 }
 
-static void xtensa_irq_disable(struct irq_chip *d)
+static void xtensa_irq_disable(struct irq_data *d)
 {
        xtensa_irq_mask(d->irq);
        variant_irq_disable(d->irq);
 }
 
-static void xtensa_irq_ack(struct irq_chip *d)
+static void xtensa_irq_ack(struct irq_data *d)
 {
        set_sr(1 << d->irq, INTCLEAR);
 }
 
-static int xtensa_irq_retrigger(struct irq_chip *d)
+static int xtensa_irq_retrigger(struct irq_data *d)
 {
        set_sr (1 << d->irq, INTSET);
        return 1;
index 90f22cc30799cf8bf71e25c4cf68718c3fbf0cf3..a2e58eeb35499d5f44502a650c822ec000007d4e 100644 (file)
@@ -198,26 +198,13 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
 }
 EXPORT_SYMBOL(blk_dump_rq_flags);
 
-/*
- * Make sure that plugs that were pending when this function was entered,
- * are now complete and requests pushed to the queue.
-*/
-static inline void queue_sync_plugs(struct request_queue *q)
-{
-       /*
-        * If the current process is plugged and has barriers submitted,
-        * we will livelock if we don't unplug first.
-        */
-       blk_flush_plug(current);
-}
-
 static void blk_delay_work(struct work_struct *work)
 {
        struct request_queue *q;
 
        q = container_of(work, struct request_queue, delay_work.work);
        spin_lock_irq(q->queue_lock);
-       __blk_run_queue(q, false);
+       __blk_run_queue(q);
        spin_unlock_irq(q->queue_lock);
 }
 
@@ -233,7 +220,8 @@ static void blk_delay_work(struct work_struct *work)
  */
 void blk_delay_queue(struct request_queue *q, unsigned long msecs)
 {
-       schedule_delayed_work(&q->delay_work, msecs_to_jiffies(msecs));
+       queue_delayed_work(kblockd_workqueue, &q->delay_work,
+                               msecs_to_jiffies(msecs));
 }
 EXPORT_SYMBOL(blk_delay_queue);
 
@@ -251,7 +239,7 @@ void blk_start_queue(struct request_queue *q)
        WARN_ON(!irqs_disabled());
 
        queue_flag_clear(QUEUE_FLAG_STOPPED, q);
-       __blk_run_queue(q, false);
+       __blk_run_queue(q);
 }
 EXPORT_SYMBOL(blk_start_queue);
 
@@ -298,37 +286,41 @@ void blk_sync_queue(struct request_queue *q)
 {
        del_timer_sync(&q->timeout);
        cancel_delayed_work_sync(&q->delay_work);
-       queue_sync_plugs(q);
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
 /**
  * __blk_run_queue - run a single device queue
  * @q: The queue to run
- * @force_kblockd: Don't run @q->request_fn directly.  Use kblockd.
  *
  * Description:
  *    See @blk_run_queue. This variant must be called with the queue lock
  *    held and interrupts disabled.
- *
  */
-void __blk_run_queue(struct request_queue *q, bool force_kblockd)
+void __blk_run_queue(struct request_queue *q)
 {
        if (unlikely(blk_queue_stopped(q)))
                return;
 
-       /*
-        * Only recurse once to avoid overrunning the stack, let the unplug
-        * handling reinvoke the handler shortly if we already got there.
-        */
-       if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
-               q->request_fn(q);
-               queue_flag_clear(QUEUE_FLAG_REENTER, q);
-       } else
-               queue_delayed_work(kblockd_workqueue, &q->delay_work, 0);
+       q->request_fn(q);
 }
 EXPORT_SYMBOL(__blk_run_queue);
 
+/**
+ * blk_run_queue_async - run a single device queue in workqueue context
+ * @q: The queue to run
+ *
+ * Description:
+ *    Tells kblockd to perform the equivalent of @blk_run_queue on behalf
+ *    of us.
+ */
+void blk_run_queue_async(struct request_queue *q)
+{
+       if (likely(!blk_queue_stopped(q)))
+               queue_delayed_work(kblockd_workqueue, &q->delay_work, 0);
+}
+EXPORT_SYMBOL(blk_run_queue_async);
+
 /**
  * blk_run_queue - run a single device queue
  * @q: The queue to run
@@ -342,7 +334,7 @@ void blk_run_queue(struct request_queue *q)
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __blk_run_queue(q, false);
+       __blk_run_queue(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_run_queue);
@@ -991,7 +983,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
                blk_queue_end_tag(q, rq);
 
        add_acct_request(q, rq, where);
-       __blk_run_queue(q, false);
+       __blk_run_queue(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_insert_request);
@@ -1311,7 +1303,15 @@ get_rq:
 
        plug = current->plug;
        if (plug) {
-               if (!plug->should_sort && !list_empty(&plug->list)) {
+               /*
+                * If this is the first request added after a plug, fire
+                * of a plug trace. If others have been added before, check
+                * if we have multiple devices in this plug. If so, make a
+                * note to sort the list before dispatch.
+                */
+               if (list_empty(&plug->list))
+                       trace_block_plug(q);
+               else if (!plug->should_sort) {
                        struct request *__rq;
 
                        __rq = list_entry_rq(plug->list.prev);
@@ -1327,7 +1327,7 @@ get_rq:
        } else {
                spin_lock_irq(q->queue_lock);
                add_acct_request(q, req, where);
-               __blk_run_queue(q, false);
+               __blk_run_queue(q);
 out_unlock:
                spin_unlock_irq(q->queue_lock);
        }
@@ -2644,6 +2644,7 @@ void blk_start_plug(struct blk_plug *plug)
 
        plug->magic = PLUG_MAGIC;
        INIT_LIST_HEAD(&plug->list);
+       INIT_LIST_HEAD(&plug->cb_list);
        plug->should_sort = 0;
 
        /*
@@ -2668,33 +2669,93 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
        return !(rqa->q <= rqb->q);
 }
 
-static void flush_plug_list(struct blk_plug *plug)
+/*
+ * If 'from_schedule' is true, then postpone the dispatch of requests
+ * until a safe kblockd context. We due this to avoid accidental big
+ * additional stack usage in driver dispatch, in places where the originally
+ * plugger did not intend it.
+ */
+static void queue_unplugged(struct request_queue *q, unsigned int depth,
+                           bool from_schedule)
+       __releases(q->queue_lock)
+{
+       trace_block_unplug(q, depth, !from_schedule);
+
+       /*
+        * If we are punting this to kblockd, then we can safely drop
+        * the queue_lock before waking kblockd (which needs to take
+        * this lock).
+        */
+       if (from_schedule) {
+               spin_unlock(q->queue_lock);
+               blk_run_queue_async(q);
+       } else {
+               __blk_run_queue(q);
+               spin_unlock(q->queue_lock);
+       }
+
+}
+
+static void flush_plug_callbacks(struct blk_plug *plug)
+{
+       LIST_HEAD(callbacks);
+
+       if (list_empty(&plug->cb_list))
+               return;
+
+       list_splice_init(&plug->cb_list, &callbacks);
+
+       while (!list_empty(&callbacks)) {
+               struct blk_plug_cb *cb = list_first_entry(&callbacks,
+                                                         struct blk_plug_cb,
+                                                         list);
+               list_del(&cb->list);
+               cb->callback(cb);
+       }
+}
+
+void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
 {
        struct request_queue *q;
        unsigned long flags;
        struct request *rq;
+       LIST_HEAD(list);
+       unsigned int depth;
 
        BUG_ON(plug->magic != PLUG_MAGIC);
 
+       flush_plug_callbacks(plug);
        if (list_empty(&plug->list))
                return;
 
-       if (plug->should_sort)
-               list_sort(NULL, &plug->list, plug_rq_cmp);
+       list_splice_init(&plug->list, &list);
+
+       if (plug->should_sort) {
+               list_sort(NULL, &list, plug_rq_cmp);
+               plug->should_sort = 0;
+       }
 
        q = NULL;
+       depth = 0;
+
+       /*
+        * Save and disable interrupts here, to avoid doing it for every
+        * queue lock we have to take.
+        */
        local_irq_save(flags);
-       while (!list_empty(&plug->list)) {
-               rq = list_entry_rq(plug->list.next);
+       while (!list_empty(&list)) {
+               rq = list_entry_rq(list.next);
                list_del_init(&rq->queuelist);
                BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
                BUG_ON(!rq->q);
                if (rq->q != q) {
-                       if (q) {
-                               __blk_run_queue(q, false);
-                               spin_unlock(q->queue_lock);
-                       }
+                       /*
+                        * This drops the queue lock
+                        */
+                       if (q)
+                               queue_unplugged(q, depth, from_schedule);
                        q = rq->q;
+                       depth = 0;
                        spin_lock(q->queue_lock);
                }
                rq->cmd_flags &= ~REQ_ON_PLUG;
@@ -2706,38 +2767,27 @@ static void flush_plug_list(struct blk_plug *plug)
                        __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH);
                else
                        __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE);
-       }
 
-       if (q) {
-               __blk_run_queue(q, false);
-               spin_unlock(q->queue_lock);
+               depth++;
        }
 
-       BUG_ON(!list_empty(&plug->list));
-       local_irq_restore(flags);
-}
-
-static void __blk_finish_plug(struct task_struct *tsk, struct blk_plug *plug)
-{
-       flush_plug_list(plug);
+       /*
+        * This drops the queue lock
+        */
+       if (q)
+               queue_unplugged(q, depth, from_schedule);
 
-       if (plug == tsk->plug)
-               tsk->plug = NULL;
+       local_irq_restore(flags);
 }
 
 void blk_finish_plug(struct blk_plug *plug)
 {
-       if (plug)
-               __blk_finish_plug(current, plug);
-}
-EXPORT_SYMBOL(blk_finish_plug);
+       blk_flush_plug_list(plug, false);
 
-void __blk_flush_plug(struct task_struct *tsk, struct blk_plug *plug)
-{
-       __blk_finish_plug(tsk, plug);
-       tsk->plug = plug;
+       if (plug == current->plug)
+               current->plug = NULL;
 }
-EXPORT_SYMBOL(__blk_flush_plug);
+EXPORT_SYMBOL(blk_finish_plug);
 
 int __init blk_dev_init(void)
 {
index 7482b7fa863ba10b337d7547fb7040767e02b2da..81e31819a597bb0c6ed6dd4f781eb037c986a243 100644 (file)
@@ -55,7 +55,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        WARN_ON(irqs_disabled());
        spin_lock_irq(q->queue_lock);
        __elv_add_request(q, rq, where);
-       __blk_run_queue(q, false);
+       __blk_run_queue(q);
        /* the queue is stopped so it won't be plugged+unplugged */
        if (rq->cmd_type == REQ_TYPE_PM_RESUME)
                q->request_fn(q);
index eba4a2790c6c4ba2e0467ca58300050e190d6804..6c9b5e189e624888860e5185d1d9b3479b3e49a4 100644 (file)
@@ -218,7 +218,7 @@ static void flush_end_io(struct request *flush_rq, int error)
         * request_fn may confuse the driver.  Always use kblockd.
         */
        if (queued)
-               __blk_run_queue(q, true);
+               blk_run_queue_async(q);
 }
 
 /**
@@ -274,7 +274,7 @@ static void flush_data_end_io(struct request *rq, int error)
         * the comment in flush_end_io().
         */
        if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error))
-               __blk_run_queue(q, true);
+               blk_run_queue_async(q);
 }
 
 /**
index 261c75c665ae381a4c12dd444f7ed3b847c155a0..bd236313f35d59bd08da5a3d375cc29eed6fd86f 100644 (file)
@@ -66,14 +66,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
 
        if (rl->count[BLK_RW_SYNC] >= q->nr_requests) {
                blk_set_queue_full(q, BLK_RW_SYNC);
-       } else if (rl->count[BLK_RW_SYNC]+1 <= q->nr_requests) {
+       } else {
                blk_clear_queue_full(q, BLK_RW_SYNC);
                wake_up(&rl->wait[BLK_RW_SYNC]);
        }
 
        if (rl->count[BLK_RW_ASYNC] >= q->nr_requests) {
                blk_set_queue_full(q, BLK_RW_ASYNC);
-       } else if (rl->count[BLK_RW_ASYNC]+1 <= q->nr_requests) {
+       } else {
                blk_clear_queue_full(q, BLK_RW_ASYNC);
                wake_up(&rl->wait[BLK_RW_ASYNC]);
        }
@@ -498,7 +498,6 @@ int blk_register_queue(struct gendisk *disk)
 {
        int ret;
        struct device *dev = disk_to_dev(disk);
-
        struct request_queue *q = disk->queue;
 
        if (WARN_ON(!q))
@@ -509,8 +508,10 @@ int blk_register_queue(struct gendisk *disk)
                return ret;
 
        ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue");
-       if (ret < 0)
+       if (ret < 0) {
+               blk_trace_remove_sysfs(dev);
                return ret;
+       }
 
        kobject_uevent(&q->kobj, KOBJ_ADD);
 
@@ -521,7 +522,7 @@ int blk_register_queue(struct gendisk *disk)
        if (ret) {
                kobject_uevent(&q->kobj, KOBJ_REMOVE);
                kobject_del(&q->kobj);
-               blk_trace_remove_sysfs(disk_to_dev(disk));
+               blk_trace_remove_sysfs(dev);
                kobject_put(&dev->kobj);
                return ret;
        }
index 3be881ec95ad06fa95ce0710dddb81f0cbef1c50..5b52011e3a40a38c1235e1729554abfbb9f99c7d 100644 (file)
@@ -2582,28 +2582,20 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
 }
 
 /*
- * Must always be called with the rcu_read_lock() held
+ * Call func for each cic attached to this ioc.
  */
 static void
-__call_for_each_cic(struct io_context *ioc,
-                   void (*func)(struct io_context *, struct cfq_io_context *))
+call_for_each_cic(struct io_context *ioc,
+                 void (*func)(struct io_context *, struct cfq_io_context *))
 {
        struct cfq_io_context *cic;
        struct hlist_node *n;
 
+       rcu_read_lock();
+
        hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list)
                func(ioc, cic);
-}
 
-/*
- * Call func for each cic attached to this ioc.
- */
-static void
-call_for_each_cic(struct io_context *ioc,
-                 void (*func)(struct io_context *, struct cfq_io_context *))
-{
-       rcu_read_lock();
-       __call_for_each_cic(ioc, func);
        rcu_read_unlock();
 }
 
@@ -2664,7 +2656,7 @@ static void cfq_free_io_context(struct io_context *ioc)
         * should be ok to iterate over the known list, we will see all cic's
         * since no new ones are added.
         */
-       __call_for_each_cic(ioc, cic_free_func);
+       call_for_each_cic(ioc, cic_free_func);
 }
 
 static void cfq_put_cooperator(struct cfq_queue *cfqq)
@@ -3368,7 +3360,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                            cfqd->busy_queues > 1) {
                                cfq_del_timer(cfqd, cfqq);
                                cfq_clear_cfqq_wait_request(cfqq);
-                               __blk_run_queue(cfqd->queue, false);
+                               __blk_run_queue(cfqd->queue);
                        } else {
                                cfq_blkiocg_update_idle_time_stats(
                                                &cfqq->cfqg->blkg);
@@ -3383,7 +3375,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 * this new queue is RT and the current one is BE
                 */
                cfq_preempt_queue(cfqd, cfqq);
-               __blk_run_queue(cfqd->queue, false);
+               __blk_run_queue(cfqd->queue);
        }
 }
 
@@ -3743,7 +3735,7 @@ static void cfq_kick_queue(struct work_struct *work)
        struct request_queue *q = cfqd->queue;
 
        spin_lock_irq(q->queue_lock);
-       __blk_run_queue(cfqd->queue, false);
+       __blk_run_queue(cfqd->queue);
        spin_unlock_irq(q->queue_lock);
 }
 
index 0cdb4e7ebab4e8eba1e7ca1514525c1120948e5b..45ca1e34f58249ff5b3838c0ec89fbc1c6ea2bb7 100644 (file)
@@ -642,7 +642,7 @@ void elv_quiesce_start(struct request_queue *q)
         */
        elv_drain_elevator(q);
        while (q->rq.elvpriv) {
-               __blk_run_queue(q, false);
+               __blk_run_queue(q);
                spin_unlock_irq(q->queue_lock);
                msleep(10);
                spin_lock_irq(q->queue_lock);
@@ -671,7 +671,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
                        q->boundary_rq = rq;
                }
        } else if (!(rq->cmd_flags & REQ_ELVPRIV) &&
-                   where == ELEVATOR_INSERT_SORT)
+                   (where == ELEVATOR_INSERT_SORT ||
+                    where == ELEVATOR_INSERT_SORT_MERGE))
                where = ELEVATOR_INSERT_BACK;
 
        switch (where) {
@@ -695,7 +696,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
                 *   with anything.  There's no point in delaying queue
                 *   processing.
                 */
-               __blk_run_queue(q, false);
+               __blk_run_queue(q);
                break;
 
        case ELEVATOR_INSERT_SORT_MERGE:
index b364bd038a18f76fc5461d5f9c7e1186d696fb31..2dd988723d73e98880d271b84dc77ef36b49a0a9 100644 (file)
@@ -1588,9 +1588,13 @@ static void disk_events_workfn(struct work_struct *work)
 
        spin_unlock_irq(&ev->lock);
 
-       /* tell userland about new events */
+       /*
+        * Tell userland about new events.  Only the events listed in
+        * @disk->events are reported.  Unlisted events are processed the
+        * same internally but never get reported to userland.
+        */
        for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
-               if (events & (1 << i))
+               if (events & disk->events & (1 << i))
                        envp[nr_events++] = disk_uevents[i];
 
        if (nr_events)
index b136c9c1e531954dc27cc4bed422e1618e7681ee..449c556274c052cf4c9fd221c577b7735bcdca0f 100644 (file)
@@ -943,6 +943,10 @@ static int acpi_bus_get_flags(struct acpi_device *device)
        if (ACPI_SUCCESS(status))
                device->flags.lockable = 1;
 
+       /* Power resources cannot be power manageable. */
+       if (device->device_type == ACPI_BUS_TYPE_POWER)
+               return 0;
+
        /* Presence of _PS0|_PR0 indicates 'power manageable' */
        status = acpi_get_handle(device->handle, "_PS0", &temp);
        if (ACPI_FAILURE(status))
index 8210405031544e900bcc97f6a7d21c43a02923fb..7025593a58c89d39cb3ff260801b242730d8fdf2 100644 (file)
@@ -214,7 +214,7 @@ static int amba_pm_resume_noirq(struct device *dev)
 
 #endif /* !CONFIG_SUSPEND */
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 
 static int amba_pm_freeze(struct device *dev)
 {
@@ -352,7 +352,7 @@ static int amba_pm_restore_noirq(struct device *dev)
        return ret;
 }
 
-#else /* !CONFIG_HIBERNATION */
+#else /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #define amba_pm_freeze         NULL
 #define amba_pm_thaw           NULL
@@ -363,7 +363,7 @@ static int amba_pm_restore_noirq(struct device *dev)
 #define amba_pm_poweroff_noirq NULL
 #define amba_pm_restore_noirq  NULL
 
-#endif /* !CONFIG_HIBERNATION */
+#endif /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #ifdef CONFIG_PM
 
index 39d829cd82dd4dfae5f87ee59bdb9f0f300ede8c..71afe0371311d7475e7034bb5ab1e483b2d3ce68 100644 (file)
@@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = {
        {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
                                 AHCI_HFLAG_YES_NCQ),
-               .flags          = AHCI_FLAG_COMMON,
+               .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
                .pio_mask       = ATA_PIO4,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
@@ -261,6 +261,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
        { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
        { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
+       { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
+       { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
+       { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
+       { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
index 39865009c25117410ba99f1a17141e8fd724dbe5..12c5282e7fca9c6effe1c42a2a7dae0a78395b2e 100644 (file)
@@ -229,6 +229,10 @@ enum {
        EM_CTL_ALHD             = (1 << 26), /* Activity LED */
        EM_CTL_XMT              = (1 << 25), /* Transmit Only */
        EM_CTL_SMB              = (1 << 24), /* Single Message Buffer */
+       EM_CTL_SGPIO            = (1 << 19), /* SGPIO messages supported */
+       EM_CTL_SES              = (1 << 18), /* SES-2 messages supported */
+       EM_CTL_SAFTE            = (1 << 17), /* SAF-TE messages supported */
+       EM_CTL_LED              = (1 << 16), /* LED messages supported */
 
        /* em message type */
        EM_MSG_TYPE_LED         = (1 << 0), /* LED */
index 0bc3fd6c3fdb8ea2f979f0a57b135ecc57a6e770..6f6e7718b05c7ff905ab3ad068aaa15160992581 100644 (file)
@@ -309,6 +309,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
        /* SATA Controller IDE (PBG) */
        { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* SATA Controller IDE (Panther Point) */
+       { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+       /* SATA Controller IDE (Panther Point) */
+       { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+       /* SATA Controller IDE (Panther Point) */
+       { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* SATA Controller IDE (Panther Point) */
+       { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
        { }     /* terminate list */
 };
 
index 26d452339e98f59fc483cbc85e9c53f56b2a0183..ff9d832a163de8442c2adc1d8fa18be75ec4f417 100644 (file)
@@ -109,6 +109,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
 static ssize_t ahci_store_em_buffer(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t size);
+static ssize_t ahci_show_em_supported(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
 
 static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
 static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
@@ -116,6 +118,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
 static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
 static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
                   ahci_read_em_buffer, ahci_store_em_buffer);
+static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
 
 struct device_attribute *ahci_shost_attrs[] = {
        &dev_attr_link_power_management_policy,
@@ -126,6 +129,7 @@ struct device_attribute *ahci_shost_attrs[] = {
        &dev_attr_ahci_host_version,
        &dev_attr_ahci_port_cmd,
        &dev_attr_em_buffer,
+       &dev_attr_em_message_supported,
        NULL
 };
 EXPORT_SYMBOL_GPL(ahci_shost_attrs);
@@ -343,6 +347,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
        return size;
 }
 
+static ssize_t ahci_show_em_supported(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ata_port *ap = ata_shost_to_port(shost);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->mmio;
+       u32 em_ctl;
+
+       em_ctl = readl(mmio + HOST_EM_CTL);
+
+       return sprintf(buf, "%s%s%s%s\n",
+                      em_ctl & EM_CTL_LED ? "led " : "",
+                      em_ctl & EM_CTL_SAFTE ? "saf-te " : "",
+                      em_ctl & EM_CTL_SES ? "ses-2 " : "",
+                      em_ctl & EM_CTL_SGPIO ? "sgpio " : "");
+}
+
 /**
  *     ahci_save_initial_config - Save and fixup initial config values
  *     @dev: target AHCI device
@@ -539,6 +561,27 @@ void ahci_start_engine(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
+       u8 status;
+
+       status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+
+       /*
+        * At end of section 10.1 of AHCI spec (rev 1.3), it states
+        * Software shall not set PxCMD.ST to 1 until it is determined
+        * that a functoinal device is present on the port as determined by
+        * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h
+        *
+        * Even though most AHCI host controllers work without this check,
+        * specific controller will fail under this condition
+        */
+       if (status & (ATA_BUSY | ATA_DRQ))
+               return;
+       else {
+               ahci_scr_read(&ap->link, SCR_STATUS, &tmp);
+
+               if ((tmp & 0xf) != 0x3)
+                       return;
+       }
 
        /* start DMA */
        tmp = readl(port_mmio + PORT_CMD);
@@ -1897,7 +1940,17 @@ static void ahci_pmp_attach(struct ata_port *ap)
        ahci_enable_fbs(ap);
 
        pp->intr_mask |= PORT_IRQ_BAD_PMP;
-       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+       /*
+        * We must not change the port interrupt mask register if the
+        * port is marked frozen, the value in pp->intr_mask will be
+        * restored later when the port is thawed.
+        *
+        * Note that during initialization, the port is marked as
+        * frozen since the irq handler is not yet registered.
+        */
+       if (!(ap->pflags & ATA_PFLAG_FROZEN))
+               writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
 
 static void ahci_pmp_detach(struct ata_port *ap)
@@ -1913,7 +1966,10 @@ static void ahci_pmp_detach(struct ata_port *ap)
        writel(cmd, port_mmio + PORT_CMD);
 
        pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
-       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+       /* see comment above in ahci_pmp_attach() */
+       if (!(ap->pflags & ATA_PFLAG_FROZEN))
+               writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
 
 int ahci_port_resume(struct ata_port *ap)
index 423c0a6952b25af341bdd0360656af2be09019ff..76c3c15cb1e66680e11f9c5fb670d616e564acc5 100644 (file)
@@ -4139,6 +4139,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-212D",   "1.28", ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-216D",   "1.08", ATA_HORKAGE_NOSETXFER },
 
        /* End Marker */
        { }
@@ -5480,7 +5481,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        if (!ap)
                return NULL;
 
-       ap->pflags |= ATA_PFLAG_INITIALIZING;
+       ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
        ap->lock = &host->lock;
        ap->print_id = -1;
        ap->host = host;
index 88cd22fa65cd82057b217f7b36a5e8657d910781..f26f2fe3480ad0847b6ce059a0b4206e182a9f46 100644 (file)
@@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
        struct ata_eh_context *ehc = &link->eh_context;
        struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
        enum ata_lpm_policy old_policy = link->lpm_policy;
+       bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM;
        unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
        unsigned int err_mask;
        int rc;
@@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
         */
        ata_for_each_dev(dev, link, ENABLED) {
                bool hipm = ata_id_has_hipm(dev->id);
-               bool dipm = ata_id_has_dipm(dev->id);
+               bool dipm = ata_id_has_dipm(dev->id) && !no_dipm;
 
                /* find the first enabled and LPM enabled devices */
                if (!link_dev)
@@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
 
        /* host config updated, enable DIPM if transitioning to MIN_POWER */
        ata_for_each_dev(dev, link, ENABLED) {
-               if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
+               if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
+                   ata_id_has_dipm(dev->id)) {
                        err_mask = ata_dev_set_feature(dev,
                                        SETFEATURES_SATA_ENABLE, SATA_DIPM);
                        if (err_mask && err_mask != AC_ERR_DEV) {
index 0da0dcc7dd089427a988171c3f1a8b62c1b8f90f..a5fdbdcb0faf2ed8daa5c4fa77767da6cc3fa7ea 100644 (file)
 
 
 #define DRV_NAME "pata_at91"
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
 
 #define CF_IDE_OFFSET      0x00c00000
 #define CF_ALT_IDE_OFFSET   0x00e00000
 #define CF_IDE_RES_SIZE     0x08
+#define NCS_RD_PULSE_LIMIT  0x3f /* maximal value for pulse bitfields */
 
 struct at91_ide_info {
        unsigned long mode;
@@ -49,8 +50,18 @@ struct at91_ide_info {
        void __iomem *alt_addr;
 };
 
-static const struct ata_timing initial_timing =
-       {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+static const struct ata_timing initial_timing = {
+       .mode           = XFER_PIO_0,
+       .setup          = 70,
+       .act8b          = 290,
+       .rec8b          = 240,
+       .cyc8b          = 600,
+       .active         = 165,
+       .recover        = 150,
+       .dmack_hold     = 0,
+       .cycle          = 600,
+       .udma           = 0
+};
 
 static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
 {
@@ -109,6 +120,11 @@ static void set_smc_timing(struct device *dev,
        /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
        ncs_read_setup = 1;
        ncs_read_pulse = read_cycle - 2;
+       if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) {
+               ncs_read_pulse = NCS_RD_PULSE_LIMIT;
+               dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n",
+                       ncs_read_pulse);
+       }
 
        /* Write timings same as read timings */
        write_cycle = read_cycle;
index f051cfff18afe2e703bc6383d8b6277cdc652401..9e0e4fc24c46506e4adcfd6f4e429ad6ddced5f7 100644 (file)
@@ -149,6 +149,7 @@ static void platform_device_release(struct device *dev)
 
        of_device_node_put(&pa->pdev.dev);
        kfree(pa->pdev.dev.platform_data);
+       kfree(pa->pdev.mfd_cell);
        kfree(pa->pdev.resource);
        kfree(pa);
 }
@@ -771,7 +772,7 @@ int __weak platform_pm_resume_noirq(struct device *dev)
 
 #endif /* !CONFIG_SUSPEND */
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 
 static int platform_pm_freeze(struct device *dev)
 {
@@ -909,7 +910,7 @@ static int platform_pm_restore_noirq(struct device *dev)
        return ret;
 }
 
-#else /* !CONFIG_HIBERNATION */
+#else /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #define platform_pm_freeze             NULL
 #define platform_pm_thaw               NULL
@@ -920,7 +921,7 @@ static int platform_pm_restore_noirq(struct device *dev)
 #define platform_pm_poweroff_noirq     NULL
 #define platform_pm_restore_noirq      NULL
 
-#endif /* !CONFIG_HIBERNATION */
+#endif /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #ifdef CONFIG_PM_RUNTIME
 
index 052dc53eef388db918f2a0f6ce961be366691577..abe3ab709e87ffe3340757b6ae80bad694caf2d8 100644 (file)
@@ -63,6 +63,7 @@ void device_pm_init(struct device *dev)
        dev->power.wakeup = NULL;
        spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
+       INIT_LIST_HEAD(&dev->power.entry);
 }
 
 /**
@@ -233,7 +234,7 @@ static int pm_op(struct device *dev,
                }
                break;
 #endif /* CONFIG_SUSPEND */
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
        case PM_EVENT_FREEZE:
        case PM_EVENT_QUIESCE:
                if (ops->freeze) {
@@ -260,7 +261,7 @@ static int pm_op(struct device *dev,
                        suspend_report_result(ops->restore, error);
                }
                break;
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
        default:
                error = -EINVAL;
        }
@@ -308,7 +309,7 @@ static int pm_noirq_op(struct device *dev,
                }
                break;
 #endif /* CONFIG_SUSPEND */
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
        case PM_EVENT_FREEZE:
        case PM_EVENT_QUIESCE:
                if (ops->freeze_noirq) {
@@ -335,7 +336,7 @@ static int pm_noirq_op(struct device *dev,
                        suspend_report_result(ops->restore_noirq, error);
                }
                break;
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
        default:
                error = -EINVAL;
        }
index 4573c83df6ddc4d996e342bc47bb54f717063474..abbbd33e8d8af8ebd82c27f0b1a298f2286d0373 100644 (file)
@@ -258,7 +258,7 @@ void device_set_wakeup_capable(struct device *dev, bool capable)
        if (!!dev->power.can_wakeup == !!capable)
                return;
 
-       if (device_is_registered(dev)) {
+       if (device_is_registered(dev) && !list_empty(&dev->power.entry)) {
                if (capable) {
                        if (wakeup_sysfs_add(dev))
                                return;
index 90af2943f9e4a56bb284aab6ce5bab177cfba794..c126db3cb7d12c92be4b5d62abfd58d4a699a961 100644 (file)
@@ -73,6 +73,7 @@ int syscore_suspend(void)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(syscore_suspend);
 
 /**
  * syscore_resume - Execute all the registered system core resume callbacks.
@@ -95,6 +96,7 @@ void syscore_resume(void)
                                "Interrupts enabled after %pF\n", ops->resume);
                }
 }
+EXPORT_SYMBOL_GPL(syscore_resume);
 #endif /* CONFIG_PM_SLEEP */
 
 /**
index 16dc3645291cd7bbb3eab203b83dde68939b61d7..3e904717c1c05f4dee56e040f9bf7df2faf57ce1 100644 (file)
@@ -777,9 +777,9 @@ static int rbd_do_request(struct request *rq,
                                      ops,
                                      false,
                                      GFP_NOIO, pages, bio);
-       if (IS_ERR(req)) {
+       if (!req) {
                up_read(&header->snap_rwsem);
-               ret = PTR_ERR(req);
+               ret = -ENOMEM;
                goto done_pages;
        }
 
index 012cba0d6d965219de4d286a855285eeab05ec23..b072648dc3f64904f60df2f58d230de06688024e 100644 (file)
@@ -115,6 +115,9 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
        struct agp_memory *new;
        unsigned long alloc_size = num_agp_pages*sizeof(struct page *);
 
+       if (INT_MAX/sizeof(struct page *) < num_agp_pages)
+               return NULL;
+
        new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL);
        if (new == NULL)
                return NULL;
@@ -234,11 +237,14 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
        int scratch_pages;
        struct agp_memory *new;
        size_t i;
+       int cur_memory;
 
        if (!bridge)
                return NULL;
 
-       if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
+       cur_memory = atomic_read(&bridge->current_memory_agp);
+       if ((cur_memory + page_count > bridge->max_memory_agp) ||
+           (cur_memory + page_count < page_count))
                return NULL;
 
        if (type >= AGP_USER_TYPES) {
@@ -1089,8 +1095,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
                return -EINVAL;
        }
 
-       /* AK: could wrap */
-       if ((pg_start + mem->page_count) > num_entries)
+       if (((pg_start + mem->page_count) > num_entries) ||
+           ((pg_start + mem->page_count) < pg_start))
                return -EINVAL;
 
        j = pg_start;
@@ -1124,7 +1130,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
        size_t i;
        struct agp_bridge_data *bridge;
-       int mask_type;
+       int mask_type, num_entries;
 
        bridge = mem->bridge;
        if (!bridge)
@@ -1136,6 +1142,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        if (type != mem->type)
                return -EINVAL;
 
+       num_entries = agp_num_entries();
+       if (((pg_start + mem->page_count) > num_entries) ||
+           ((pg_start + mem->page_count) < pg_start))
+               return -EINVAL;
+
        mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
        if (mask_type != 0) {
                /* The generic routines know nothing of memory types */
index 84b164d1eb2b16d29db4d87ed6a7d745fa1938bc..838568a7dbf56845755bf6e579142505a7172809 100644 (file)
@@ -1280,18 +1280,7 @@ static void unplug_port(struct port *port)
                spin_lock_irq(&pdrvdata_lock);
                list_del(&port->cons.list);
                spin_unlock_irq(&pdrvdata_lock);
-#if 0
-               /*
-                * hvc_remove() not called as removing one hvc port
-                * results in other hvc ports getting frozen.
-                *
-                * Once this is resolved in hvc, this functionality
-                * will be enabled.  Till that is done, the -EPIPE
-                * return from get_chars() above will help
-                * hvc_console.c to clean up on ports we remove here.
-                */
                hvc_remove(port->cons.hvc);
-#endif
        }
 
        /* Remove unused data this port might have received. */
index 0fc0a79852de0f919bd2ac9ac117533ed8a0f991..6db161f64ae0e9ab42a17f04608ab3ac18638141 100644 (file)
@@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex);
  * Then we take the most specific entry - with the following
  * order of precedence: dev+con > dev only > con only.
  */
-static struct clk *clk_find(const char *dev_id, const char *con_id)
+static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
 {
-       struct clk_lookup *p;
-       struct clk *clk = NULL;
+       struct clk_lookup *p, *cl = NULL;
        int match, best = 0;
 
        list_for_each_entry(p, &clocks, node) {
@@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id)
                }
 
                if (match > best) {
-                       clk = p->clk;
+                       cl = p;
                        if (match != 3)
                                best = match;
                        else
                                break;
                }
        }
-       return clk;
+       return cl;
 }
 
 struct clk *clk_get_sys(const char *dev_id, const char *con_id)
 {
-       struct clk *clk;
+       struct clk_lookup *cl;
 
        mutex_lock(&clocks_mutex);
-       clk = clk_find(dev_id, con_id);
-       if (clk && !__clk_get(clk))
-               clk = NULL;
+       cl = clk_find(dev_id, con_id);
+       if (cl && !__clk_get(cl->clk))
+               cl = NULL;
        mutex_unlock(&clocks_mutex);
 
-       return clk ? clk : ERR_PTR(-ENOENT);
+       return cl ? cl->clk : ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get_sys);
 
index d77005849af857935fe270725f2ee0d08561d265..219d88a0eeae07c1e963c4997f6894fe79046d2a 100644 (file)
@@ -142,6 +142,7 @@ static int cn_call_callback(struct sk_buff *skb)
                cbq->callback(msg, nsp);
                kfree_skb(skb);
                cn_queue_release_callback(cbq);
+               err = 0;
        }
 
        return err;
index 31e71c4fc83171e7da846740533f63131189327b..9a8bebcf6b177fa79e9635ecde71f05b2578e798 100644 (file)
@@ -211,8 +211,6 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
 
        scrubval = scrubval & 0x001F;
 
-       amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval);
-
        for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
                if (scrubrates[i].scrubval == scrubval) {
                        retval = scrubrates[i].bandwidth;
@@ -933,25 +931,74 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
 /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
 static u64 get_error_address(struct mce *m)
 {
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+       u64 addr;
        u8 start_bit = 1;
        u8 end_bit   = 47;
 
-       if (boot_cpu_data.x86 == 0xf) {
+       if (c->x86 == 0xf) {
                start_bit = 3;
                end_bit   = 39;
        }
 
-       return m->addr & GENMASK(start_bit, end_bit);
+       addr = m->addr & GENMASK(start_bit, end_bit);
+
+       /*
+        * Erratum 637 workaround
+        */
+       if (c->x86 == 0x15) {
+               struct amd64_pvt *pvt;
+               u64 cc6_base, tmp_addr;
+               u32 tmp;
+               u8 mce_nid, intlv_en;
+
+               if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
+                       return addr;
+
+               mce_nid = amd_get_nb_id(m->extcpu);
+               pvt     = mcis[mce_nid]->pvt_info;
+
+               amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
+               intlv_en = tmp >> 21 & 0x7;
+
+               /* add [47:27] + 3 trailing bits */
+               cc6_base  = (tmp & GENMASK(0, 20)) << 3;
+
+               /* reverse and add DramIntlvEn */
+               cc6_base |= intlv_en ^ 0x7;
+
+               /* pin at [47:24] */
+               cc6_base <<= 24;
+
+               if (!intlv_en)
+                       return cc6_base | (addr & GENMASK(0, 23));
+
+               amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp);
+
+                                                       /* faster log2 */
+               tmp_addr  = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1);
+
+               /* OR DramIntlvSel into bits [14:12] */
+               tmp_addr |= (tmp & GENMASK(21, 23)) >> 9;
+
+               /* add remaining [11:0] bits from original MC4_ADDR */
+               tmp_addr |= addr & GENMASK(0, 11);
+
+               return cc6_base | tmp_addr;
+       }
+
+       return addr;
 }
 
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 {
+       struct cpuinfo_x86 *c = &boot_cpu_data;
        int off = range << 3;
 
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
 
-       if (boot_cpu_data.x86 == 0xf)
+       if (c->x86 == 0xf)
                return;
 
        if (!dram_rw(pvt, range))
@@ -959,6 +1006,31 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
+
+       /* Factor in CC6 save area by reading dst node's limit reg */
+       if (c->x86 == 0x15) {
+               struct pci_dev *f1 = NULL;
+               u8 nid = dram_dst_node(pvt, range);
+               u32 llim;
+
+               f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
+               if (WARN_ON(!f1))
+                       return;
+
+               amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
+
+               pvt->ranges[range].lim.lo &= GENMASK(0, 15);
+
+                                           /* {[39:27],111b} */
+               pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
+
+               pvt->ranges[range].lim.hi &= GENMASK(0, 7);
+
+                                           /* [47:40] */
+               pvt->ranges[range].lim.hi |= llim >> 13;
+
+               pci_dev_put(f1);
+       }
 }
 
 static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1403,12 +1475,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
                return -EINVAL;
        }
 
-       if (intlv_en &&
-           (intlv_sel != ((sys_addr >> 12) & intlv_en))) {
-               amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n",
-                          intlv_en, intlv_sel);
+       if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en)))
                return -EINVAL;
-       }
 
        sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
 
index 11be36a311eb55d312178e8e6886f6abc6594cd8..9a666cb985b2bd446edba7c249f3740d23e49d8e 100644 (file)
 
 #define DCT_CFG_SEL                    0x10C
 
+#define DRAM_LOCAL_NODE_BASE           0x120
+#define DRAM_LOCAL_NODE_LIM            0x124
+
 #define DRAM_BASE_HI                   0x140
 #define DRAM_LIMIT_HI                  0x144
 
index 26343fd46596da9d44e5fdc6f20ab71d10f5f0ce..29ffa350bfbe00281376c61c5c5c9c8434098a37 100644 (file)
@@ -458,13 +458,13 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
                return -EINVAL;
 
        new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
-       if (new_bw >= 0) {
-               edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw);
-               return count;
+       if (new_bw < 0) {
+               edac_printk(KERN_WARNING, EDAC_MC,
+                           "Error setting scrub rate to: %lu\n", bandwidth);
+               return -EINVAL;
        }
 
-       edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth);
-       return -EINVAL;
+       return count;
 }
 
 /*
@@ -483,7 +483,6 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
                return bandwidth;
        }
 
-       edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth);
        return sprintf(data, "%d\n", bandwidth);
 }
 
index f903d7b6f34a92bca580b5ed01cf422c9a8caf7c..23d1468ad253d54c9c0745a858b6b155123e76e7 100644 (file)
@@ -2199,7 +2199,6 @@ static int ohci_set_config_rom(struct fw_card *card,
 {
        struct fw_ohci *ohci;
        unsigned long flags;
-       int ret = -EBUSY;
        __be32 *next_config_rom;
        dma_addr_t uninitialized_var(next_config_rom_bus);
 
@@ -2240,22 +2239,37 @@ static int ohci_set_config_rom(struct fw_card *card,
 
        spin_lock_irqsave(&ohci->lock, flags);
 
+       /*
+        * If there is not an already pending config_rom update,
+        * push our new allocation into the ohci->next_config_rom
+        * and then mark the local variable as null so that we
+        * won't deallocate the new buffer.
+        *
+        * OTOH, if there is a pending config_rom update, just
+        * use that buffer with the new config_rom data, and
+        * let this routine free the unused DMA allocation.
+        */
+
        if (ohci->next_config_rom == NULL) {
                ohci->next_config_rom = next_config_rom;
                ohci->next_config_rom_bus = next_config_rom_bus;
+               next_config_rom = NULL;
+       }
 
-               copy_config_rom(ohci->next_config_rom, config_rom, length);
+       copy_config_rom(ohci->next_config_rom, config_rom, length);
 
-               ohci->next_header = config_rom[0];
-               ohci->next_config_rom[0] = 0;
+       ohci->next_header = config_rom[0];
+       ohci->next_config_rom[0] = 0;
 
-               reg_write(ohci, OHCI1394_ConfigROMmap,
-                         ohci->next_config_rom_bus);
-               ret = 0;
-       }
+       reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
 
        spin_unlock_irqrestore(&ohci->lock, flags);
 
+       /* If we didn't use the DMA allocation, delete it. */
+       if (next_config_rom != NULL)
+               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                 next_config_rom, next_config_rom_bus);
+
        /*
         * Now initiate a bus reset to have the changes take
         * effect. We clean up the old config rom memory and DMA
@@ -2263,13 +2277,10 @@ static int ohci_set_config_rom(struct fw_card *card,
         * controller could need to access it before the bus reset
         * takes effect.
         */
-       if (ret == 0)
-               fw_schedule_bus_reset(&ohci->card, true, true);
-       else
-               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-                                 next_config_rom, next_config_rom_bus);
 
-       return ret;
+       fw_schedule_bus_reset(&ohci->card, true, true);
+
+       return 0;
 }
 
 static void ohci_send_request(struct fw_card *card, struct fw_packet *packet)
index a6feb78c404c33a9f0c98f9f44cd57aef226874b..b493663c7ba717a0652e45b456fac3d95aa56de4 100644 (file)
@@ -24,6 +24,7 @@ config DRM_KMS_HELPER
        depends on DRM
        select FB
        select FRAMEBUFFER_CONSOLE if !EXPERT
+       select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE
        help
          FB and CRTC helpers for KMS drivers.
 
@@ -96,6 +97,7 @@ config DRM_I915
        # i915 depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_CLASS_DEVICE if ACPI
+       select VIDEO_OUTPUT_CONTROL if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
        select ACPI_BUTTON if ACPI
index 950720473967069ff093712b172446183a7c493f..11d7a72c22d9141697697db81b375e15a8a15f0b 100644 (file)
@@ -342,9 +342,22 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+{
+       bool error = false;
+       int i, ret;
+       for (i = 0; i < fb_helper->crtc_count; i++) {
+               struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+               ret = drm_crtc_helper_set_config(mode_set);
+               if (ret)
+                       error = true;
+       }
+       return error;
+}
+EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
+
 bool drm_fb_helper_force_kernel_mode(void)
 {
-       int i = 0;
        bool ret, error = false;
        struct drm_fb_helper *helper;
 
@@ -352,12 +365,12 @@ bool drm_fb_helper_force_kernel_mode(void)
                return false;
 
        list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-               for (i = 0; i < helper->crtc_count; i++) {
-                       struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
-                       ret = drm_crtc_helper_set_config(mode_set);
-                       if (ret)
-                               error = true;
-               }
+               if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+                       continue;
+
+               ret = drm_fb_helper_restore_fbdev_mode(helper);
+               if (ret)
+                       error = true;
        }
        return error;
 }
index 741457bd1c46ef1f54af12296e348a053430329e..a1f12cb043deb233484f9a4957300fa475c3a024 100644 (file)
@@ -932,11 +932,34 @@ EXPORT_SYMBOL(drm_vblank_put);
 
 void drm_vblank_off(struct drm_device *dev, int crtc)
 {
+       struct drm_pending_vblank_event *e, *t;
+       struct timeval now;
        unsigned long irqflags;
+       unsigned int seq;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        vblank_disable_and_save(dev, crtc);
        DRM_WAKEUP(&dev->vbl_queue[crtc]);
+
+       /* Send any queued vblank events, lest the natives grow disquiet */
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+               if (e->pipe != crtc)
+                       continue;
+               DRM_DEBUG("Sending premature vblank event on disable: \
+                         wanted %d, current %d\n",
+                         e->event.sequence, seq);
+
+               e->event.sequence = seq;
+               e->event.tv_sec = now.tv_sec;
+               e->event.tv_usec = now.tv_usec;
+               drm_vblank_put(dev, e->pipe);
+               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+               wake_up_interruptible(&e->base.file_priv->event_wait);
+               trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
+                                                e->event.sequence);
+       }
+
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 EXPORT_SYMBOL(drm_vblank_off);
index 5d00b0fc0d91d837f6aa47b49901cb04bd6db1c0..959186cbf3280b90b911ff54373531ee577eef97 100644 (file)
@@ -431,7 +431,7 @@ EXPORT_SYMBOL(drm_mm_search_free_in_range);
 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
 {
        list_replace(&old->node_list, &new->node_list);
-       list_replace(&old->node_list, &new->hole_stack);
+       list_replace(&old->hole_stack, &new->hole_stack);
        new->hole_follows = old->hole_follows;
        new->mm = old->mm;
        new->start = old->start;
@@ -699,8 +699,8 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
                                entry->size);
                total_used += entry->size;
                if (entry->hole_follows) {
-                       hole_start = drm_mm_hole_node_start(&mm->head_node);
-                       hole_end = drm_mm_hole_node_end(&mm->head_node);
+                       hole_start = drm_mm_hole_node_start(entry);
+                       hole_end = drm_mm_hole_node_end(entry);
                        hole_size = hole_end - hole_start;
                        seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
                                        hole_start, hole_end, hole_size);
index 72730377a01b7cac5fec231c2fd93e5b81b01f99..12876f2795d2b373d9cac4130ec0052b44db23e6 100644 (file)
@@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
-               drm_fb_helper_restore();
+               intel_fb_restore_mode(dev);
                vga_switcheroo_process_delayed_switch();
                return;
        }
index 432fc04c6bffc1b58d8da1645a8a5687049a9bc2..373c2a005ec1821f07a72cb49aad5bd823df753f 100644 (file)
@@ -3771,8 +3771,11 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        int entries, tlb_miss;
 
        crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled)
+       if (crtc->fb == NULL || !crtc->enabled) {
+               *cursor_wm = cursor->guard_size;
+               *plane_wm = display->guard_size;
                return false;
+       }
 
        htotal = crtc->mode.htotal;
        hdisplay = crtc->mode.hdisplay;
@@ -5151,8 +5154,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        I915_WRITE(DSPCNTR(plane), dspcntr);
        POSTING_READ(DSPCNTR(plane));
-       if (!HAS_PCH_SPLIT(dev))
-               intel_enable_plane(dev_priv, plane, pipe);
 
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
@@ -5602,9 +5603,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
        intel_clock_t clock;
 
        if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
-               fp = FP0(pipe);
+               fp = I915_READ(FP0(pipe));
        else
-               fp = FP1(pipe);
+               fp = I915_READ(FP1(pipe));
 
        clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
        if (IS_PINEVIEW(dev)) {
@@ -6215,36 +6216,6 @@ cleanup_work:
        return ret;
 }
 
-static void intel_crtc_reset(struct drm_crtc *crtc)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       /* Reset flags back to the 'unknown' status so that they
-        * will be correctly set on the initial modeset.
-        */
-       intel_crtc->dpms_mode = -1;
-}
-
-static struct drm_crtc_helper_funcs intel_helper_funcs = {
-       .dpms = intel_crtc_dpms,
-       .mode_fixup = intel_crtc_mode_fixup,
-       .mode_set = intel_crtc_mode_set,
-       .mode_set_base = intel_pipe_set_base,
-       .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .load_lut = intel_crtc_load_lut,
-       .disable = intel_crtc_disable,
-};
-
-static const struct drm_crtc_funcs intel_crtc_funcs = {
-       .reset = intel_crtc_reset,
-       .cursor_set = intel_crtc_cursor_set,
-       .cursor_move = intel_crtc_cursor_move,
-       .gamma_set = intel_crtc_gamma_set,
-       .set_config = drm_crtc_helper_set_config,
-       .destroy = intel_crtc_destroy,
-       .page_flip = intel_crtc_page_flip,
-};
-
 static void intel_sanitize_modesetting(struct drm_device *dev,
                                       int pipe, int plane)
 {
@@ -6281,6 +6252,42 @@ static void intel_sanitize_modesetting(struct drm_device *dev,
        intel_disable_pipe(dev_priv, pipe);
 }
 
+static void intel_crtc_reset(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       /* Reset flags back to the 'unknown' status so that they
+        * will be correctly set on the initial modeset.
+        */
+       intel_crtc->dpms_mode = -1;
+
+       /* We need to fix up any BIOS configuration that conflicts with
+        * our expectations.
+        */
+       intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
+}
+
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
+       .dpms = intel_crtc_dpms,
+       .mode_fixup = intel_crtc_mode_fixup,
+       .mode_set = intel_crtc_mode_set,
+       .mode_set_base = intel_pipe_set_base,
+       .mode_set_base_atomic = intel_pipe_set_base_atomic,
+       .load_lut = intel_crtc_load_lut,
+       .disable = intel_crtc_disable,
+};
+
+static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .reset = intel_crtc_reset,
+       .cursor_set = intel_crtc_cursor_set,
+       .cursor_move = intel_crtc_cursor_move,
+       .gamma_set = intel_crtc_gamma_set,
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = intel_crtc_destroy,
+       .page_flip = intel_crtc_page_flip,
+};
+
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -6330,8 +6337,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
                    (unsigned long)intel_crtc);
-
-       intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
 }
 
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -6572,8 +6577,10 @@ intel_user_framebuffer_create(struct drm_device *dev,
                return ERR_PTR(-ENOENT);
 
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb)
+       if (!intel_fb) {
+               drm_gem_object_unreference_unlocked(&obj->base);
                return ERR_PTR(-ENOMEM);
+       }
 
        ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
        if (ret) {
index cb8578b7e4432c1aad04f79324be3d588c1e74e0..a4d80314e7f8cf5edb13bce97328a60f1f26f6ce 100644 (file)
@@ -1470,7 +1470,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        if (!HAS_PCH_CPT(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+               struct drm_crtc *crtc = intel_dp->base.base.crtc;
+
                /* Hardware workaround: leaving our transcoder select
                 * set to transcoder B while it's off will prevent the
                 * corresponding HDMI output on transcoder A.
@@ -1485,7 +1486,19 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                /* Changes to enable or select take place the vblank
                 * after being written.
                 */
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
+               if (crtc == NULL) {
+                       /* We can arrive here never having been attached
+                        * to a CRTC, for instance, due to inheriting
+                        * random state from the BIOS.
+                        *
+                        * If the pipe is not running, play safe and
+                        * wait for the clocks to stabilise before
+                        * continuing.
+                        */
+                       POSTING_READ(intel_dp->output_reg);
+                       msleep(50);
+               } else
+                       intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
        }
 
        I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
index f5b0d8306d8372142f8c649f815a170d348be99e..1d20712d527f1e5d38a192f59f2aa3c6493e5e53 100644 (file)
@@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
                               struct drm_file *file_priv);
 
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
+extern void intel_fb_restore_mode(struct drm_device *dev);
 #endif /* __INTEL_DRV_H__ */
index 512782728e5127aed5ea383efb7f4d79dd2b8cb7..ec49bae7338260d77cc6b78f9bc15d948303c1e8 100644 (file)
@@ -264,3 +264,13 @@ void intel_fb_output_poll_changed(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
 }
+
+void intel_fb_restore_mode(struct drm_device *dev)
+{
+       int ret;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
+       if (ret)
+               DRM_DEBUG("failed to restore crtc mode\n");
+}
index a562bd2648c7bb76f2db4df8a167f755db57ae1b..67cb076d271b5eb00a4c87a9022f0957f3ff569e 100644 (file)
@@ -539,6 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
        struct drm_device *dev = dev_priv->dev;
        struct drm_connector *connector = dev_priv->int_lvds_connector;
 
+       if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
+               return NOTIFY_OK;
+
        /*
         * check and update the status of LVDS connector after receiving
         * the LID nofication event.
index 4256b8ef3947454048d2d432c3375776983c3e06..6b22c1dcc015f406bf2fcdbc866511bc92f3d882 100644 (file)
@@ -1151,10 +1151,10 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                            (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
        {
                int pipeconf_reg = PIPECONF(pipe);
-               int dspcntr_reg = DSPCNTR(pipe);
+               int dspcntr_reg = DSPCNTR(intel_crtc->plane);
                int pipeconf = I915_READ(pipeconf_reg);
                int dspcntr = I915_READ(dspcntr_reg);
-               int dspbase_reg = DSPADDR(pipe);
+               int dspbase_reg = DSPADDR(intel_crtc->plane);
                int xpos = 0x0, ypos = 0x0;
                unsigned int xsize, ysize;
                /* Pipe must be off here */
@@ -1378,7 +1378,9 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        if (type < 0)
                return connector_status_disconnected;
 
+       intel_tv->type = type;
        intel_tv_find_better_format(connector);
+
        return connector_status_connected;
 }
 
@@ -1670,8 +1672,7 @@ intel_tv_init(struct drm_device *dev)
         *
         * More recent chipsets favour HDMI rather than integrated S-Video.
         */
-       connector->polled =
-               DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
index 8314a49b6b9a9e195250c92729a0f77168f6f44c..90aef64b76f277a649cd8e7caf79bfa40851cf3f 100644 (file)
@@ -269,7 +269,7 @@ struct init_tbl_entry {
        int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
 };
 
-static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
+static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *);
 
 #define MACRO_INDEX_SIZE       2
 #define MACRO_SIZE             8
@@ -2010,6 +2010,27 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        return 3;
 }
 
+static int
+init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_JUMP   opcode: 0x5C ('\')
+        *
+        * offset      (8  bit): opcode
+        * offset + 1  (16 bit): offset (in bios)
+        *
+        * Continue execution of init table from 'offset'
+        */
+
+       uint16_t jmp_offset = ROM16(bios->data[offset + 1]);
+
+       if (!iexec->execute)
+               return 3;
+
+       BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset);
+       return jmp_offset - offset;
+}
+
 static int
 init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
@@ -3659,6 +3680,7 @@ static struct init_tbl_entry itbl_entry[] = {
        { "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
        /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
        { "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
+       { "INIT_JUMP"                         , 0x5C, init_jump                       },
        { "INIT_I2C_IF"                       , 0x5E, init_i2c_if                     },
        { "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
        { "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
@@ -3700,8 +3722,7 @@ static struct init_tbl_entry itbl_entry[] = {
 #define MAX_TABLE_OPS 1000
 
 static int
-parse_init_table(struct nvbios *bios, unsigned int offset,
-                struct init_exec *iexec)
+parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
         * Parses all commands in an init table.
@@ -6333,6 +6354,32 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
                }
        }
 
+       /* XFX GT-240X-YA
+        *
+        * So many things wrong here, replace the entire encoder table..
+        */
+       if (nv_match_device(dev, 0x0ca3, 0x1682, 0x3003)) {
+               if (idx == 0) {
+                       *conn = 0x02001300; /* VGA, connector 1 */
+                       *conf = 0x00000028;
+               } else
+               if (idx == 1) {
+                       *conn = 0x01010312; /* DVI, connector 0 */
+                       *conf = 0x00020030;
+               } else
+               if (idx == 2) {
+                       *conn = 0x01010310; /* VGA, connector 0 */
+                       *conf = 0x00000028;
+               } else
+               if (idx == 3) {
+                       *conn = 0x02022362; /* HDMI, connector 2 */
+                       *conf = 0x00020010;
+               } else {
+                       *conn = 0x0000000e; /* EOL */
+                       *conf = 0x00000000;
+               }
+       }
+
        return true;
 }
 
index ce38e97b9428eaaaf81e248572555a80736c9242..568caedd7216e141a148753ea1dd55d8657ff261 100644 (file)
@@ -83,7 +83,7 @@ nouveau_dma_init(struct nouveau_channel *chan)
                return ret;
 
        /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
-       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000,
+       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
                                     &chan->m2mf_ntfy);
        if (ret)
                return ret;
index 57e5302503dbfc2fd804a95fd54aba1550ca682e..a76514a209b369880ac8b5ced881bb337a186695 100644 (file)
@@ -682,6 +682,9 @@ struct drm_nouveau_private {
        /* For PFIFO and PGRAPH. */
        spinlock_t context_switch_lock;
 
+       /* VM/PRAMIN flush, legacy PRAMIN aperture */
+       spinlock_t vm_lock;
+
        /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
        struct nouveau_ramht  *ramht;
        struct nouveau_gpuobj *ramfc;
@@ -1190,7 +1193,7 @@ extern int  nv50_graph_load_context(struct nouveau_channel *);
 extern int  nv50_graph_unload_context(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
 extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv86_graph_tlb_flush(struct drm_device *dev);
+extern void nv84_graph_tlb_flush(struct drm_device *dev);
 extern struct nouveau_enum nv50_data_error_names[];
 
 /* nvc0_graph.c */
index 889c4454682e674316685ac322b55b3960610dc1..39aee6d4daf869ab5c5c931bd7174b249aab10b5 100644 (file)
@@ -181,13 +181,13 @@ nouveau_fbcon_sync(struct fb_info *info)
                OUT_RING  (chan, 0);
        }
 
-       nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff);
+       nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff);
        FIRE_RING(chan);
        mutex_unlock(&chan->mutex);
 
        ret = -EBUSY;
        for (i = 0; i < 100000; i++) {
-               if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy + 3)) {
+               if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) {
                        ret = 0;
                        break;
                }
index 2683377f4131ed73b29a9d57282c04fab8874246..c3e953b089923d552de922e8007c13e1e8eb94e5 100644 (file)
@@ -152,8 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       nouveau_bo_ref(NULL, &dev_priv->vga_ram);
-
        ttm_bo_device_release(&dev_priv->ttm.bdev);
 
        nouveau_ttm_global_release(dev_priv);
@@ -398,7 +396,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
                        dma_bits = 40;
        } else
        if (drm_pci_device_is_pcie(dev) &&
-           dev_priv->chipset != 0x40 &&
+           dev_priv->chipset  > 0x40 &&
            dev_priv->chipset != 0x45) {
                if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39)))
                        dma_bits = 39;
@@ -552,6 +550,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
        u8 tRC;         /* Byte 9 */
        u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
        u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+       u8 magic_number = 0; /* Yeah... sorry*/
        u8 *mem = NULL, *entry;
        int i, recordlen, entries;
 
@@ -596,6 +595,12 @@ nouveau_mem_timing_init(struct drm_device *dev)
        if (!memtimings->timing)
                return;
 
+       /* Get "some number" from the timing reg for NV_40
+        * Used in calculations later */
+       if(dev_priv->card_type == NV_40) {
+               magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+       }
+
        entry = mem + mem[1];
        for (i = 0; i < entries; i++, entry += recordlen) {
                struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
@@ -635,36 +640,51 @@ nouveau_mem_timing_init(struct drm_device *dev)
 
                /* XXX: I don't trust the -1's and +1's... they must come
                 *      from somewhere! */
-               timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 |
+               timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
                                      tUNK_18 << 16 |
-                                     (tUNK_1 + tUNK_19 + 1) << 8 |
-                                     (tUNK_2 - 1));
+                                     (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
+               if(dev_priv->chipset == 0xa8) {
+                       timing->reg_100224 |= (tUNK_2 - 1);
+               } else {
+                       timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
+               }
 
                timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
-               if(recordlen > 19) {
-                       timing->reg_100228 += (tUNK_19 - 1) << 24;
-               }/* I cannot back-up this else-statement right now
-                        else {
-                       timing->reg_100228 += tUNK_12 << 24;
-               }*/
-
-               /* XXX: reg_10022c */
-               timing->reg_10022c = tUNK_2 - 1;
-
-               timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
-                                     tUNK_13 << 8  | tUNK_13);
-
-               /* XXX: +6? */
-               timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
-               timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
-
-               /* XXX; reg_100238, reg_10023c
-                * reg: 0x00??????
-                * reg_10023c:
-                *      0 for pre-NV50 cards
-                *      0x????0202 for NV50+ cards (empirical evidence) */
-               if(dev_priv->card_type >= NV_50) {
+               if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+                       timing->reg_100228 |= (tUNK_19 - 1) << 24;
+               }
+
+               if(dev_priv->card_type == NV_40) {
+                       /* NV40: don't know what the rest of the regs are..
+                        * And don't need to know either */
+                       timing->reg_100228 |= 0x20200000 | magic_number << 24;
+               } else if(dev_priv->card_type >= NV_50) {
+                       /* XXX: reg_10022c */
+                       timing->reg_10022c = tUNK_2 - 1;
+
+                       timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
+                                                 tUNK_13 << 8  | tUNK_13);
+
+                       timing->reg_100234 = (tRAS << 24 | tRC);
+                       timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+
+                       if(dev_priv->chipset < 0xa3) {
+                               timing->reg_100234 |= (tUNK_2 + 2) << 8;
+                       } else {
+                               /* XXX: +6? */
+                               timing->reg_100234 |= (tUNK_19 + 6) << 8;
+                       }
+
+                       /* XXX; reg_100238, reg_10023c
+                        * reg_100238: 0x00??????
+                        * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
                        timing->reg_10023c = 0x202;
+                       if(dev_priv->chipset < 0xa3) {
+                               timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
+                       } else {
+                               /* currently unknown
+                                * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
+                       }
                }
 
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
@@ -675,7 +695,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
                         timing->reg_100238, timing->reg_10023c);
        }
 
-       memtimings->nr_timing  = entries;
+       memtimings->nr_timing = entries;
        memtimings->supported = true;
 }
 
index 7ba3fc0b30c19a5dfdcda496202b99c2d141e0a8..5b39718ae1f8359683f96295d96a55ac4fdc56a8 100644 (file)
@@ -35,19 +35,22 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct nouveau_bo *ntfy = NULL;
-       uint32_t flags;
+       uint32_t flags, ttmpl;
        int ret;
 
-       if (nouveau_vram_notify)
+       if (nouveau_vram_notify) {
                flags = NOUVEAU_GEM_DOMAIN_VRAM;
-       else
+               ttmpl = TTM_PL_FLAG_VRAM;
+       } else {
                flags = NOUVEAU_GEM_DOMAIN_GART;
+               ttmpl = TTM_PL_FLAG_TT;
+       }
 
        ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy);
        if (ret)
                return ret;
 
-       ret = nouveau_bo_pin(ntfy, flags);
+       ret = nouveau_bo_pin(ntfy, ttmpl);
        if (ret)
                goto out_err;
 
index 4f00c87ed86eefda49bbd4e01559d51007700082..67a16e01ffa6db3030fd789d500dafd9b03eaf54 100644 (file)
@@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
 {
        struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
        struct drm_device *dev = gpuobj->dev;
+       unsigned long flags;
 
        if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
                u64  ptr = gpuobj->vinst + offset;
                u32 base = ptr >> 16;
                u32  val;
 
-               spin_lock(&dev_priv->ramin_lock);
+               spin_lock_irqsave(&dev_priv->vm_lock, flags);
                if (dev_priv->ramin_base != base) {
                        dev_priv->ramin_base = base;
                        nv_wr32(dev, 0x001700, dev_priv->ramin_base);
                }
                val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
-               spin_unlock(&dev_priv->ramin_lock);
+               spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
                return val;
        }
 
@@ -1063,18 +1064,19 @@ nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
 {
        struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
        struct drm_device *dev = gpuobj->dev;
+       unsigned long flags;
 
        if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
                u64  ptr = gpuobj->vinst + offset;
                u32 base = ptr >> 16;
 
-               spin_lock(&dev_priv->ramin_lock);
+               spin_lock_irqsave(&dev_priv->vm_lock, flags);
                if (dev_priv->ramin_base != base) {
                        dev_priv->ramin_base = base;
                        nv_wr32(dev, 0x001700, dev_priv->ramin_base);
                }
                nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
-               spin_unlock(&dev_priv->ramin_lock);
+               spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
                return;
        }
 
index ac62a1b8c4fc307afad07c9fafbb034f3301efcb..670e3cb697ec7664921e1fc87f57fa6fa40cd68e 100644 (file)
@@ -134,7 +134,7 @@ nouveau_perf_init(struct drm_device *dev)
                case 0x13:
                case 0x15:
                        perflvl->fanspeed = entry[55];
-                       perflvl->voltage = entry[56];
+                       perflvl->voltage = (recordlen > 56) ? entry[56] : 0;
                        perflvl->core = ROM32(entry[1]) * 10;
                        perflvl->memory = ROM32(entry[5]) * 20;
                        break;
index a33fe4019286e39294af123b7f8140973451c623..4bce801bc588ffd04e1cdd3800e2e82ebf33008f 100644 (file)
@@ -55,6 +55,7 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
                                be->func->clear(be);
                                return -EFAULT;
                        }
+                       nvbe->ttm_alloced[nvbe->nr_pages] = false;
                }
 
                nvbe->nr_pages++;
@@ -427,7 +428,7 @@ nouveau_sgdma_init(struct drm_device *dev)
        u32 aper_size, align;
        int ret;
 
-       if (dev_priv->card_type >= NV_50 || drm_pci_device_is_pcie(dev))
+       if (dev_priv->card_type >= NV_40 && drm_pci_device_is_pcie(dev))
                aper_size = 512 * 1024 * 1024;
        else
                aper_size = 64 * 1024 * 1024;
@@ -457,7 +458,7 @@ nouveau_sgdma_init(struct drm_device *dev)
                dev_priv->gart_info.func = &nv50_sgdma_backend;
        } else
        if (drm_pci_device_is_pcie(dev) &&
-           dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) {
+           dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) {
                if (nv44_graph_class(dev)) {
                        dev_priv->gart_info.func = &nv44_sgdma_backend;
                        align = 512 * 1024;
index 5bb2859001e22dedaa27c33b160a0d37408cffc6..915fbce8959517f4c51a9114a8224617ecbe265b 100644 (file)
@@ -376,15 +376,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.destroy_context   = nv50_graph_destroy_context;
                engine->graph.load_context      = nv50_graph_load_context;
                engine->graph.unload_context    = nv50_graph_unload_context;
-               if (dev_priv->chipset != 0x86)
+               if (dev_priv->chipset == 0x50 ||
+                   dev_priv->chipset == 0xac)
                        engine->graph.tlb_flush = nv50_graph_tlb_flush;
-               else {
-                       /* from what i can see nvidia do this on every
-                        * pre-NVA3 board except NVAC, but, we've only
-                        * ever seen problems on NV86
-                        */
-                       engine->graph.tlb_flush = nv86_graph_tlb_flush;
-               }
+               else
+                       engine->graph.tlb_flush = nv84_graph_tlb_flush;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nv50_fifo_init;
                engine->fifo.takedown           = nv50_fifo_takedown;
@@ -612,6 +608,7 @@ nouveau_card_init(struct drm_device *dev)
        spin_lock_init(&dev_priv->channels.lock);
        spin_lock_init(&dev_priv->tile.lock);
        spin_lock_init(&dev_priv->context_switch_lock);
+       spin_lock_init(&dev_priv->vm_lock);
 
        /* Make the CRTCs and I2C buses accessible */
        ret = engine->display.early_init(dev);
@@ -771,6 +768,11 @@ static void nouveau_card_takedown(struct drm_device *dev)
        engine->mc.takedown(dev);
        engine->display.late_takedown(dev);
 
+       if (dev_priv->vga_ram) {
+               nouveau_bo_unpin(dev_priv->vga_ram);
+               nouveau_bo_ref(NULL, &dev_priv->vga_ram);
+       }
+
        mutex_lock(&dev->struct_mutex);
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
index c82db37d9f4157a26e2dfc8ce679a3f6821be9fd..12098bf839c493561bf5aa5ab185a3601eeca34d 100644 (file)
@@ -581,12 +581,13 @@ static void nv04_dfp_restore(struct drm_encoder *encoder)
        int head = nv_encoder->restore.head;
 
        if (nv_encoder->dcb->type == OUTPUT_LVDS) {
-               struct drm_display_mode *native_mode = nouveau_encoder_connector_get(nv_encoder)->native_mode;
-               if (native_mode)
-                       call_lvds_script(dev, nv_encoder->dcb, head, LVDS_PANEL_ON,
-                                        native_mode->clock);
-               else
-                       NV_ERROR(dev, "Not restoring LVDS without native mode\n");
+               struct nouveau_connector *connector =
+                       nouveau_encoder_connector_get(nv_encoder);
+
+               if (connector && connector->native_mode)
+                       call_lvds_script(dev, nv_encoder->dcb, head,
+                                        LVDS_PANEL_ON,
+                                        connector->native_mode->clock);
 
        } else if (nv_encoder->dcb->type == OUTPUT_TMDS) {
                int clock = nouveau_hw_pllvals_to_clk
index 2b9984027f417702af0ce5ec9b6d03326cb4f32a..a19ccaa025b389508f604f72a10a060d338a32ee 100644 (file)
@@ -469,9 +469,6 @@ nv50_crtc_wait_complete(struct drm_crtc *crtc)
 
        start = ptimer->read(dev);
        do {
-               nv_wr32(dev, 0x61002c, 0x370);
-               nv_wr32(dev, 0x000140, 1);
-
                if (nv_ro32(disp->ntfy, 0x000))
                        return 0;
        } while (ptimer->read(dev) - start < 2000000000ULL);
index a2cfaa691e9bb3968d7e12f41cc5c5e226a4008a..c8e83c1a4de8f1381236ba750f670639b4ab155e 100644 (file)
@@ -186,6 +186,7 @@ nv50_evo_channel_init(struct nouveau_channel *evo)
        nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id);
 
        evo->dma.max = (4096/4) - 2;
+       evo->dma.max &= ~7;
        evo->dma.put = 0;
        evo->dma.cur = evo->dma.put;
        evo->dma.free = evo->dma.max - evo->dma.cur;
index 8675b00caf1890b37b81a3245c6ebcb3a636df28..b02a5b1e7d379fb1928467a668b905ddb4fa30b9 100644 (file)
@@ -503,7 +503,7 @@ nv50_graph_tlb_flush(struct drm_device *dev)
 }
 
 void
-nv86_graph_tlb_flush(struct drm_device *dev)
+nv84_graph_tlb_flush(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
index a6f8aa651fc6e585c5af4104c7b0e9146a45c3b9..4f95a1e5822e151ab89fcc51ba665c47cc4b50e4 100644 (file)
@@ -404,23 +404,25 @@ void
 nv50_instmem_flush(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       spin_lock(&dev_priv->ramin_lock);
+       spin_lock_irqsave(&dev_priv->vm_lock, flags);
        nv_wr32(dev, 0x00330c, 0x00000001);
        if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 
 void
 nv84_instmem_flush(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       spin_lock(&dev_priv->ramin_lock);
+       spin_lock_irqsave(&dev_priv->vm_lock, flags);
        nv_wr32(dev, 0x070000, 0x00000001);
        if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 
index 4fd3432b5b8d36023a853101074bd74d90073c9a..6c26944907418b0d090d35758b8e22d7ce9de06c 100644 (file)
@@ -174,10 +174,11 @@ void
 nv50_vm_flush_engine(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       spin_lock(&dev_priv->ramin_lock);
+       spin_lock_irqsave(&dev_priv->vm_lock, flags);
        nv_wr32(dev, 0x100c80, (engine << 16) | 1);
        if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
                NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
index 69af0ba7edd3c3edb5a6147d19f0950b2495bc7d..a179e6c55afbaeaaabcc71de6d834c5426abb6b9 100644 (file)
@@ -104,20 +104,27 @@ nvc0_vm_flush(struct nouveau_vm *vm)
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        struct drm_device *dev = vm->dev;
        struct nouveau_vm_pgd *vpgd;
-       u32 r100c80, engine;
+       unsigned long flags;
+       u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5;
 
        pinstmem->flush(vm->dev);
 
-       if (vm == dev_priv->chan_vm)
-               engine = 1;
-       else
-               engine = 5;
-
+       spin_lock_irqsave(&dev_priv->vm_lock, flags);
        list_for_each_entry(vpgd, &vm->pgd_list, head) {
-               r100c80 = nv_rd32(dev, 0x100c80);
+               /* looks like maybe a "free flush slots" counter, the
+                * faster you write to 0x100cbc to more it decreases
+                */
+               if (!nv_wait_ne(dev, 0x100c80, 0x00ff0000, 0x00000000)) {
+                       NV_ERROR(dev, "vm timeout 0: 0x%08x %d\n",
+                                nv_rd32(dev, 0x100c80), engine);
+               }
                nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8);
                nv_wr32(dev, 0x100cbc, 0x80000000 | engine);
-               if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80))
-                       NV_ERROR(dev, "vm flush timeout eng %d\n", engine);
+               /* wait for flush to be queued? */
+               if (!nv_wait(dev, 0x100c80, 0x00008000, 0x00008000)) {
+                       NV_ERROR(dev, "vm timeout 1: 0x%08x %d\n",
+                                nv_rd32(dev, 0x100c80), engine);
+               }
        }
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
index 258fa5e7a2d9aa4b175807f73e3f55fa407986f6..7bd7456890974025c74bfce11f8516bad909eacf 100644 (file)
@@ -32,6 +32,7 @@
 #include "atom.h"
 #include "atom-names.h"
 #include "atom-bits.h"
+#include "radeon.h"
 
 #define ATOM_COND_ABOVE                0
 #define ATOM_COND_ABOVEOREQUAL 1
@@ -101,7 +102,9 @@ static void debug_print_spaces(int n)
 static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
                                 uint32_t index, uint32_t data)
 {
+       struct radeon_device *rdev = ctx->card->dev->dev_private;
        uint32_t temp = 0xCDCDCDCD;
+
        while (1)
                switch (CU8(base)) {
                case ATOM_IIO_NOP:
@@ -112,7 +115,8 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
                        base += 3;
                        break;
                case ATOM_IIO_WRITE:
-                       (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
+                       if (rdev->family == CHIP_RV515)
+                               (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
                        ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
                        base += 3;
                        break;
@@ -131,7 +135,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
                case ATOM_IIO_MOVE_INDEX:
                        temp &=
                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
-                             CU8(base + 2));
+                             CU8(base + 3));
                        temp |=
                            ((index >> CU8(base + 2)) &
                             (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
@@ -141,7 +145,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
                case ATOM_IIO_MOVE_DATA:
                        temp &=
                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
-                             CU8(base + 2));
+                             CU8(base + 3));
                        temp |=
                            ((data >> CU8(base + 2)) &
                             (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
@@ -151,7 +155,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
                case ATOM_IIO_MOVE_ATTR:
                        temp &=
                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
-                             CU8(base + 2));
+                             CU8(base + 3));
                        temp |=
                            ((ctx->
                              io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
index b41ec59c7100b98346c2b4d170c89e1034a43927..529a3a704731ba39d77b423ac1ebe670697816f3 100644 (file)
@@ -531,6 +531,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
                else
                        pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+
+               if (rdev->family < CHIP_RV770)
+                       pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
        } else {
                pll->flags |= RADEON_PLL_LEGACY;
 
@@ -559,7 +562,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                                if (ss_enabled) {
                                        if (ss->refdiv) {
-                                               pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
                                                pll->flags |= RADEON_PLL_USE_REF_DIV;
                                                pll->reference_div = ss->refdiv;
                                                if (ASIC_IS_AVIVO(rdev))
index 0b0cc74c08c0834359601e2ba2fe9bd2171aa983..c20eac3379e67f055f0d18ec89174ff4eb166e44 100644 (file)
@@ -120,11 +120,16 @@ void evergreen_pm_misc(struct radeon_device *rdev)
        struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx];
        struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
 
-       if ((voltage->type == VOLTAGE_SW) && voltage->voltage) {
-               if (voltage->voltage != rdev->pm.current_vddc) {
-                       radeon_atom_set_voltage(rdev, voltage->voltage);
+       if (voltage->type == VOLTAGE_SW) {
+               if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) {
+                       radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
-                       DRM_DEBUG("Setting: v: %d\n", voltage->voltage);
+                       DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage);
+               }
+               if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) {
+                       radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI);
+                       rdev->pm.current_vddci = voltage->vddci;
+                       DRM_DEBUG("Setting: vddci: %d\n", voltage->vddci);
                }
        }
 }
@@ -348,7 +353,7 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
                                        struct drm_display_mode *mode,
                                        struct drm_display_mode *other_mode)
 {
-       u32 tmp = 0;
+       u32 tmp;
        /*
         * Line Buffer Setup
         * There are 3 line buffers, each one shared by 2 display controllers.
@@ -358,64 +363,63 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
         * first display controller
         *  0 - first half of lb (3840 * 2)
         *  1 - first 3/4 of lb (5760 * 2)
-        *  2 - whole lb (7680 * 2)
+        *  2 - whole lb (7680 * 2), other crtc must be disabled
         *  3 - first 1/4 of lb (1920 * 2)
         * second display controller
         *  4 - second half of lb (3840 * 2)
         *  5 - second 3/4 of lb (5760 * 2)
-        *  6 - whole lb (7680 * 2)
+        *  6 - whole lb (7680 * 2), other crtc must be disabled
         *  7 - last 1/4 of lb (1920 * 2)
         */
-       if (mode && other_mode) {
-               if (mode->hdisplay > other_mode->hdisplay) {
-                       if (mode->hdisplay > 2560)
-                               tmp = 1; /* 3/4 */
-                       else
-                               tmp = 0; /* 1/2 */
-               } else if (other_mode->hdisplay > mode->hdisplay) {
-                       if (other_mode->hdisplay > 2560)
-                               tmp = 3; /* 1/4 */
-                       else
-                               tmp = 0; /* 1/2 */
-               } else
+       /* this can get tricky if we have two large displays on a paired group
+        * of crtcs.  Ideally for multiple large displays we'd assign them to
+        * non-linked crtcs for maximum line buffer allocation.
+        */
+       if (radeon_crtc->base.enabled && mode) {
+               if (other_mode)
                        tmp = 0; /* 1/2 */
-       } else if (mode)
-               tmp = 2; /* whole */
-       else if (other_mode)
-               tmp = 3; /* 1/4 */
+               else
+                       tmp = 2; /* whole */
+       } else
+               tmp = 0;
 
        /* second controller of the pair uses second half of the lb */
        if (radeon_crtc->crtc_id % 2)
                tmp += 4;
        WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp);
 
-       switch (tmp) {
-       case 0:
-       case 4:
-       default:
-               if (ASIC_IS_DCE5(rdev))
-                       return 4096 * 2;
-               else
-                       return 3840 * 2;
-       case 1:
-       case 5:
-               if (ASIC_IS_DCE5(rdev))
-                       return 6144 * 2;
-               else
-                       return 5760 * 2;
-       case 2:
-       case 6:
-               if (ASIC_IS_DCE5(rdev))
-                       return 8192 * 2;
-               else
-                       return 7680 * 2;
-       case 3:
-       case 7:
-               if (ASIC_IS_DCE5(rdev))
-                       return 2048 * 2;
-               else
-                       return 1920 * 2;
+       if (radeon_crtc->base.enabled && mode) {
+               switch (tmp) {
+               case 0:
+               case 4:
+               default:
+                       if (ASIC_IS_DCE5(rdev))
+                               return 4096 * 2;
+                       else
+                               return 3840 * 2;
+               case 1:
+               case 5:
+                       if (ASIC_IS_DCE5(rdev))
+                               return 6144 * 2;
+                       else
+                               return 5760 * 2;
+               case 2:
+               case 6:
+                       if (ASIC_IS_DCE5(rdev))
+                               return 8192 * 2;
+                       else
+                               return 7680 * 2;
+               case 3:
+               case 7:
+                       if (ASIC_IS_DCE5(rdev))
+                               return 2048 * 2;
+                       else
+                               return 1920 * 2;
+               }
        }
+
+       /* controller not enabled, so no lb used */
+       return 0;
 }
 
 static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
@@ -858,9 +862,15 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev)
                SYSTEM_ACCESS_MODE_NOT_IN_SYS |
                SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
                EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
-       WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
-       WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
-       WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+       if (rdev->flags & RADEON_IS_IGP) {
+               WREG32(FUS_MC_VM_MD_L1_TLB0_CNTL, tmp);
+               WREG32(FUS_MC_VM_MD_L1_TLB1_CNTL, tmp);
+               WREG32(FUS_MC_VM_MD_L1_TLB2_CNTL, tmp);
+       } else {
+               WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
+               WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
+               WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+       }
        WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
        WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
        WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
@@ -2576,7 +2586,7 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
        u32 wptr, tmp;
 
        if (rdev->wb.enabled)
-               wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+               wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
        else
                wptr = RREG32(IH_RB_WPTR);
 
@@ -2919,11 +2929,6 @@ static int evergreen_startup(struct radeon_device *rdev)
                rdev->asic->copy = NULL;
                dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
        }
-       /* XXX: ontario has problems blitting to gart at the moment */
-       if (rdev->family == CHIP_PALM) {
-               rdev->asic->copy = NULL;
-               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
-       }
 
        /* allocate wb buffer */
        r = radeon_wb_init(rdev);
@@ -3036,9 +3041,6 @@ int evergreen_init(struct radeon_device *rdev)
 {
        int r;
 
-       r = radeon_dummy_page_init(rdev);
-       if (r)
-               return r;
        /* This don't do much */
        r = radeon_gem_init(rdev);
        if (r)
@@ -3150,7 +3152,6 @@ void evergreen_fini(struct radeon_device *rdev)
        radeon_atombios_fini(rdev);
        kfree(rdev->bios);
        rdev->bios = NULL;
-       radeon_dummy_page_fini(rdev);
 }
 
 static void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
index 9aaa3f0c9372135e8d55c0cb79e925f1656264e1..94533849927e4ef473fcbfc19deb8f67b28464e8 100644 (file)
 #define        MC_VM_MD_L1_TLB0_CNTL                           0x2654
 #define        MC_VM_MD_L1_TLB1_CNTL                           0x2658
 #define        MC_VM_MD_L1_TLB2_CNTL                           0x265C
+
+#define        FUS_MC_VM_MD_L1_TLB0_CNTL                       0x265C
+#define        FUS_MC_VM_MD_L1_TLB1_CNTL                       0x2660
+#define        FUS_MC_VM_MD_L1_TLB2_CNTL                       0x2664
+
 #define        MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR              0x203C
 #define        MC_VM_SYSTEM_APERTURE_HIGH_ADDR                 0x2038
 #define        MC_VM_SYSTEM_APERTURE_LOW_ADDR                  0x2034
index be271c42de4db0619957eca16583cba133ecdaac..6f27593901c7110752b9b2f39267f04546f544eb 100644 (file)
@@ -587,7 +587,7 @@ void r600_pm_misc(struct radeon_device *rdev)
 
        if ((voltage->type == VOLTAGE_SW) && voltage->voltage) {
                if (voltage->voltage != rdev->pm.current_vddc) {
-                       radeon_atom_set_voltage(rdev, voltage->voltage);
+                       radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
                        DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage);
                }
@@ -2509,9 +2509,6 @@ int r600_init(struct radeon_device *rdev)
 {
        int r;
 
-       r = radeon_dummy_page_init(rdev);
-       if (r)
-               return r;
        if (r600_debugfs_mc_info_init(rdev)) {
                DRM_ERROR("Failed to register debugfs file for mc !\n");
        }
@@ -2625,7 +2622,6 @@ void r600_fini(struct radeon_device *rdev)
        radeon_atombios_fini(rdev);
        kfree(rdev->bios);
        rdev->bios = NULL;
-       radeon_dummy_page_fini(rdev);
 }
 
 
@@ -3235,7 +3231,7 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
        u32 wptr, tmp;
 
        if (rdev->wb.enabled)
-               wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+               wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
        else
                wptr = RREG32(IH_RB_WPTR);
 
index 93f536594c73ae9b3a36fe3ffe63e6f60609a03c..ba643b5760542e0e6ad3298464be1e7505995739 100644 (file)
@@ -177,7 +177,7 @@ void radeon_pm_suspend(struct radeon_device *rdev);
 void radeon_pm_resume(struct radeon_device *rdev);
 void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
-void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
+void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
 void rs690_pm_info(struct radeon_device *rdev);
 extern int rv6xx_get_temp(struct radeon_device *rdev);
 extern int rv770_get_temp(struct radeon_device *rdev);
@@ -767,7 +767,9 @@ struct radeon_voltage {
        u8 vddci_id; /* index into vddci voltage table */
        bool vddci_enabled;
        /* r6xx+ sw */
-       u32 voltage;
+       u16 voltage;
+       /* evergreen+ vddci */
+       u16 vddci;
 };
 
 /* clock mode flags */
@@ -835,10 +837,12 @@ struct radeon_pm {
        int                     default_power_state_index;
        u32                     current_sclk;
        u32                     current_mclk;
-       u32                     current_vddc;
+       u16                     current_vddc;
+       u16                     current_vddci;
        u32                     default_sclk;
        u32                     default_mclk;
-       u32                     default_vddc;
+       u16                     default_vddc;
+       u16                     default_vddci;
        struct radeon_i2c_chan *i2c_bus;
        /* selected pm method */
        enum radeon_pm_method     pm_method;
index eb888ee5f674d518a82f90dbae5c752019b549c4..ca576191d0588bb23356b2c40d25afa668736cb8 100644 (file)
@@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
                rdev->mc_rreg = &rs600_mc_rreg;
                rdev->mc_wreg = &rs600_mc_wreg;
        }
-       if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) {
+       if (rdev->family >= CHIP_R600) {
                rdev->pciep_rreg = &r600_pciep_rreg;
                rdev->pciep_wreg = &r600_pciep_wreg;
        }
index 99768d9d91dacb4db763c6ecee074c64ba24bed9..dd881d035f0934579154a6acc0d2b56534c563f9 100644 (file)
@@ -431,7 +431,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                }
        }
 
-       /* Acer laptop (Acer TravelMate 5730G) has an HDMI port
+       /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port
         * on the laptop and a DVI port on the docking station and
         * both share the same encoder, hpd pin, and ddc line.
         * So while the bios table is technically correct,
@@ -440,7 +440,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
         * with different crtcs which isn't possible on the hardware
         * side and leaves no crtcs for LVDS or VGA.
         */
-       if ((dev->pdev->device == 0x95c4) &&
+       if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) &&
            (dev->pdev->subsystem_vendor == 0x1025) &&
            (dev->pdev->subsystem_device == 0x013c)) {
                if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
@@ -1599,9 +1599,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                                                        memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
                                                               fake_edid_record->ucFakeEDIDLength);
 
-                                                       if (drm_edid_is_valid(edid))
+                                                       if (drm_edid_is_valid(edid)) {
                                                                rdev->mode_info.bios_hardcoded_edid = edid;
-                                                       else
+                                                               rdev->mode_info.bios_hardcoded_edid_size = edid_size;
+                                                       } else
                                                                kfree(edid);
                                                }
                                        }
@@ -2176,24 +2177,27 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
        }
 }
 
-static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev)
+static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
+                                                u16 *vddc, u16 *vddci)
 {
        struct radeon_mode_info *mode_info = &rdev->mode_info;
        int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
        u8 frev, crev;
        u16 data_offset;
        union firmware_info *firmware_info;
-       u16 vddc = 0;
+
+       *vddc = 0;
+       *vddci = 0;
 
        if (atom_parse_data_header(mode_info->atom_context, index, NULL,
                                   &frev, &crev, &data_offset)) {
                firmware_info =
                        (union firmware_info *)(mode_info->atom_context->bios +
                                                data_offset);
-               vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
+               *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
+               if ((frev == 2) && (crev >= 2))
+                       *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
        }
-
-       return vddc;
 }
 
 static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
@@ -2203,7 +2207,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
        int j;
        u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
        u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
-       u16 vddc = radeon_atombios_get_default_vddc(rdev);
+       u16 vddc, vddci;
+
+       radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
 
        rdev->pm.power_state[state_index].misc = misc;
        rdev->pm.power_state[state_index].misc2 = misc2;
@@ -2244,6 +2250,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
                        rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
                        rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
                        rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
+                       rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
                } else {
                        /* patch the table values with the default slck/mclk from firmware info */
                        for (j = 0; j < mode_index; j++) {
@@ -2286,6 +2293,8 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                        VOLTAGE_SW;
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
                        le16_to_cpu(clock_info->evergreen.usVDDC);
+               rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
+                       le16_to_cpu(clock_info->evergreen.usVDDCI);
        } else {
                sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
                sclk |= clock_info->r600.ucEngineClockHigh << 16;
@@ -2577,25 +2586,25 @@ union set_voltage {
        struct _SET_VOLTAGE_PARAMETERS_V2 v2;
 };
 
-void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level)
+void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
 {
        union set_voltage args;
        int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
-       u8 frev, crev, volt_index = level;
+       u8 frev, crev, volt_index = voltage_level;
 
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
                return;
 
        switch (crev) {
        case 1:
-               args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC;
+               args.v1.ucVoltageType = voltage_type;
                args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
                args.v1.ucVoltageIndex = volt_index;
                break;
        case 2:
-               args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC;
+               args.v2.ucVoltageType = voltage_type;
                args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
-               args.v2.usVoltageLevel = cpu_to_le16(level);
+               args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
                break;
        default:
                DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
index ed5dfe58f29c0845e8eb8a478560b9a01fe17677..9d95792bea3eab3c961b1221918beb1e4378d2f9 100644 (file)
@@ -15,6 +15,9 @@
 #define ATPX_VERSION 0
 #define ATPX_GPU_PWR 2
 #define ATPX_MUX_SELECT 3
+#define ATPX_I2C_MUX_SELECT 4
+#define ATPX_SWITCH_START 5
+#define ATPX_SWITCH_END 6
 
 #define ATPX_INTEGRATED 0
 #define ATPX_DISCRETE 1
@@ -149,13 +152,35 @@ static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id)
        return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id);
 }
 
+static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id)
+{
+       return radeon_atpx_execute(handle, ATPX_I2C_MUX_SELECT, mux_id);
+}
+
+static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id)
+{
+       return radeon_atpx_execute(handle, ATPX_SWITCH_START, gpu_id);
+}
+
+static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id)
+{
+       return radeon_atpx_execute(handle, ATPX_SWITCH_END, gpu_id);
+}
 
 static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
 {
+       int gpu_id;
+
        if (id == VGA_SWITCHEROO_IGD)
-               radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0);
+               gpu_id = ATPX_INTEGRATED;
        else
-               radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1);
+               gpu_id = ATPX_DISCRETE;
+
+       radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id);
+       radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id);
+       radeon_atpx_switch_i2c_mux(radeon_atpx_priv.atpx_handle, gpu_id);
+       radeon_atpx_switch_end(radeon_atpx_priv.atpx_handle, gpu_id);
+
        return 0;
 }
 
index 2ef6d513506404075307c5f5865e091b8e4653ea..5f45fa12bb8b88471f5a301e44a893c97a6f96b3 100644 (file)
@@ -1199,7 +1199,7 @@ radeon_add_atom_connector(struct drm_device *dev,
        if (router->ddc_valid || router->cd_valid) {
                radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
                if (!radeon_connector->router_bus)
-                       goto failed;
+                       DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
        }
        switch (connector_type) {
        case DRM_MODE_CONNECTOR_VGA:
@@ -1208,7 +1208,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                radeon_connector->dac_load_detect = true;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1226,7 +1226,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                radeon_connector->dac_load_detect = true;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1249,7 +1249,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                subpixel_order = SubPixelHorizontalRGB;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1290,7 +1290,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                drm_connector_attach_property(&radeon_connector->base,
                                              rdev->mode_info.coherent_mode_property,
@@ -1329,10 +1329,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        else
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
                        if (!radeon_dig_connector->dp_i2c_bus)
-                               goto failed;
+                               DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                subpixel_order = SubPixelHorizontalRGB;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1381,7 +1381,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                drm_connector_attach_property(&radeon_connector->base,
                                              dev->mode_config.scaling_mode_property,
@@ -1457,7 +1457,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                radeon_connector->dac_load_detect = true;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1475,7 +1475,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                radeon_connector->dac_load_detect = true;
                drm_connector_attach_property(&radeon_connector->base,
@@ -1493,7 +1493,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                if (connector_type == DRM_MODE_CONNECTOR_DVII) {
                        radeon_connector->dac_load_detect = true;
@@ -1538,7 +1538,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                if (i2c_bus->valid) {
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               goto failed;
+                               DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
                drm_connector_attach_property(&radeon_connector->base,
                                              dev->mode_config.scaling_mode_property,
@@ -1567,9 +1567,4 @@ radeon_add_legacy_connector(struct drm_device *dev,
                                radeon_legacy_backlight_init(radeon_encoder, connector);
                }
        }
-       return;
-
-failed:
-       drm_connector_cleanup(connector);
-       kfree(connector);
 }
index bdf2fa1189ae7a3c1aa5e1ae41a1ded25c96b9f7..3189a7efb2e97e0ee25f111db13e42c5b41c7c76 100644 (file)
@@ -167,9 +167,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       radeon_crtc->cursor_width = width;
-       radeon_crtc->cursor_height = height;
-
        obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
        if (!obj) {
                DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
@@ -180,6 +177,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
        if (ret)
                goto fail;
 
+       radeon_crtc->cursor_width = width;
+       radeon_crtc->cursor_height = height;
+
        radeon_lock_cursor(crtc, true);
        /* XXX only 27 bit offset for legacy cursor */
        radeon_set_cursor(crtc, obj, gpu_addr);
index 9e59868d354e4a83e6f06d40663171416151a1f5..bbcd1dd7bac0eb27057f44b39add48528f701ffd 100644 (file)
@@ -79,7 +79,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
                        scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
                else
                        scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
-               seq = rdev->wb.wb[scratch_index/4];
+               seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]);
        } else
                seq = RREG32(rdev->fence_drv.scratch_reg);
        if (seq != rdev->fence_drv.last_seq) {
index f0534ef2f3311d20f57976ff683dd24619127a51..8a955bbdb6082521c725b81bbf5ee0e34e7934b6 100644 (file)
@@ -285,4 +285,6 @@ void radeon_gart_fini(struct radeon_device *rdev)
        rdev->gart.pages = NULL;
        rdev->gart.pages_addr = NULL;
        rdev->gart.ttm_alloced = NULL;
+
+       radeon_dummy_page_fini(rdev);
 }
index ded2a45bc95cd5f2845b9d32009d98dc00105c5f..983cbac75af0159d493c7b81dbe2da1fd90866e6 100644 (file)
@@ -1062,7 +1062,7 @@ void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
                *val = in_buf[0];
                DRM_DEBUG("val = 0x%02x\n", *val);
        } else {
-               DRM_ERROR("i2c 0x%02x 0x%02x read failed\n",
+               DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n",
                          addr, *val);
        }
 }
@@ -1084,7 +1084,7 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
        out_buf[1] = val;
 
        if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1)
-               DRM_ERROR("i2c 0x%02x 0x%02x write failed\n",
+               DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n",
                          addr, val);
 }
 
@@ -1096,6 +1096,9 @@ void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
        if (!radeon_connector->router.ddc_valid)
                return;
 
+       if (!radeon_connector->router_bus)
+               return;
+
        radeon_i2c_get_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x3, &val);
@@ -1121,6 +1124,9 @@ void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
        if (!radeon_connector->router.cd_valid)
                return;
 
+       if (!radeon_connector->router_bus)
+               return;
+
        radeon_i2c_get_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x3, &val);
index bf7d4c061451cc35c396cee0d739c40dca6f33eb..bd58af658581b3d3672aa363f7e5c7418abaaefa 100644 (file)
@@ -221,6 +221,22 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                        return -EINVAL;
                }
                break;
+       case RADEON_INFO_NUM_TILE_PIPES:
+               if (rdev->family >= CHIP_CAYMAN)
+                       value = rdev->config.cayman.max_tile_pipes;
+               else if (rdev->family >= CHIP_CEDAR)
+                       value = rdev->config.evergreen.max_tile_pipes;
+               else if (rdev->family >= CHIP_RV770)
+                       value = rdev->config.rv770.max_tile_pipes;
+               else if (rdev->family >= CHIP_R600)
+                       value = rdev->config.r600.max_tile_pipes;
+               else {
+                       return -EINVAL;
+               }
+               break;
+       case RADEON_INFO_FUSION_GART_WORKING:
+               value = 1;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index 5b54268ed6b2c9e881b664e04ba05d421eea404d..2f46e0c8df53256a9bf5d6271b55141be2f8b35a 100644 (file)
@@ -269,7 +269,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
        .disable = radeon_legacy_encoder_disable,
 };
 
-#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
 
 #define MAX_RADEON_LEVEL 0xFF
 
index 08de669e025ab9bddf0bd118a457288bbb2b49e0..86eda1ea94dfc7a250d7add83ad2b25b8ae0dd76 100644 (file)
@@ -23,6 +23,7 @@
 #include "drmP.h"
 #include "radeon.h"
 #include "avivod.h"
+#include "atom.h"
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
 #endif
@@ -535,7 +536,11 @@ void radeon_pm_resume(struct radeon_device *rdev)
        /* set up the default clocks if the MC ucode is loaded */
        if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
                if (rdev->pm.default_vddc)
-                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddc);
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDC);
+               if (rdev->pm.default_vddci)
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDCI);
                if (rdev->pm.default_sclk)
                        radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
                if (rdev->pm.default_mclk)
@@ -548,6 +553,7 @@ void radeon_pm_resume(struct radeon_device *rdev)
        rdev->pm.current_sclk = rdev->pm.default_sclk;
        rdev->pm.current_mclk = rdev->pm.default_mclk;
        rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
+       rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
        if (rdev->pm.pm_method == PM_METHOD_DYNPM
            && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
                rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
@@ -585,7 +591,8 @@ int radeon_pm_init(struct radeon_device *rdev)
                /* set up the default clocks if the MC ucode is loaded */
                if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
                        if (rdev->pm.default_vddc)
-                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddc);
+                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+                                                       SET_VOLTAGE_TYPE_ASIC_VDDC);
                        if (rdev->pm.default_sclk)
                                radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
                        if (rdev->pm.default_mclk)
index bbc9cd8233346e1a65df6657c324e1c7313f1678..c6776e48fdde44d678880a1af436866cb24c8740 100644 (file)
@@ -248,7 +248,7 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
 void radeon_ring_free_size(struct radeon_device *rdev)
 {
        if (rdev->wb.enabled)
-               rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4];
+               rdev->cp.rptr = le32_to_cpu(rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4]);
        else {
                if (rdev->family >= CHIP_R600)
                        rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
index af0da4ae3f55acb5223f2791940ec90c1db20bce..92f1900dc7caf10f14dba34edec2e34b721ff09d 100644 (file)
@@ -708,6 +708,7 @@ r600 0x9400
 0x00028D0C DB_RENDER_CONTROL
 0x00028D10 DB_RENDER_OVERRIDE
 0x0002880C DB_SHADER_CONTROL
+0x00028D28 DB_SRESULTS_COMPARE_STATE0
 0x00028D2C DB_SRESULTS_COMPARE_STATE1
 0x00028430 DB_STENCILREFMASK
 0x00028434 DB_STENCILREFMASK_BF
index 876cebc4b8ba7cef0b2d6fe2e1cc6a38c512c652..6e3b11e5abbe5a83842e4e9b1b49d6531e460d92 100644 (file)
@@ -114,7 +114,7 @@ void rs600_pm_misc(struct radeon_device *rdev)
                                udelay(voltage->delay);
                }
        } else if (voltage->type == VOLTAGE_VDDC)
-               radeon_atom_set_voltage(rdev, voltage->vddc_id);
+               radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC);
 
        dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH);
        dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf);
index b974ac7df8dfad511bad054bf121388842519435..ef8a5babe9f7679fce662775faa98afb4f1002a2 100644 (file)
@@ -106,7 +106,7 @@ void rv770_pm_misc(struct radeon_device *rdev)
 
        if ((voltage->type == VOLTAGE_SW) && voltage->voltage) {
                if (voltage->voltage != rdev->pm.current_vddc) {
-                       radeon_atom_set_voltage(rdev, voltage->voltage);
+                       radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
                        DRM_DEBUG("Setting: v: %d\n", voltage->voltage);
                }
@@ -1255,9 +1255,6 @@ int rv770_init(struct radeon_device *rdev)
 {
        int r;
 
-       r = radeon_dummy_page_init(rdev);
-       if (r)
-               return r;
        /* This don't do much */
        r = radeon_gem_init(rdev);
        if (r)
@@ -1372,7 +1369,6 @@ void rv770_fini(struct radeon_device *rdev)
        radeon_atombios_fini(rdev);
        kfree(rdev->bios);
        rdev->bios = NULL;
-       radeon_dummy_page_fini(rdev);
 }
 
 static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
index 737a2a2e46a58ca7ee66cbf67c0afd0583275ff6..9d9d92945f8c5e515adc87dc40e9f4b1f97427bc 100644 (file)
@@ -683,22 +683,14 @@ int ttm_get_pages(struct list_head *pages, int flags,
                        gfp_flags |= GFP_HIGHUSER;
 
                for (r = 0; r < count; ++r) {
-                       if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
-                               void *addr;
-                               addr = dma_alloc_coherent(NULL, PAGE_SIZE,
-                                                         &dma_address[r],
-                                                         gfp_flags);
-                               if (addr == NULL)
-                                       return -ENOMEM;
-                               p = virt_to_page(addr);
-                       } else
-                               p = alloc_page(gfp_flags);
+                       p = alloc_page(gfp_flags);
                        if (!p) {
 
                                printk(KERN_ERR TTM_PFX
                                       "Unable to allocate page.");
                                return -ENOMEM;
                        }
+
                        list_add(&p->lru, pages);
                }
                return 0;
@@ -746,24 +738,12 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
        unsigned long irq_flags;
        struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
        struct page *p, *tmp;
-       unsigned r;
 
        if (pool == NULL) {
                /* No pool for this memory type so free the pages */
 
-               r = page_count-1;
                list_for_each_entry_safe(p, tmp, pages, lru) {
-                       if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
-                               void *addr = page_address(p);
-                               WARN_ON(!addr || !dma_address[r]);
-                               if (addr)
-                                       dma_free_coherent(NULL, PAGE_SIZE,
-                                                         addr,
-                                                         dma_address[r]);
-                               dma_address[r] = 0;
-                       } else
-                               __free_page(p);
-                       r--;
+                       __free_page(p);
                }
                /* Make the pages list empty */
                INIT_LIST_HEAD(pages);
index 70e60a4bb678e0c1ed669badc4ceb3e69be5c9e5..419917955bf6cef7466aee105bb1c322c4e92468 100644 (file)
@@ -5,6 +5,7 @@ config STUB_POULSBO
        # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_CLASS_DEVICE if ACPI
+       select VIDEO_OUTPUT_CONTROL if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
        select THERMAL if ACPI
index 060ef63278763f2a96da76365f6a2a617f84f191..50e40dbd8bb64877a66a0f2d70d71053b972aad8 100644 (file)
@@ -110,8 +110,7 @@ config SENSORS_ADM1021
        help
          If you say yes here you get support for Analog Devices ADM1021
          and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
-         Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10,
-         and the XEON processor built-in sensor.
+         Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10.
 
          This driver can also be built as a module.  If so, the module
          will be called adm1021.
@@ -618,10 +617,10 @@ config SENSORS_LM90
        depends on I2C
        help
          If you say yes here you get support for National Semiconductor LM90,
-         LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim
-         MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
-         MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton
-         W83L771W/G/AWG/ASG sensor chips.
+         LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
+         Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
+         MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
+         and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm90.
index 250d099ca3980e1dbb8131e4748610d137049658..da72dc12068c11f85769f93aa57a6370ffa2ffd0 100644 (file)
@@ -1094,6 +1094,7 @@ static struct attribute *lm85_attributes_minctl[] = {
        &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
        &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
        &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+       NULL
 };
 
 static const struct attribute_group lm85_group_minctl = {
@@ -1104,6 +1105,7 @@ static struct attribute *lm85_attributes_temp_off[] = {
        &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
        &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
        &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+       NULL
 };
 
 static const struct attribute_group lm85_group_temp_off = {
@@ -1329,11 +1331,11 @@ static int lm85_probe(struct i2c_client *client,
        if (data->type != emc6d103s) {
                err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl);
                if (err)
-                       goto err_kfree;
+                       goto err_remove_files;
                err = sysfs_create_group(&client->dev.kobj,
                                         &lm85_group_temp_off);
                if (err)
-                       goto err_kfree;
+                       goto err_remove_files;
        }
 
        /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
index c43b4e9f96a9ecd6816954e6c9964b581c2ac1b4..2f94f9504804f29963a17b9327abd860be851436 100644 (file)
  * chips, but support three temperature sensors instead of two. MAX6695
  * and MAX6696 only differ in the pinout so they can be treated identically.
  *
- * This driver also supports the ADT7461 chip from Analog Devices.
- * It's supported in both compatibility and extended mode. It is mostly
- * compatible with LM90 except for a data format difference for the
- * temperature value registers.
+ * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as
+ * NCT1008 from ON Semiconductor. The chips are supported in both compatibility
+ * and extended mode. They are mostly compatible with LM90 except for a data
+ * format difference for the temperature value registers.
  *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * Addresses to scan
  * Address is fully defined internally and cannot be changed except for
  * MAX6659, MAX6680 and MAX6681.
- * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657,
- * MAX6658 and W83L771 have address 0x4c.
- * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d.
+ * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649,
+ * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c.
+ * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D
+ * have address 0x4d.
  * MAX6647 has address 0x4e.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e.
  * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
@@ -174,6 +175,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 static const struct i2c_device_id lm90_id[] = {
        { "adm1032", adm1032 },
        { "adt7461", adt7461 },
+       { "adt7461a", adt7461 },
        { "lm90", lm90 },
        { "lm86", lm86 },
        { "lm89", lm86 },
@@ -188,6 +190,7 @@ static const struct i2c_device_id lm90_id[] = {
        { "max6681", max6680 },
        { "max6695", max6696 },
        { "max6696", max6696 },
+       { "nct1008", adt7461 },
        { "w83l771", w83l771 },
        { }
 };
@@ -1153,6 +1156,11 @@ static int lm90_detect(struct i2c_client *new_client,
                 && (reg_config1 & 0x1B) == 0x00
                 && reg_convrate <= 0x0A) {
                        name = "adt7461";
+               } else
+               if (chip_id == 0x57 /* ADT7461A, NCT1008 */
+                && (reg_config1 & 0x1B) == 0x00
+                && reg_convrate <= 0x0A) {
+                       name = "adt7461a";
                }
        } else
        if (man_id == 0x4D) { /* Maxim */
index edfb92e41735df7f713a2283a12a299e764423ca..196ffafafd88ff3cebf37de7bae8d37494d2dc34 100644 (file)
@@ -139,7 +139,6 @@ struct pmbus_data {
         * A single status register covers multiple attributes,
         * so we keep them all together.
         */
-       u8 status_bits;
        u8 status[PB_NUM_STATUS_REG];
 
        u8 currpage;
index de5819199e2e35cd65d8b2816431328a3ddd58cf..57240740b161d190329b5ca3b7dfaf0d049ef02e 100644 (file)
@@ -98,7 +98,6 @@ static const struct attribute_group twl4030_madc_group = {
 static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev)
 {
        int ret;
-       int status;
        struct device *hwmon;
 
        ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group);
@@ -107,7 +106,7 @@ static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev)
        hwmon = hwmon_device_register(&pdev->dev);
        if (IS_ERR(hwmon)) {
                dev_err(&pdev->dev, "hwmon_device_register failed.\n");
-               status = PTR_ERR(hwmon);
+               ret = PTR_ERR(hwmon);
                goto err_reg;
        }
 
index 38319a69bd0a9de978fc688bded38fa3dea90def..d6d58684712bc8b68cafb662316fe123e53b270d 100644 (file)
@@ -232,9 +232,17 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
  * Sanity check for the adapter hardware - check the reaction of
  * the bus lines only if it seems to be idle.
  */
-static int test_bus(struct i2c_algo_bit_data *adap, char *name)
+static int test_bus(struct i2c_adapter *i2c_adap)
 {
-       int scl, sda;
+       struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+       const char *name = i2c_adap->name;
+       int scl, sda, ret;
+
+       if (adap->pre_xfer) {
+               ret = adap->pre_xfer(i2c_adap);
+               if (ret < 0)
+                       return -ENODEV;
+       }
 
        if (adap->getscl == NULL)
                pr_info("%s: Testing SDA only, SCL is not readable\n", name);
@@ -297,11 +305,19 @@ static int test_bus(struct i2c_algo_bit_data *adap, char *name)
                       "while pulling SCL high!\n", name);
                goto bailout;
        }
+
+       if (adap->post_xfer)
+               adap->post_xfer(i2c_adap);
+
        pr_info("%s: Test OK\n", name);
        return 0;
 bailout:
        sdahi(adap);
        sclhi(adap);
+
+       if (adap->post_xfer)
+               adap->post_xfer(i2c_adap);
+
        return -ENODEV;
 }
 
@@ -607,7 +623,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
        int ret;
 
        if (bit_test) {
-               ret = test_bus(bit_adap, adap->name);
+               ret = test_bus(adap);
                if (ret < 0)
                        return -ENODEV;
        }
index 72c0415f6f944922470ad962361c086ac4290809..455e909bc768637a1a7f6d793f626baef082f46d 100644 (file)
                                 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
                                 SMBHSTSTS_INTR)
 
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0        0x1d70
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1        0x1d71
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2        0x1d72
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS     0x2330
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 
 struct i801_priv {
        struct i2c_adapter adapter;
index 0eb1515541e72446a4e81e3bf54702bcf0635347..2dbba163b10202cf51aba175f7ffbf9cfd57aea2 100644 (file)
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
  * i2c-parport.c I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
    
    Based on older i2c-philips-par.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
@@ -33,6 +33,8 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/i2c-smbus.h>
 #include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
 #include "i2c-parport.h"
 
 /* ----- Device list ------------------------------------------------------ */
@@ -43,10 +45,11 @@ struct i2c_par {
        struct i2c_algo_bit_data algo_data;
        struct i2c_smbus_alert_setup alert_data;
        struct i2c_client *ara;
-       struct i2c_par *next;
+       struct list_head node;
 };
 
-static struct i2c_par *adapter_list;
+static LIST_HEAD(adapter_list);
+static DEFINE_MUTEX(adapter_list_lock);
 
 /* ----- Low-level parallel port access ----------------------------------- */
 
@@ -228,8 +231,9 @@ static void i2c_parport_attach (struct parport *port)
        }
 
        /* Add the new adapter to the list */
-       adapter->next = adapter_list;
-       adapter_list = adapter;
+       mutex_lock(&adapter_list_lock);
+       list_add_tail(&adapter->node, &adapter_list);
+       mutex_unlock(&adapter_list_lock);
         return;
 
 ERROR1:
@@ -241,11 +245,11 @@ ERROR0:
 
 static void i2c_parport_detach (struct parport *port)
 {
-       struct i2c_par *adapter, *prev;
+       struct i2c_par *adapter, *_n;
 
        /* Walk the list */
-       for (prev = NULL, adapter = adapter_list; adapter;
-            prev = adapter, adapter = adapter->next) {
+       mutex_lock(&adapter_list_lock);
+       list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
                if (adapter->pdev->port == port) {
                        if (adapter->ara) {
                                parport_disable_irq(port);
@@ -259,14 +263,11 @@ static void i2c_parport_detach (struct parport *port)
                                
                        parport_release(adapter->pdev);
                        parport_unregister_device(adapter->pdev);
-                       if (prev)
-                               prev->next = adapter->next;
-                       else
-                               adapter_list = adapter->next;
+                       list_del(&adapter->node);
                        kfree(adapter);
-                       return;
                }
        }
+       mutex_unlock(&adapter_list_lock);
 }
 
 static struct parport_driver i2c_parport_driver = {
index 70c30e6bce0b2efcfbdee8f90bfd620d62319bd9..9a58994ff7ea54bd46cf6b576e9e43b10e736b79 100644 (file)
@@ -797,7 +797,8 @@ static int i2c_do_add_adapter(struct i2c_driver *driver,
 
        /* Let legacy drivers scan this bus for matching devices */
        if (driver->attach_adapter) {
-               dev_warn(&adap->dev, "attach_adapter method is deprecated\n");
+               dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
+                        driver->driver.name);
                dev_warn(&adap->dev, "Please use another way to instantiate "
                         "your i2c_client\n");
                /* We ignore the return code; if it fails, too bad */
@@ -984,7 +985,8 @@ static int i2c_do_del_adapter(struct i2c_driver *driver,
 
        if (!driver->detach_adapter)
                return 0;
-       dev_warn(&adapter->dev, "detach_adapter method is deprecated\n");
+       dev_warn(&adapter->dev, "%s: detach_adapter method is deprecated\n",
+                driver->driver.name);
        res = driver->detach_adapter(adapter);
        if (res)
                dev_err(&adapter->dev, "detach_adapter failed (%d) "
index fd1e117991373853d5b51d8827f99157fabd3b55..a5ec5a7cb381bbffac45a13c9e2cdccfd0a7d8b0 100644 (file)
@@ -1782,7 +1782,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
        g->flags |= GENHD_FL_REMOVABLE;
-       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 2a6bc50e8a41e8918da5ad8aca49686d68da318c..02caa7dd51c83f99e34e05de972f67020945a2d6 100644 (file)
@@ -79,6 +79,12 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
        return CDS_DRIVE_NOT_READY;
 }
 
+/*
+ * ide-cd always generates media changed event if media is missing, which
+ * makes it impossible to use for proper event reporting, so disk->events
+ * is cleared to 0 and the following function is used only to trigger
+ * revalidation and never propagated to userland.
+ */
 unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi,
                                         unsigned int clearing, int slot_nr)
 {
index c4ffd4888939a7f4e67ee7f1191a08d485c85e44..70ea8763567dcc7b1b7fd946275dea49303534f6 100644 (file)
@@ -298,6 +298,12 @@ static unsigned int ide_gd_check_events(struct gendisk *disk,
                return 0;
        }
 
+       /*
+        * The following is used to force revalidation on the first open on
+        * removeable devices, and never gets reported to userland as
+        * genhd->events is 0.  This is intended as removeable ide disk
+        * can't really detect MEDIA_CHANGE events.
+        */
        ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED;
        drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
 
@@ -413,7 +419,6 @@ static int ide_gd_probe(ide_drive_t *drive)
        if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
                g->flags = GENHD_FL_REMOVABLE;
        g->fops = &ide_gd_ops;
-       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 7de4b7ebffc541f1a204360fb6d9d39a5f9b96d1..d8ca0a0b970d39879e7d981acbf5cb1647dca424 100644 (file)
@@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd)
        /*
         * Keep chip from being accessed until we are ready.  Use
         * writeq() directly, to allow the write even though QIB_PRESENT
-        * isn't' set.
+        * isn't set.
         */
        dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
        dd->int_counter = 0; /* so we check interrupts work again */
index 74fe0360bec7a00a7e082d1bdfc45004239e4e14..c765a2eb04cf27ba3b28ef4eb33e5e99ed6027ba 100644 (file)
@@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd)
        /*
         * Keep chip from being accessed until we are ready.  Use
         * writeq() directly, to allow the write even though QIB_PRESENT
-        * isn't' set.
+        * isn't set.
         */
        dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
        dd->int_counter = 0; /* so we check interrupts work again */
index 55de3cf3441c51173c169064a891de38d138ca5b..6bab3eaea70f3588f31de57c69703ac5da736935 100644 (file)
@@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd)
        /*
         * Keep chip from being accessed until we are ready.  Use
         * writeq() directly, to allow the write even though QIB_PRESENT
-        * isn't' set.
+        * isn't set.
         */
        dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR);
        dd->flags |= QIB_DOING_RESET;
index 7f42d3a454d2d6aaebdc41e0e5a8c6700d6a00df..88d8e4cb419a1d0d6cc17828894dc4d3b67e0201 100644 (file)
@@ -39,13 +39,13 @@ struct evdev {
 };
 
 struct evdev_client {
-       int head;
-       int tail;
+       unsigned int head;
+       unsigned int tail;
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
-       int bufsize;
+       unsigned int bufsize;
        struct input_event buffer[];
 };
 
@@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex);
 static void evdev_pass_event(struct evdev_client *client,
                             struct input_event *event)
 {
-       /*
-        * Interrupts are disabled, just acquire the lock.
-        * Make sure we don't leave with the client buffer
-        * "empty" by having client->head == client->tail.
-        */
+       /* Interrupts are disabled, just acquire the lock. */
        spin_lock(&client->buffer_lock);
-       do {
-               client->buffer[client->head++] = *event;
-               client->head &= client->bufsize - 1;
-       } while (client->head == client->tail);
+
+       client->buffer[client->head++] = *event;
+       client->head &= client->bufsize - 1;
+
+       if (unlikely(client->head == client->tail)) {
+               /*
+                * This effectively "drops" all unconsumed events, leaving
+                * EV_SYN/SYN_DROPPED plus the newest event in the queue.
+                */
+               client->tail = (client->head - 2) & (client->bufsize - 1);
+
+               client->buffer[client->tail].time = event->time;
+               client->buffer[client->tail].type = EV_SYN;
+               client->buffer[client->tail].code = SYN_DROPPED;
+               client->buffer[client->tail].value = 0;
+       }
+
        spin_unlock(&client->buffer_lock);
 
        if (event->type == EV_SYN)
index d6e8bd8a851c26d0e4718d10d30977451bb28009..ebbceedc92f4fb8a9f8bc959734be4b442586d01 100644 (file)
@@ -1746,6 +1746,42 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
 }
 EXPORT_SYMBOL(input_set_capability);
 
+static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
+{
+       int mt_slots;
+       int i;
+       unsigned int events;
+
+       if (dev->mtsize) {
+               mt_slots = dev->mtsize;
+       } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
+               mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
+                          dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
+               clamp(mt_slots, 2, 32);
+       } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
+               mt_slots = 2;
+       } else {
+               mt_slots = 0;
+       }
+
+       events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */
+
+       for (i = 0; i < ABS_CNT; i++) {
+               if (test_bit(i, dev->absbit)) {
+                       if (input_is_mt_axis(i))
+                               events += mt_slots;
+                       else
+                               events++;
+               }
+       }
+
+       for (i = 0; i < REL_CNT; i++)
+               if (test_bit(i, dev->relbit))
+                       events++;
+
+       return events;
+}
+
 #define INPUT_CLEANSE_BITMASK(dev, type, bits)                         \
        do {                                                            \
                if (!test_bit(EV_##type, dev->evbit))                   \
@@ -1793,6 +1829,10 @@ int input_register_device(struct input_dev *dev)
        /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
        input_cleanse_bitmasks(dev);
 
+       if (!dev->hint_events_per_packet)
+               dev->hint_events_per_packet =
+                               input_estimate_events_per_packet(dev);
+
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
index 09bef79d9da1c6e3aecd6efe40c0d4c4c900ba0b..a26922cf0e84d3049d972b7dc0d79b986b3645fb 100644 (file)
@@ -332,18 +332,20 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
 static int __devinit twl4030_kp_probe(struct platform_device *pdev)
 {
        struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
-       const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
+       const struct matrix_keymap_data *keymap_data;
        struct twl4030_keypad *kp;
        struct input_dev *input;
        u8 reg;
        int error;
 
-       if (!pdata || !pdata->rows || !pdata->cols ||
+       if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data ||
            pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) {
                dev_err(&pdev->dev, "Invalid platform_data\n");
                return -EINVAL;
        }
 
+       keymap_data = pdata->keymap_data;
+
        kp = kzalloc(sizeof(*kp), GFP_KERNEL);
        input = input_allocate_device();
        if (!kp || !input) {
index 7077f9bf5ead88a15eb65699e71d00e49715fc84..62bae99424e6e436defda3723654816c44be2609 100644 (file)
@@ -303,7 +303,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
                                   enum xenbus_state backend_state)
 {
        struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-       int val;
+       int ret, val;
 
        switch (backend_state) {
        case XenbusStateInitialising:
@@ -316,6 +316,17 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
 
        case XenbusStateInitWait:
 InitWait:
+               ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                  "feature-abs-pointer", "%d", &val);
+               if (ret < 0)
+                       val = 0;
+               if (val) {
+                       ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
+                                           "request-abs-pointer", "1");
+                       if (ret)
+                               pr_warning("xenkbd: can't request abs-pointer");
+               }
+
                xenbus_switch_state(dev, XenbusStateConnected);
                break;
 
index efa06882de00cb855d992f868079338067813d8c..45f93d0f5592e2c3adcdcfdad32ce83696312647 100644 (file)
@@ -399,31 +399,34 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
                        IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
                err = -EBUSY;
-               goto fail2;
+               goto fail1;
        }
 
        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
                        IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
                err = -EBUSY;
-               goto fail3;
+               goto fail2;
        }
 
        serio_set_drvdata(serio, ts);
 
        err = serio_open(serio, drv);
        if (err)
-               return err;
+               goto fail3;
 
        //h3600_flite_control(1, 25);     /* default brightness */
-       input_register_device(ts->dev);
+       err = input_register_device(ts->dev);
+       if (err)
+               goto fail4;
 
        return 0;
 
-fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
+fail4: serio_close(serio);
+fail3: serio_set_drvdata(serio, NULL);
+       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
 fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
-fail1: serio_set_drvdata(serio, NULL);
-       input_free_device(input_dev);
+fail1: input_free_device(input_dev);
        kfree(ts);
        return err;
 }
index 6ae054f8e0aa50b5e07f7d43f21f582bb19cf98f..9175d49d25469d0eaa7794960580c14d7740b9a9 100644 (file)
@@ -68,8 +68,23 @@ struct wm831x_ts {
        unsigned int pd_irq;
        bool pressure;
        bool pen_down;
+       struct work_struct pd_data_work;
 };
 
+static void wm831x_pd_data_work(struct work_struct *work)
+{
+       struct wm831x_ts *wm831x_ts =
+               container_of(work, struct wm831x_ts, pd_data_work);
+
+       if (wm831x_ts->pen_down) {
+               enable_irq(wm831x_ts->data_irq);
+               dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n");
+       } else {
+               enable_irq(wm831x_ts->pd_irq);
+               dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n");
+       }
+}
+
 static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
 {
        struct wm831x_ts *wm831x_ts = irq_data;
@@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
        }
 
        if (!wm831x_ts->pen_down) {
+               /* Switch from data to pen down */
+               dev_dbg(wm831x->dev, "IRQ DATA->PD\n");
+
                disable_irq_nosync(wm831x_ts->data_irq);
 
                /* Don't need data any more */
@@ -128,6 +146,10 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
                                         ABS_PRESSURE, 0);
 
                input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0);
+
+               schedule_work(&wm831x_ts->pd_data_work);
+       } else {
+               input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
        }
 
        input_sync(wm831x_ts->input_dev);
@@ -141,6 +163,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
        struct wm831x *wm831x = wm831x_ts->wm831x;
        int ena = 0;
 
+       if (wm831x_ts->pen_down)
+               return IRQ_HANDLED;
+
+       disable_irq_nosync(wm831x_ts->pd_irq);
+
        /* Start collecting data */
        if (wm831x_ts->pressure)
                ena |= WM831X_TCH_Z_ENA;
@@ -149,14 +176,14 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
                        WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA,
                        WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena);
 
-       input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
-       input_sync(wm831x_ts->input_dev);
-
        wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
                        WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
 
        wm831x_ts->pen_down = true;
-       enable_irq(wm831x_ts->data_irq);
+
+       /* Switch from pen down to data */
+       dev_dbg(wm831x->dev, "IRQ PD->DATA\n");
+       schedule_work(&wm831x_ts->pd_data_work);
 
        return IRQ_HANDLED;
 }
@@ -182,13 +209,28 @@ static void wm831x_ts_input_close(struct input_dev *idev)
        struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
        struct wm831x *wm831x = wm831x_ts->wm831x;
 
+       /* Shut the controller down, disabling all other functionality too */
        wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
-                       WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
-                       WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
-                       WM831X_TCH_Z_ENA, 0);
+                       WM831X_TCH_ENA | WM831X_TCH_X_ENA |
+                       WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0);
 
-       if (wm831x_ts->pen_down)
+       /* Make sure any pending IRQs are done, the above will prevent
+        * new ones firing.
+        */
+       synchronize_irq(wm831x_ts->data_irq);
+       synchronize_irq(wm831x_ts->pd_irq);
+
+       /* Make sure the IRQ completion work is quiesced */
+       flush_work_sync(&wm831x_ts->pd_data_work);
+
+       /* If we ended up with the pen down then make sure we revert back
+        * to pen detection state for the next time we start up.
+        */
+       if (wm831x_ts->pen_down) {
                disable_irq(wm831x_ts->data_irq);
+               enable_irq(wm831x_ts->pd_irq);
+               wm831x_ts->pen_down = false;
+       }
 }
 
 static __devinit int wm831x_ts_probe(struct platform_device *pdev)
@@ -198,7 +240,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
        struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent);
        struct wm831x_touch_pdata *pdata = NULL;
        struct input_dev *input_dev;
-       int error;
+       int error, irqf;
 
        if (core_pdata)
                pdata = core_pdata->touch;
@@ -212,6 +254,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
 
        wm831x_ts->wm831x = wm831x;
        wm831x_ts->input_dev = input_dev;
+       INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work);
 
        /*
         * If we have a direct IRQ use it, otherwise use the interrupt
@@ -270,9 +313,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
        wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
                        WM831X_TCH_RATE_MASK, 6);
 
+       if (pdata && pdata->data_irqf)
+               irqf = pdata->data_irqf;
+       else
+               irqf = IRQF_TRIGGER_HIGH;
+
        error = request_threaded_irq(wm831x_ts->data_irq,
                                     NULL, wm831x_ts_data_irq,
-                                    IRQF_ONESHOT,
+                                    irqf | IRQF_ONESHOT,
                                     "Touchscreen data", wm831x_ts);
        if (error) {
                dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n",
@@ -281,9 +329,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
        }
        disable_irq(wm831x_ts->data_irq);
 
+       if (pdata && pdata->pd_irqf)
+               irqf = pdata->pd_irqf;
+       else
+               irqf = IRQF_TRIGGER_HIGH;
+
        error = request_threaded_irq(wm831x_ts->pd_irq,
                                     NULL, wm831x_ts_pen_down_irq,
-                                    IRQF_ONESHOT,
+                                    irqf | IRQF_ONESHOT,
                                     "Touchscreen pen down", wm831x_ts);
        if (error) {
                dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n",
index 3790816643bef85bee2dd1824bcb29818a693f86..8497f56f8e461cf70d8d1b8692e04b11e353323c 100644 (file)
@@ -178,6 +178,10 @@ static int __devinit regulator_led_probe(struct platform_device *pdev)
        led->cdev.flags |= LED_CORE_SUSPENDRESUME;
        led->vcc = vcc;
 
+       /* to handle correctly an already enabled regulator */
+       if (regulator_is_enabled(led->vcc))
+               led->enabled = 1;
+
        mutex_init(&led->mutex);
        INIT_WORK(&led->work, led_work);
 
index 5ef136cdba91dd4a891f00920029962a54185d63..e5d8904fc8f647162d4a7d79150491797cfda6d2 100644 (file)
@@ -390,13 +390,6 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits)
        return md_raid5_congested(&rs->md, bits);
 }
 
-static void raid_unplug(struct dm_target_callbacks *cb)
-{
-       struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
-
-       md_raid5_kick_device(rs->md.private);
-}
-
 /*
  * Construct a RAID4/5/6 mapping:
  * Args:
@@ -487,7 +480,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
 
        rs->callbacks.congested_fn = raid_is_congested;
-       rs->callbacks.unplug_fn = raid_unplug;
        dm_table_add_target_callbacks(ti->table, &rs->callbacks);
 
        return 0;
index b12b3776c0c0c8ca46b998cac6df78845363f7ee..7d6f7f18a92052e3258ffeae719c377b2df4fb78 100644 (file)
@@ -447,48 +447,59 @@ EXPORT_SYMBOL(md_flush_request);
 
 /* Support for plugging.
  * This mirrors the plugging support in request_queue, but does not
- * require having a whole queue
+ * require having a whole queue or request structures.
+ * We allocate an md_plug_cb for each md device and each thread it gets
+ * plugged on.  This links tot the private plug_handle structure in the
+ * personality data where we keep a count of the number of outstanding
+ * plugs so other code can see if a plug is active.
  */
-static void plugger_work(struct work_struct *work)
-{
-       struct plug_handle *plug =
-               container_of(work, struct plug_handle, unplug_work);
-       plug->unplug_fn(plug);
-}
-static void plugger_timeout(unsigned long data)
-{
-       struct plug_handle *plug = (void *)data;
-       kblockd_schedule_work(NULL, &plug->unplug_work);
-}
-void plugger_init(struct plug_handle *plug,
-                 void (*unplug_fn)(struct plug_handle *))
-{
-       plug->unplug_flag = 0;
-       plug->unplug_fn = unplug_fn;
-       init_timer(&plug->unplug_timer);
-       plug->unplug_timer.function = plugger_timeout;
-       plug->unplug_timer.data = (unsigned long)plug;
-       INIT_WORK(&plug->unplug_work, plugger_work);
-}
-EXPORT_SYMBOL_GPL(plugger_init);
+struct md_plug_cb {
+       struct blk_plug_cb cb;
+       mddev_t *mddev;
+};
 
-void plugger_set_plug(struct plug_handle *plug)
+static void plugger_unplug(struct blk_plug_cb *cb)
 {
-       if (!test_and_set_bit(PLUGGED_FLAG, &plug->unplug_flag))
-               mod_timer(&plug->unplug_timer, jiffies + msecs_to_jiffies(3)+1);
+       struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb);
+       if (atomic_dec_and_test(&mdcb->mddev->plug_cnt))
+               md_wakeup_thread(mdcb->mddev->thread);
+       kfree(mdcb);
 }
-EXPORT_SYMBOL_GPL(plugger_set_plug);
 
-int plugger_remove_plug(struct plug_handle *plug)
+/* Check that an unplug wakeup will come shortly.
+ * If not, wakeup the md thread immediately
+ */
+int mddev_check_plugged(mddev_t *mddev)
 {
-       if (test_and_clear_bit(PLUGGED_FLAG, &plug->unplug_flag)) {
-               del_timer(&plug->unplug_timer);
-               return 1;
-       } else
+       struct blk_plug *plug = current->plug;
+       struct md_plug_cb *mdcb;
+
+       if (!plug)
                return 0;
-}
-EXPORT_SYMBOL_GPL(plugger_remove_plug);
 
+       list_for_each_entry(mdcb, &plug->cb_list, cb.list) {
+               if (mdcb->cb.callback == plugger_unplug &&
+                   mdcb->mddev == mddev) {
+                       /* Already on the list, move to top */
+                       if (mdcb != list_first_entry(&plug->cb_list,
+                                                   struct md_plug_cb,
+                                                   cb.list))
+                               list_move(&mdcb->cb.list, &plug->cb_list);
+                       return 1;
+               }
+       }
+       /* Not currently on the callback list */
+       mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC);
+       if (!mdcb)
+               return 0;
+
+       mdcb->mddev = mddev;
+       mdcb->cb.callback = plugger_unplug;
+       atomic_inc(&mddev->plug_cnt);
+       list_add(&mdcb->cb.list, &plug->cb_list);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(mddev_check_plugged);
 
 static inline mddev_t *mddev_get(mddev_t *mddev)
 {
@@ -538,6 +549,7 @@ void mddev_init(mddev_t *mddev)
        atomic_set(&mddev->active, 1);
        atomic_set(&mddev->openers, 0);
        atomic_set(&mddev->active_io, 0);
+       atomic_set(&mddev->plug_cnt, 0);
        spin_lock_init(&mddev->write_lock);
        atomic_set(&mddev->flush_pending, 0);
        init_waitqueue_head(&mddev->sb_wait);
@@ -3158,6 +3170,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
        mddev->layout = mddev->new_layout;
        mddev->chunk_sectors = mddev->new_chunk_sectors;
        mddev->delta_disks = 0;
+       mddev->degraded = 0;
        if (mddev->pers->sync_request == NULL) {
                /* this is now an array without redundancy, so
                 * it must always be in_sync
@@ -4723,7 +4736,6 @@ static void md_clean(mddev_t *mddev)
        mddev->bitmap_info.chunksize = 0;
        mddev->bitmap_info.daemon_sleep = 0;
        mddev->bitmap_info.max_write_behind = 0;
-       mddev->plug = NULL;
 }
 
 static void __md_stop_writes(mddev_t *mddev)
@@ -6688,12 +6700,6 @@ int md_allow_write(mddev_t *mddev)
 }
 EXPORT_SYMBOL_GPL(md_allow_write);
 
-void md_unplug(mddev_t *mddev)
-{
-       if (mddev->plug)
-               mddev->plug->unplug_fn(mddev->plug);
-}
-
 #define SYNC_MARKS     10
 #define        SYNC_MARK_STEP  (3*HZ)
 void md_do_sync(mddev_t *mddev)
index 52b407369e13f0c82b7fa23f3ee2ca7d41483bbb..0b1fd3f1d85b5decfaaba4ab8b70595fffbaba1f 100644 (file)
 typedef struct mddev_s mddev_t;
 typedef struct mdk_rdev_s mdk_rdev_t;
 
-/* generic plugging support - like that provided with request_queue,
- * but does not require a request_queue
- */
-struct plug_handle {
-       void                    (*unplug_fn)(struct plug_handle *);
-       struct timer_list       unplug_timer;
-       struct work_struct      unplug_work;
-       unsigned long           unplug_flag;
-};
-#define        PLUGGED_FLAG 1
-void plugger_init(struct plug_handle *plug,
-                 void (*unplug_fn)(struct plug_handle *));
-void plugger_set_plug(struct plug_handle *plug);
-int plugger_remove_plug(struct plug_handle *plug);
-static inline void plugger_flush(struct plug_handle *plug)
-{
-       del_timer_sync(&plug->unplug_timer);
-       cancel_work_sync(&plug->unplug_work);
-}
-
 /*
  * MD's 'extended' device
  */
@@ -199,6 +179,9 @@ struct mddev_s
        int                             delta_disks, new_level, new_layout;
        int                             new_chunk_sectors;
 
+       atomic_t                        plug_cnt;       /* If device is expecting
+                                                        * more bios soon.
+                                                        */
        struct mdk_thread_s             *thread;        /* management thread */
        struct mdk_thread_s             *sync_thread;   /* doing resync or reconstruct */
        sector_t                        curr_resync;    /* last block scheduled */
@@ -336,7 +319,6 @@ struct mddev_s
        struct list_head                all_mddevs;
 
        struct attribute_group          *to_remove;
-       struct plug_handle              *plug; /* if used by personality */
 
        struct bio_set                  *bio_set;
 
@@ -516,7 +498,6 @@ extern int md_integrity_register(mddev_t *mddev);
 extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
 extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
 extern void restore_bitmap_write_access(struct file *file);
-extern void md_unplug(mddev_t *mddev);
 
 extern void mddev_init(mddev_t *mddev);
 extern int md_run(mddev_t *mddev);
@@ -530,4 +511,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
                                   mddev_t *mddev);
 extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
                                   mddev_t *mddev);
+extern int mddev_check_plugged(mddev_t *mddev);
 #endif /* _MD_MD_H */
index c2a21ae56d977d6249f9c8501f124e50c48f15dd..2b7a7ff401dc6fba50047bbc3f0fb1980055da13 100644 (file)
@@ -565,12 +565,6 @@ static void flush_pending_writes(conf_t *conf)
                spin_unlock_irq(&conf->device_lock);
 }
 
-static void md_kick_device(mddev_t *mddev)
-{
-       blk_flush_plug(current);
-       md_wakeup_thread(mddev->thread);
-}
-
 /* Barriers....
  * Sometimes we need to suspend IO while we do something else,
  * either some resync/recovery, or reconfigure the array.
@@ -600,7 +594,7 @@ static void raise_barrier(conf_t *conf)
 
        /* Wait until no block IO is waiting */
        wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting,
-                           conf->resync_lock, md_kick_device(conf->mddev));
+                           conf->resync_lock, );
 
        /* block any new IO from starting */
        conf->barrier++;
@@ -608,7 +602,7 @@ static void raise_barrier(conf_t *conf)
        /* Now wait for all pending IO to complete */
        wait_event_lock_irq(conf->wait_barrier,
                            !conf->nr_pending && conf->barrier < RESYNC_DEPTH,
-                           conf->resync_lock, md_kick_device(conf->mddev));
+                           conf->resync_lock, );
 
        spin_unlock_irq(&conf->resync_lock);
 }
@@ -630,7 +624,7 @@ static void wait_barrier(conf_t *conf)
                conf->nr_waiting++;
                wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
                                    conf->resync_lock,
-                                   md_kick_device(conf->mddev));
+                                   );
                conf->nr_waiting--;
        }
        conf->nr_pending++;
@@ -666,8 +660,7 @@ static void freeze_array(conf_t *conf)
        wait_event_lock_irq(conf->wait_barrier,
                            conf->nr_pending == conf->nr_queued+1,
                            conf->resync_lock,
-                           ({ flush_pending_writes(conf);
-                              md_kick_device(conf->mddev); }));
+                           flush_pending_writes(conf));
        spin_unlock_irq(&conf->resync_lock);
 }
 static void unfreeze_array(conf_t *conf)
@@ -729,6 +722,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
        const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
        mdk_rdev_t *blocked_rdev;
+       int plugged;
 
        /*
         * Register the new request and wait if the reconstruction
@@ -820,6 +814,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
         * inc refcount on their rdev.  Record them by setting
         * bios[x] to bio
         */
+       plugged = mddev_check_plugged(mddev);
+
        disks = conf->raid_disks;
  retry_write:
        blocked_rdev = NULL;
@@ -925,7 +921,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid1d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
-       if (do_sync || !bitmap)
+       if (do_sync || !bitmap || !plugged)
                md_wakeup_thread(mddev->thread);
 
        return 0;
@@ -1516,13 +1512,16 @@ static void raid1d(mddev_t *mddev)
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
        mdk_rdev_t *rdev;
+       struct blk_plug plug;
 
        md_check_recovery(mddev);
-       
+
+       blk_start_plug(&plug);
        for (;;) {
                char b[BDEVNAME_SIZE];
 
-               flush_pending_writes(conf);
+               if (atomic_read(&mddev->plug_cnt) == 0)
+                       flush_pending_writes(conf);
 
                spin_lock_irqsave(&conf->device_lock, flags);
                if (list_empty(head)) {
@@ -1593,6 +1592,7 @@ static void raid1d(mddev_t *mddev)
                }
                cond_resched();
        }
+       blk_finish_plug(&plug);
 }
 
 
@@ -2039,7 +2039,6 @@ static int stop(mddev_t *mddev)
 
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
-       blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        if (conf->r1bio_pool)
                mempool_destroy(conf->r1bio_pool);
        kfree(conf->mirrors);
index 2da83d5665925eea27b441e954ca145569278055..8e9462626ec5cb8d7441b46ddae9a848772153fe 100644 (file)
@@ -634,12 +634,6 @@ static void flush_pending_writes(conf_t *conf)
                spin_unlock_irq(&conf->device_lock);
 }
 
-static void md_kick_device(mddev_t *mddev)
-{
-       blk_flush_plug(current);
-       md_wakeup_thread(mddev->thread);
-}
-
 /* Barriers....
  * Sometimes we need to suspend IO while we do something else,
  * either some resync/recovery, or reconfigure the array.
@@ -669,15 +663,15 @@ static void raise_barrier(conf_t *conf, int force)
 
        /* Wait until no block IO is waiting (unless 'force') */
        wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting,
-                           conf->resync_lock, md_kick_device(conf->mddev));
+                           conf->resync_lock, );
 
        /* block any new IO from starting */
        conf->barrier++;
 
-       /* No wait for all pending IO to complete */
+       /* Now wait for all pending IO to complete */
        wait_event_lock_irq(conf->wait_barrier,
                            !conf->nr_pending && conf->barrier < RESYNC_DEPTH,
-                           conf->resync_lock, md_kick_device(conf->mddev));
+                           conf->resync_lock, );
 
        spin_unlock_irq(&conf->resync_lock);
 }
@@ -698,7 +692,7 @@ static void wait_barrier(conf_t *conf)
                conf->nr_waiting++;
                wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
                                    conf->resync_lock,
-                                   md_kick_device(conf->mddev));
+                                   );
                conf->nr_waiting--;
        }
        conf->nr_pending++;
@@ -734,8 +728,8 @@ static void freeze_array(conf_t *conf)
        wait_event_lock_irq(conf->wait_barrier,
                            conf->nr_pending == conf->nr_queued+1,
                            conf->resync_lock,
-                           ({ flush_pending_writes(conf);
-                              md_kick_device(conf->mddev); }));
+                           flush_pending_writes(conf));
+
        spin_unlock_irq(&conf->resync_lock);
 }
 
@@ -762,6 +756,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
        unsigned long flags;
        mdk_rdev_t *blocked_rdev;
+       int plugged;
 
        if (unlikely(bio->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bio);
@@ -870,6 +865,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
         * inc refcount on their rdev.  Record them by setting
         * bios[x] to bio
         */
+       plugged = mddev_check_plugged(mddev);
+
        raid10_find_phys(conf, r10_bio);
  retry_write:
        blocked_rdev = NULL;
@@ -946,9 +943,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid10d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
-       if (do_sync || !mddev->bitmap)
+       if (do_sync || !mddev->bitmap || !plugged)
                md_wakeup_thread(mddev->thread);
-
        return 0;
 }
 
@@ -1640,9 +1636,11 @@ static void raid10d(mddev_t *mddev)
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
        mdk_rdev_t *rdev;
+       struct blk_plug plug;
 
        md_check_recovery(mddev);
 
+       blk_start_plug(&plug);
        for (;;) {
                char b[BDEVNAME_SIZE];
 
@@ -1716,6 +1714,7 @@ static void raid10d(mddev_t *mddev)
                }
                cond_resched();
        }
+       blk_finish_plug(&plug);
 }
 
 
index e867ee42b15239707c0dfede4be71d2bc9a72e20..49bf5f8914353a1c7972beaa27d6b5caee1031cc 100644 (file)
  *
  * We group bitmap updates into batches.  Each batch has a number.
  * We may write out several batches at once, but that isn't very important.
- * conf->bm_write is the number of the last batch successfully written.
- * conf->bm_flush is the number of the last batch that was closed to
+ * conf->seq_write is the number of the last batch successfully written.
+ * conf->seq_flush is the number of the last batch that was closed to
  *    new additions.
  * When we discover that we will need to write to any block in a stripe
  * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq
- * the number of the batch it will be in. This is bm_flush+1.
+ * the number of the batch it will be in. This is seq_flush+1.
  * When we are ready to do a write, if that batch hasn't been written yet,
  *   we plug the array and queue the stripe for later.
  * When an unplug happens, we increment bm_flush, thus closing the current
@@ -199,14 +199,12 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
                BUG_ON(!list_empty(&sh->lru));
                BUG_ON(atomic_read(&conf->active_stripes)==0);
                if (test_bit(STRIPE_HANDLE, &sh->state)) {
-                       if (test_bit(STRIPE_DELAYED, &sh->state)) {
+                       if (test_bit(STRIPE_DELAYED, &sh->state))
                                list_add_tail(&sh->lru, &conf->delayed_list);
-                               plugger_set_plug(&conf->plug);
-                       } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
-                                  sh->bm_seq - conf->seq_write > 0) {
+                       else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
+                                  sh->bm_seq - conf->seq_write > 0)
                                list_add_tail(&sh->lru, &conf->bitmap_list);
-                               plugger_set_plug(&conf->plug);
-                       } else {
+                       else {
                                clear_bit(STRIPE_BIT_DELAY, &sh->state);
                                list_add_tail(&sh->lru, &conf->handle_list);
                        }
@@ -461,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector,
                                                     < (conf->max_nr_stripes *3/4)
                                                     || !conf->inactive_blocked),
                                                    conf->device_lock,
-                                                   md_raid5_kick_device(conf));
+                                                   );
                                conf->inactive_blocked = 0;
                        } else
                                init_stripe(sh, sector, previous);
@@ -1470,7 +1468,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
                wait_event_lock_irq(conf->wait_for_stripe,
                                    !list_empty(&conf->inactive_list),
                                    conf->device_lock,
-                                   blk_flush_plug(current));
+                                   );
                osh = get_free_stripe(conf);
                spin_unlock_irq(&conf->device_lock);
                atomic_set(&nsh->count, 1);
@@ -3623,8 +3621,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->hold_list);
                }
-       } else
-               plugger_set_plug(&conf->plug);
+       }
 }
 
 static void activate_bit_delay(raid5_conf_t *conf)
@@ -3641,21 +3638,6 @@ static void activate_bit_delay(raid5_conf_t *conf)
        }
 }
 
-void md_raid5_kick_device(raid5_conf_t *conf)
-{
-       blk_flush_plug(current);
-       raid5_activate_delayed(conf);
-       md_wakeup_thread(conf->mddev->thread);
-}
-EXPORT_SYMBOL_GPL(md_raid5_kick_device);
-
-static void raid5_unplug(struct plug_handle *plug)
-{
-       raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug);
-
-       md_raid5_kick_device(conf);
-}
-
 int md_raid5_congested(mddev_t *mddev, int bits)
 {
        raid5_conf_t *conf = mddev->private;
@@ -3945,6 +3927,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
        struct stripe_head *sh;
        const int rw = bio_data_dir(bi);
        int remaining;
+       int plugged;
 
        if (unlikely(bi->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bi);
@@ -3963,6 +3946,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
        bi->bi_next = NULL;
        bi->bi_phys_segments = 1;       /* over-loaded to count active stripes */
 
+       plugged = mddev_check_plugged(mddev);
        for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
                DEFINE_WAIT(w);
                int disks, data_disks;
@@ -4057,7 +4041,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                                 * add failed due to overlap.  Flush everything
                                 * and wait a while
                                 */
-                               md_raid5_kick_device(conf);
+                               md_wakeup_thread(mddev->thread);
                                release_stripe(sh);
                                schedule();
                                goto retry;
@@ -4077,6 +4061,9 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                }
                        
        }
+       if (!plugged)
+               md_wakeup_thread(mddev->thread);
+
        spin_lock_irq(&conf->device_lock);
        remaining = raid5_dec_bi_phys_segments(bi);
        spin_unlock_irq(&conf->device_lock);
@@ -4478,24 +4465,30 @@ static void raid5d(mddev_t *mddev)
        struct stripe_head *sh;
        raid5_conf_t *conf = mddev->private;
        int handled;
+       struct blk_plug plug;
 
        pr_debug("+++ raid5d active\n");
 
        md_check_recovery(mddev);
 
+       blk_start_plug(&plug);
        handled = 0;
        spin_lock_irq(&conf->device_lock);
        while (1) {
                struct bio *bio;
 
-               if (conf->seq_flush != conf->seq_write) {
-                       int seq = conf->seq_flush;
+               if (atomic_read(&mddev->plug_cnt) == 0 &&
+                   !list_empty(&conf->bitmap_list)) {
+                       /* Now is a good time to flush some bitmap updates */
+                       conf->seq_flush++;
                        spin_unlock_irq(&conf->device_lock);
                        bitmap_unplug(mddev->bitmap);
                        spin_lock_irq(&conf->device_lock);
-                       conf->seq_write = seq;
+                       conf->seq_write = conf->seq_flush;
                        activate_bit_delay(conf);
                }
+               if (atomic_read(&mddev->plug_cnt) == 0)
+                       raid5_activate_delayed(conf);
 
                while ((bio = remove_bio_from_retry(conf))) {
                        int ok;
@@ -4525,6 +4518,7 @@ static void raid5d(mddev_t *mddev)
        spin_unlock_irq(&conf->device_lock);
 
        async_tx_issue_pending_all();
+       blk_finish_plug(&plug);
 
        pr_debug("--- raid5d inactive\n");
 }
@@ -5141,8 +5135,6 @@ static int run(mddev_t *mddev)
                       mdname(mddev));
        md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
 
-       plugger_init(&conf->plug, raid5_unplug);
-       mddev->plug = &conf->plug;
        if (mddev->queue) {
                int chunk_size;
                /* read-ahead size must cover two whole stripes, which
@@ -5159,7 +5151,6 @@ static int run(mddev_t *mddev)
 
                mddev->queue->backing_dev_info.congested_data = mddev;
                mddev->queue->backing_dev_info.congested_fn = raid5_congested;
-               mddev->queue->queue_lock = &conf->device_lock;
 
                chunk_size = mddev->chunk_sectors << 9;
                blk_queue_io_min(mddev->queue, chunk_size);
@@ -5192,7 +5183,6 @@ static int stop(mddev_t *mddev)
        mddev->thread = NULL;
        if (mddev->queue)
                mddev->queue->backing_dev_info.congested_fn = NULL;
-       plugger_flush(&conf->plug); /* the unplug fn references 'conf'*/
        free_conf(conf);
        mddev->private = NULL;
        mddev->to_remove = &raid5_attrs_group;
@@ -5688,6 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state)
 static void *raid45_takeover_raid0(mddev_t *mddev, int level)
 {
        struct raid0_private_data *raid0_priv = mddev->private;
+       sector_t sectors;
 
        /* for raid0 takeover only one zone is supported */
        if (raid0_priv->nr_strip_zones > 1) {
@@ -5696,6 +5687,9 @@ static void *raid45_takeover_raid0(mddev_t *mddev, int level)
                return ERR_PTR(-EINVAL);
        }
 
+       sectors = raid0_priv->strip_zone[0].zone_end;
+       sector_div(sectors, raid0_priv->strip_zone[0].nb_dev);
+       mddev->dev_sectors = sectors;
        mddev->new_level = level;
        mddev->new_layout = ALGORITHM_PARITY_N;
        mddev->new_chunk_sectors = mddev->chunk_sectors;
index 8d563a4f022a778a6d9354a3c1bf514c6f5e10b6..3ca77a2613ba0a544ffa9c4aca4e12122d77cc96 100644 (file)
@@ -400,8 +400,6 @@ struct raid5_private_data {
                                            * Cleared when a sync completes.
                                            */
 
-       struct plug_handle      plug;
-
        /* per cpu variables */
        struct raid5_percpu {
                struct page     *spare_page; /* Used when checking P/Q in raid6 */
index 5466d47db899ea67c8551fafbe2a5e5bacb78ba7..aae40e52af5b1f3edf36c11154b6d04e41fd8273 100644 (file)
@@ -533,16 +533,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
        if (tda_fail(ret))
                goto fail;
 
-       regs[R_MPD]   = (0x77 & pd);
-
-       switch (priv->mode) {
-       case TDA18271_ANALOG:
-               regs[R_MPD]  &= ~0x08;
-               break;
-       case TDA18271_DIGITAL:
-               regs[R_MPD]  |=  0x08;
-               break;
-       }
+       regs[R_MPD]   = (0x7f & pd);
 
        div =  ((d * (freq / 1000)) << 7) / 125;
 
index 9ad4454a148d07040e03842bde866bf4dd42886a..d884f5eee73ca09b547bc168776fe1b89bac0650 100644 (file)
@@ -579,8 +579,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
 #define RF3 2
        u32 rf_default[3];
        u32 rf_freq[3];
-       u8 prog_cal[3];
-       u8 prog_tab[3];
+       s32 prog_cal[3];
+       s32 prog_tab[3];
 
        i = tda18271_lookup_rf_band(fe, &freq, NULL);
 
@@ -602,32 +602,33 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
                        return bcal;
 
                tda18271_calc_rf_cal(fe, &rf_freq[rf]);
-               prog_tab[rf] = regs[R_EB14];
+               prog_tab[rf] = (s32)regs[R_EB14];
 
                if (1 == bcal)
-                       prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
+                       prog_cal[rf] =
+                               (s32)tda18271_calibrate_rf(fe, rf_freq[rf]);
                else
                        prog_cal[rf] = prog_tab[rf];
 
                switch (rf) {
                case RF1:
                        map[i].rf_a1 = 0;
-                       map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]);
+                       map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]);
                        map[i].rf1   = rf_freq[RF1] / 1000;
                        break;
                case RF2:
-                       dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) -
-                                  (s32)(prog_cal[RF1] + prog_tab[RF1]);
+                       dividend = (prog_cal[RF2] - prog_tab[RF2] -
+                                   prog_cal[RF1] + prog_tab[RF1]);
                        divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
                        map[i].rf_a1 = (dividend / divisor);
                        map[i].rf2   = rf_freq[RF2] / 1000;
                        break;
                case RF3:
-                       dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) -
-                                  (s32)(prog_cal[RF2] + prog_tab[RF2]);
+                       dividend = (prog_cal[RF3] - prog_tab[RF3] -
+                                   prog_cal[RF2] + prog_tab[RF2]);
                        divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
                        map[i].rf_a2 = (dividend / divisor);
-                       map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]);
+                       map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]);
                        map[i].rf3   = rf_freq[RF3] / 1000;
                        break;
                default:
index e7f84c705da867f32ff7a3f663897b49c293c400..3d5b6ab7e3322630814036cf65654f545cc7e095 100644 (file)
@@ -229,8 +229,7 @@ static struct tda18271_map tda18271c2_km[] = {
 static struct tda18271_map tda18271_rf_band[] = {
        { .rfmax =  47900, .val = 0x00 },
        { .rfmax =  61100, .val = 0x01 },
-/*     { .rfmax = 152600, .val = 0x02 }, */
-       { .rfmax = 121200, .val = 0x02 },
+       { .rfmax = 152600, .val = 0x02 },
        { .rfmax = 164700, .val = 0x03 },
        { .rfmax = 203500, .val = 0x04 },
        { .rfmax = 457800, .val = 0x05 },
@@ -448,7 +447,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = {
        { .rfmax = 150000, .val = 0xb0 },
        { .rfmax = 151000, .val = 0xb1 },
        { .rfmax = 152000, .val = 0xb7 },
-       { .rfmax = 153000, .val = 0xbd },
+       { .rfmax = 152600, .val = 0xbd },
        { .rfmax = 154000, .val = 0x20 },
        { .rfmax = 155000, .val = 0x22 },
        { .rfmax = 156000, .val = 0x24 },
@@ -459,7 +458,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = {
        { .rfmax = 161000, .val = 0x2d },
        { .rfmax = 163000, .val = 0x2e },
        { .rfmax = 164000, .val = 0x2f },
-       { .rfmax = 165000, .val = 0x30 },
+       { .rfmax = 164700, .val = 0x30 },
        { .rfmax = 166000, .val = 0x11 },
        { .rfmax = 167000, .val = 0x12 },
        { .rfmax = 168000, .val = 0x13 },
@@ -510,7 +509,8 @@ static struct tda18271_map tda18271c2_rf_cal[] = {
        { .rfmax = 236000, .val = 0x1b },
        { .rfmax = 237000, .val = 0x1c },
        { .rfmax = 240000, .val = 0x1d },
-       { .rfmax = 242000, .val = 0x1f },
+       { .rfmax = 242000, .val = 0x1e },
+       { .rfmax = 244000, .val = 0x1f },
        { .rfmax = 247000, .val = 0x20 },
        { .rfmax = 249000, .val = 0x21 },
        { .rfmax = 252000, .val = 0x22 },
@@ -624,7 +624,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = {
        { .rfmax = 453000, .val = 0x93 },
        { .rfmax = 454000, .val = 0x94 },
        { .rfmax = 456000, .val = 0x96 },
-       { .rfmax = 457000, .val = 0x98 },
+       { .rfmax = 457800, .val = 0x98 },
        { .rfmax = 461000, .val = 0x11 },
        { .rfmax = 468000, .val = 0x12 },
        { .rfmax = 472000, .val = 0x13 },
index 955254090a0e56fe3d7c42537f341802c6cfd2e4..03f96d6ca8946ecafc837295cee0bc41ec51b666 100644 (file)
@@ -38,7 +38,7 @@ MODULE_PARM_DESC(debug,
        DEBSTATUS);
 
 #define DRIVER_VERSION "0.1"
-#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
+#define DRIVER_NAME "flexcop-pci"
 #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
 
 struct flexcop_pci {
index fe4f894183ffcf5bb65b85ab85b4ca0acc12473d..c545039287ad7b9b374696ddc01a2203dba22a85 100644 (file)
@@ -356,13 +356,15 @@ config DVB_USB_LME2510
        select DVB_TDA826X if !DVB_FE_CUSTOMISE
        select DVB_STV0288 if !DVB_FE_CUSTOMISE
        select DVB_IX2505V if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
 
 config DVB_USB_TECHNISAT_USB2
        tristate "Technisat DVB-S/S2 USB2.0 support"
        depends on DVB_USB
-       select DVB_STB0899 if !DVB_FE_CUSTOMISE
-       select DVB_STB6100 if !DVB_FE_CUSTOMISE
+       select DVB_STV090x if !DVB_FE_CUSTOMISE
+       select DVB_STV6110x if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Technisat USB2 DVB-S/S2 device
index 97af266d7f1deb8543fe2343be238853e9e154be..65214af5cd741ddd6a5f18978350673339eab84c 100644 (file)
@@ -2162,7 +2162,7 @@ struct dibx000_agc_config dib7090_agc_config[2] = {
                .agc1_pt3       = 98,
                .agc1_slope1    = 0,
                .agc1_slope2    = 167,
-               .agc1_pt1       = 98,
+               .agc2_pt1       = 98,
                .agc2_pt2       = 255,
                .agc2_slope1    = 104,
                .agc2_slope2    = 0,
@@ -2440,11 +2440,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
        dib0700_set_i2c_speed(adap->dev, 340);
        adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
 
-       dib7090_slave_reset(adap->fe);
-
        if (adap->fe == NULL)
                return -ENODEV;
 
+       dib7090_slave_reset(adap->fe);
+
        return 0;
 }
 
index ccc2d1af49d4d65952d543d701d4096fa39666f9..6927c726ce35b4ec1c8139eb838e7822dded28da 100644 (file)
@@ -1520,6 +1520,7 @@ static int init_channel(struct ngene_channel *chan)
        if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
                dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
                set_transfer(chan, 1);
+               chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
                set_transfer(&chan->dev->channel[2], 1);
                dvb_register_device(adapter, &chan->ci_dev,
                                    &ngene_dvbdev_ci, (void *) chan,
index 23640ed44d8536a20b7c9ee56a572c704c3a0050..056138f63c7dc26d8d8b9757f2beb8b234b6209c 100644 (file)
@@ -378,7 +378,6 @@ EXPORT_SYMBOL_GPL(media_entity_create_link);
 
 static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
 {
-       const u32 mask = MEDIA_LNK_FL_ENABLED;
        int ret;
 
        /* Notify both entities. */
@@ -395,7 +394,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
                return ret;
        }
 
-       link->flags = (link->flags & ~mask) | (flags & mask);
+       link->flags = flags;
        link->reverse->flags = link->flags;
 
        return 0;
@@ -417,6 +416,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
  */
 int __media_entity_setup_link(struct media_link *link, u32 flags)
 {
+       const u32 mask = MEDIA_LNK_FL_ENABLED;
        struct media_device *mdev;
        struct media_entity *source, *sink;
        int ret = -EBUSY;
@@ -424,6 +424,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
        if (link == NULL)
                return -EINVAL;
 
+       /* The non-modifiable link flags must not be modified. */
+       if ((link->flags & ~mask) != (flags & ~mask))
+               return -EINVAL;
+
        if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
                return link->flags == flags ? 0 : -EINVAL;
 
index 299994c3aa74a01b7d9de6ef60fda37f6d1e0af5..e4c97fd6f05a329db01408effae324c4f2ef3d42 100644 (file)
@@ -166,21 +166,6 @@ config RADIO_MAXIRADIO
          To compile this driver as a module, choose M here: the
          module will be called radio-maxiradio.
 
-config RADIO_MAESTRO
-       tristate "Maestro on board radio"
-       depends on VIDEO_V4L2 && PCI
-       ---help---
-         Say Y here to directly support the on-board radio tuner on the
-         Maestro 2 or 2E sound card.
-
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-maestro.
-
 config RADIO_MIROPCM20
        tristate "miroSOUND PCM20 radio"
        depends on ISA && VIDEO_V4L2 && SND
index 2faa333719860dd92713dea4d2139c5a9080e7ae..f484a6e04eb248f80070632a39a2754c03dc435e 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
-obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
deleted file mode 100644 (file)
index 6af61bf..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-/* Maestro PCI sound card radio driver for Linux support
- * (c) 2000 A. Tlalka, atlka@pg.gda.pl
- * Notes on the hardware
- *
- *  + Frequency control is done digitally
- *  + No volume control - only mute/unmute - you have to use Aux line volume
- *  control on Maestro card to set the volume
- *  + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
- *  frequency setting (>100ms) and only when the radio is unmuted.
- *  version 0.02
- *  + io port is automatically detected - only the first radio is used
- *  version 0.03
- *  + thread access locking additions
- *  version 0.04
- * + code improvements
- * + VIDEO_TUNER_LOW is permanent
- *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
-MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
-MODULE_LICENSE("GPL");
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
-#define DRIVER_VERSION "0.06"
-
-#define GPIO_DATA      0x60   /* port offset from ESS_IO_BASE */
-
-#define IO_MASK                4      /* mask      register offset from GPIO_DATA
-                               bits 1=unmask write to given bit */
-#define IO_DIR         8      /* direction register offset from GPIO_DATA
-                               bits 0/1=read/write direction */
-
-#define GPIO6          0x0040 /* mask bits for GPIO lines */
-#define GPIO7          0x0080
-#define GPIO8          0x0100
-#define GPIO9          0x0200
-
-#define STR_DATA       GPIO6  /* radio TEA5757 pins and GPIO bits */
-#define STR_CLK                GPIO7
-#define STR_WREN       GPIO8
-#define STR_MOST       GPIO9
-
-#define FREQ_LO                 50*16000
-#define FREQ_HI                150*16000
-
-#define FREQ_IF                171200 /* 10.7*16000   */
-#define FREQ_STEP      200    /* 12.5*16      */
-
-#define FREQ2BITS(x)   ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
-                       /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
-
-#define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
-
-struct maestro {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct pci_dev *pdev;
-       struct mutex lock;
-
-       u16     io;     /* base of Maestro card radio io (GPIO_DATA)*/
-       u16     muted;  /* VIDEO_AUDIO_MUTE */
-       u16     stereo; /* VIDEO_TUNER_STEREO_ON */
-       u16     tuned;  /* signal strength (0 or 0xffff) */
-};
-
-static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
-{
-       return container_of(v4l2_dev, struct maestro, v4l2_dev);
-}
-
-static u32 radio_bits_get(struct maestro *dev)
-{
-       u16 io = dev->io, l, rdata;
-       u32 data = 0;
-       u16 omask;
-
-       omask = inw(io + IO_MASK);
-       outw(~(STR_CLK | STR_WREN), io + IO_MASK);
-       outw(0, io);
-       udelay(16);
-
-       for (l = 24; l--;) {
-               outw(STR_CLK, io);              /* HI state */
-               udelay(2);
-               if (!l)
-                       dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
-               outw(0, io);                    /* LO state */
-               udelay(2);
-               data <<= 1;                     /* shift data */
-               rdata = inw(io);
-               if (!l)
-                       dev->stereo = (rdata & STR_MOST) ?  0 : 1;
-               else if (rdata & STR_DATA)
-                       data++;
-               udelay(2);
-       }
-
-       if (dev->muted)
-               outw(STR_WREN, io);
-
-       udelay(4);
-       outw(omask, io + IO_MASK);
-
-       return data & 0x3ffe;
-}
-
-static void radio_bits_set(struct maestro *dev, u32 data)
-{
-       u16 io = dev->io, l, bits;
-       u16 omask, odir;
-
-       omask = inw(io + IO_MASK);
-       odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
-       outw(odir | STR_DATA, io + IO_DIR);
-       outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
-       udelay(16);
-       for (l = 25; l; l--) {
-               bits = ((data >> 18) & STR_DATA) | STR_WREN;
-               data <<= 1;                     /* shift data */
-               outw(bits, io);                 /* start strobe */
-               udelay(2);
-               outw(bits | STR_CLK, io);       /* HI level */
-               udelay(2);
-               outw(bits, io);                 /* LO level */
-               udelay(4);
-       }
-
-       if (!dev->muted)
-               outw(0, io);
-
-       udelay(4);
-       outw(omask, io + IO_MASK);
-       outw(odir, io + IO_DIR);
-       msleep(125);
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
-{
-       struct maestro *dev = video_drvdata(file);
-
-       strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
-       strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct maestro *dev = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       mutex_lock(&dev->lock);
-       radio_bits_get(dev);
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = FREQ_LO;
-       v->rangehigh = FREQ_HI;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       if (dev->stereo)
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = dev->tuned;
-       mutex_unlock(&dev->lock);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct maestro *dev = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-               return -EINVAL;
-       mutex_lock(&dev->lock);
-       radio_bits_set(dev, FREQ2BITS(f->frequency));
-       mutex_unlock(&dev->lock);
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct maestro *dev = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       mutex_lock(&dev->lock);
-       f->frequency = BITS2FREQ(radio_bits_get(dev));
-       mutex_unlock(&dev->lock);
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct maestro *dev = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = dev->muted;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct maestro *dev = video_drvdata(file);
-       u16 io = dev->io;
-       u16 omask;
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               mutex_lock(&dev->lock);
-               omask = inw(io + IO_MASK);
-               outw(~STR_WREN, io + IO_MASK);
-               dev->muted = ctrl->value;
-               outw(dev->muted ? STR_WREN : 0, io);
-               udelay(4);
-               outw(omask, io + IO_MASK);
-               msleep(125);
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations maestro_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static u16 __devinit radio_power_on(struct maestro *dev)
-{
-       register u16 io = dev->io;
-       register u32 ofreq;
-       u16 omask, odir;
-
-       omask = inw(io + IO_MASK);
-       odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
-       outw(odir & ~STR_WREN, io + IO_DIR);
-       dev->muted = inw(io) & STR_WREN ? 0 : 1;
-       outw(odir, io + IO_DIR);
-       outw(~(STR_WREN | STR_CLK), io + IO_MASK);
-       outw(dev->muted ? 0 : STR_WREN, io);
-       udelay(16);
-       outw(omask, io + IO_MASK);
-       ofreq = radio_bits_get(dev);
-
-       if ((ofreq < FREQ2BITS(FREQ_LO)) || (ofreq > FREQ2BITS(FREQ_HI)))
-               ofreq = FREQ2BITS(FREQ_LO);
-       radio_bits_set(dev, ofreq);
-
-       return (ofreq == radio_bits_get(dev));
-}
-
-static int __devinit maestro_probe(struct pci_dev *pdev,
-       const struct pci_device_id *ent)
-{
-       struct maestro *dev;
-       struct v4l2_device *v4l2_dev;
-       int retval;
-
-       retval = pci_enable_device(pdev);
-       if (retval) {
-               dev_err(&pdev->dev, "enabling pci device failed!\n");
-               goto err;
-       }
-
-       retval = -ENOMEM;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               dev_err(&pdev->dev, "not enough memory\n");
-               goto err;
-       }
-
-       v4l2_dev = &dev->v4l2_dev;
-       mutex_init(&dev->lock);
-       dev->pdev = pdev;
-
-       strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
-
-       retval = v4l2_device_register(&pdev->dev, v4l2_dev);
-       if (retval < 0) {
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               goto errfr;
-       }
-
-       dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-
-       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-       dev->vdev.v4l2_dev = v4l2_dev;
-       dev->vdev.fops = &maestro_fops;
-       dev->vdev.ioctl_ops = &maestro_ioctl_ops;
-       dev->vdev.release = video_device_release_empty;
-       video_set_drvdata(&dev->vdev, dev);
-
-       if (!radio_power_on(dev)) {
-               retval = -EIO;
-               goto errfr1;
-       }
-
-       retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
-       if (retval) {
-               v4l2_err(v4l2_dev, "can't register video device!\n");
-               goto errfr1;
-       }
-
-       v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
-       return 0;
-errfr1:
-       v4l2_device_unregister(v4l2_dev);
-errfr:
-       kfree(dev);
-err:
-       return retval;
-
-}
-
-static void __devexit maestro_remove(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct maestro *dev = to_maestro(v4l2_dev);
-
-       video_unregister_device(&dev->vdev);
-       v4l2_device_unregister(&dev->v4l2_dev);
-}
-
-static struct pci_device_id maestro_r_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
-               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-               .class_mask = 0xffff00 },
-       { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
-               .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-               .class_mask = 0xffff00 },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
-
-static struct pci_driver maestro_r_driver = {
-       .name           = "maestro_radio",
-       .id_table       = maestro_r_pci_tbl,
-       .probe          = maestro_probe,
-       .remove         = __devexit_p(maestro_remove),
-};
-
-static int __init maestro_radio_init(void)
-{
-       int retval = pci_register_driver(&maestro_r_driver);
-
-       if (retval)
-               printk(KERN_ERR "error during registration pci driver\n");
-
-       return retval;
-}
-
-static void __exit maestro_radio_exit(void)
-{
-       pci_unregister_driver(&maestro_r_driver);
-}
-
-module_init(maestro_radio_init);
-module_exit(maestro_radio_exit);
index dc3f04c52d5e11e923829e74a548d78d1b3e6cad..87bad7678d92f63bab822d6e8a244a6d6729fd69 100644 (file)
@@ -170,7 +170,7 @@ static int fmr2_setfreq(struct fmr2 *dev)
        return 0;
 }
 
-/* !!! not tested, in my card this does't work !!! */
+/* !!! not tested, in my card this doesn't work !!! */
 static int fmr2_setvolume(struct fmr2 *dev)
 {
        int vol[16] = { 0x021, 0x084, 0x090, 0x104,
index 585680ffbfb64b121a4eb01eff27da0346660f6b..b1193dfc5087bb0ed2f5b24e09e9665107330c6f 100644 (file)
@@ -376,7 +376,7 @@ static int __devinit saa7706h_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct saa7706h_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
index 7c0d77751f6e66ba5d77a683fb1ba3890c0c4626..0991e1973678ce0751c455cb85249264935415fb 100644 (file)
@@ -176,7 +176,7 @@ static int __devinit tef6862_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        state->freq = TEF6862_LO_FREQ;
index ebd68edf5b245566338aebe8bc0d86ae0c836bab..8fc0f081b4701ddaf3c7ab0e79b7944f5fede297 100644 (file)
@@ -46,7 +46,7 @@
 #define MOD_AUTHOR     "Jarod Wilson <jarod@wilsonet.com>"
 #define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
 #define MOD_NAME       "imon"
-#define MOD_VERSION    "0.9.2"
+#define MOD_VERSION    "0.9.3"
 
 #define DISPLAY_MINOR_BASE     144
 #define DEVICE_NAME    "lcd%d"
@@ -460,8 +460,9 @@ static int display_close(struct inode *inode, struct file *file)
 }
 
 /**
- * Sends a packet to the device -- this function must be called
- * with ictx->lock held.
+ * Sends a packet to the device -- this function must be called with
+ * ictx->lock held, or its unlock/lock sequence while waiting for tx
+ * to complete can/will lead to a deadlock.
  */
 static int send_packet(struct imon_context *ictx)
 {
@@ -991,12 +992,21 @@ static void imon_touch_display_timeout(unsigned long data)
  * the iMON remotes, and those used by the Windows MCE remotes (which is
  * really just RC-6), but only one or the other at a time, as the signals
  * are decoded onboard the receiver.
+ *
+ * This function gets called two different ways, one way is from
+ * rc_register_device, for initial protocol selection/setup, and the other is
+ * via a userspace-initiated protocol change request, either by direct sysfs
+ * prodding or by something like ir-keytable. In the rc_register_device case,
+ * the imon context lock is already held, but when initiated from userspace,
+ * it is not, so we must acquire it prior to calling send_packet, which
+ * requires that the lock is held.
  */
 static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
 {
        int retval;
        struct imon_context *ictx = rc->priv;
        struct device *dev = ictx->dev;
+       bool unlock = false;
        unsigned char ir_proto_packet[] = {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
 
@@ -1029,6 +1039,11 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
 
        memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
 
+       if (!mutex_is_locked(&ictx->lock)) {
+               unlock = true;
+               mutex_lock(&ictx->lock);
+       }
+
        retval = send_packet(ictx);
        if (retval)
                goto out;
@@ -1037,6 +1052,9 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
        ictx->pad_mouse = false;
 
 out:
+       if (unlock)
+               mutex_unlock(&ictx->lock);
+
        return retval;
 }
 
@@ -2134,6 +2152,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
                goto rdev_setup_failed;
        }
 
+       mutex_unlock(&ictx->lock);
        return ictx;
 
 rdev_setup_failed:
@@ -2205,6 +2224,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
                goto urb_submit_failed;
        }
 
+       mutex_unlock(&ictx->lock);
        return ictx;
 
 urb_submit_failed:
@@ -2299,6 +2319,8 @@ static int __devinit imon_probe(struct usb_interface *interface,
        usb_set_intfdata(interface, ictx);
 
        if (ifnum == 0) {
+               mutex_lock(&ictx->lock);
+
                if (product == 0xffdc && ictx->rf_device) {
                        sysfs_err = sysfs_create_group(&interface->dev.kobj,
                                                       &imon_rf_attr_group);
@@ -2309,13 +2331,14 @@ static int __devinit imon_probe(struct usb_interface *interface,
 
                if (ictx->display_supported)
                        imon_init_display(ictx, interface);
+
+               mutex_unlock(&ictx->lock);
        }
 
        dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
                 "usb<%d:%d> initialized\n", vendor, product, ifnum,
                 usbdev->bus->busnum, usbdev->devnum);
 
-       mutex_unlock(&ictx->lock);
        mutex_unlock(&driver_lock);
 
        return 0;
index accaf6c9789a6bcae94157be03cd6240e15ad120..43908a70bd8b8df31e6965844883d68004328726 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/bitops.h>
index 044fb7a382d6bd888898cc889b78cdba15eeec90..0c273ec465c96142437ae4fe1272aee3a4e5f662 100644 (file)
@@ -220,6 +220,8 @@ static struct usb_device_id mceusb_dev_table[] = {
        { USB_DEVICE(VENDOR_PHILIPS, 0x206c) },
        /* Philips/Spinel plus IR transceiver for ASUS */
        { USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
+       /* Philips IR transceiver (Dell branded) */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x2093) },
        /* Realtek MCE IR Receiver and card reader */
        { USB_DEVICE(VENDOR_REALTEK, 0x0161),
          .driver_info = MULTIFUNCTION },
index f53f9c68d38dcddca8842a05e2e904b7174ae10a..a2706648e3651f30468310fcb9213bd7af7c4658 100644 (file)
@@ -707,7 +707,8 @@ static void ir_close(struct input_dev *idev)
 {
        struct rc_dev *rdev = input_get_drvdata(idev);
 
-       rdev->close(rdev);
+        if (rdev)
+               rdev->close(rdev);
 }
 
 /* class for /sys/class/rc */
@@ -733,6 +734,7 @@ static struct {
        { RC_TYPE_SONY,         "sony"          },
        { RC_TYPE_RC5_SZ,       "rc-5-sz"       },
        { RC_TYPE_LIRC,         "lirc"          },
+       { RC_TYPE_OTHER,        "other"         },
 };
 
 #define PROTO_NONE     "none"
index 4498b944dec81d8af9e9ae7a30370bde671bcce2..00f51dd121f3c3f029431af9fdf9cc0d4a421c60 100644 (file)
@@ -875,7 +875,7 @@ config MX3_VIDEO
 config VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
-       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF2_DMA_CONTIG
        select MX3_VIDEO
        ---help---
          This is a v4l2 driver for the i.MX3x Camera Sensor Interface
index c6e2ca3b1149ad37305a04dc40befac5b0ef8996..6fbc356113c18077352876da72ef0a93dbc3abdc 100644 (file)
@@ -350,9 +350,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
 
                /* No struct video_device, but can have buffers allocated */
                if (type == CX18_ENC_STREAM_TYPE_IDX) {
+                       /* If the module params didn't inhibit IDX ... */
                        if (cx->stream_buffers[type] != 0) {
                                cx->stream_buffers[type] = 0;
-                               cx18_stream_free(&cx->streams[type]);
+                               /*
+                                * Before calling cx18_stream_free(),
+                                * check if the IDX stream was actually set up.
+                                * Needed, since the cx18_probe() error path
+                                * exits through here as well as normal clean up
+                                */
+                               if (cx->streams[type].buffers != 0)
+                                       cx18_stream_free(&cx->streams[type]);
                        }
                        continue;
                }
index 3b6e7f28568e41164613d204c71fcea8ea05c19c..caab1bfb79e2b8d0cf943c83cf31c955fa191f06 100644 (file)
@@ -22,6 +22,7 @@ config VIDEO_CX23885
        select DVB_CX24116 if !DVB_FE_CUSTOMISE
        select DVB_STV0900 if !DVB_FE_CUSTOMISE
        select DVB_DS3000 if !DVB_FE_CUSTOMISE
+       select DVB_STV0367 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
index 1a116911571629f3942436c7a407a2512a06870b..0382ea752e6fb0015119b5a30656f5e34d59ad41 100644 (file)
@@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd)
 static int imx074_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
-       return -1;
+       return -EINVAL;
 }
 
 static struct soc_camera_ops imx074_ops = {
index 5e1c9a81984ca837955d2f67a895e5265bb37e6a..303ffa7df4aca521c617ed1629678deb91ea3606 100644 (file)
@@ -174,7 +174,7 @@ static int m52790_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
 
index 503bd7922bd6bcc8473bab58625506f56a082f35..472a69359e609c16c67b014da479e7bbeb2c29ed 100644 (file)
@@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
        }
 
        switch (xclksel) {
-       case 0:
+       case ISP_XCLK_A:
                isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
                                ISPTCTRL_CTRL_DIVA_MASK,
                                divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
                dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
                        currentxclk);
                break;
-       case 1:
+       case ISP_XCLK_B:
                isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
                                ISPTCTRL_CTRL_DIVB_MASK,
                                divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
                dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
                        currentxclk);
                break;
+       case ISP_XCLK_NONE:
        default:
                omap3isp_put(isp);
                dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
@@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
        }
 
        /* Do we go from stable whatever to clock? */
-       if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2)
+       if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
                omap3isp_get(isp);
        /* Stopping the clock. */
-       else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2)
+       else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
                omap3isp_put(isp);
 
-       isp->xclk_divisor[xclksel] = divisor;
+       isp->xclk_divisor[xclksel - 1] = divisor;
 
        omap3isp_put(isp);
 
@@ -285,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle)
  */
 void omap3isp_configure_bridge(struct isp_device *isp,
                               enum ccdc_input_entity input,
-                              const struct isp_parallel_platform_data *pdata)
+                              const struct isp_parallel_platform_data *pdata,
+                              unsigned int shift)
 {
        u32 ispctrl_val;
 
@@ -298,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp,
        switch (input) {
        case CCDC_INPUT_PARALLEL:
                ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
-               ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT;
                ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
                ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
+               shift += pdata->data_lane_shift * 2;
                break;
 
        case CCDC_INPUT_CSI2A:
@@ -319,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp,
                return;
        }
 
+       ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
+
        ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
        ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
 
@@ -658,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
 
        /* Apply power change to connected non-nodes. */
        ret = isp_pipeline_pm_power(entity, change);
+       if (ret < 0)
+               entity->use_count -= change;
 
        mutex_unlock(&entity->parent->graph_mutex);
 
@@ -872,6 +878,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
                }
        }
 
+       if (failure < 0)
+               isp->needs_reset = true;
+
        return failure;
 }
 
@@ -884,7 +893,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
  * single-shot or continuous mode.
  *
  * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
+ * operation otherwise. The pipeline state is not updated when the operation
+ * fails, except when stopping the pipeline.
  */
 int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
                                 enum isp_pipeline_stream_state state)
@@ -895,7 +905,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
                ret = isp_pipeline_disable(pipe);
        else
                ret = isp_pipeline_enable(pipe, state);
-       pipe->stream_state = state;
+
+       if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED)
+               pipe->stream_state = state;
 
        return ret;
 }
@@ -1481,6 +1493,10 @@ void omap3isp_put(struct isp_device *isp)
        if (--isp->ref_count == 0) {
                isp_disable_interrupts(isp);
                isp_save_ctx(isp);
+               if (isp->needs_reset) {
+                       isp_reset(isp);
+                       isp->needs_reset = false;
+               }
                isp_disable_clocks(isp);
        }
        mutex_unlock(&isp->isp_mutex);
index cf5214e95a920ca11bc1cea5bac2c6efede31fbf..2620c405f5e42cf0f37d7d724535b7e3593f6a1c 100644 (file)
@@ -132,7 +132,6 @@ struct isp_reg {
 
 /**
  * struct isp_parallel_platform_data - Parallel interface platform data
- * @width: Parallel bus width in bits (8, 10, 11 or 12)
  * @data_lane_shift: Data lane shifter
  *             0 - CAMEXT[13:0] -> CAM[13:0]
  *             1 - CAMEXT[13:2] -> CAM[11:0]
@@ -146,7 +145,6 @@ struct isp_reg {
  *             ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian
  */
 struct isp_parallel_platform_data {
-       unsigned int width;
        unsigned int data_lane_shift:2;
        unsigned int clk_pol:1;
        unsigned int bridge:4;
@@ -262,6 +260,7 @@ struct isp_device {
        /* ISP Obj */
        spinlock_t stat_lock;   /* common lock for statistic drivers */
        struct mutex isp_mutex; /* For handling ref_count field */
+       bool needs_reset;
        int has_context;
        int ref_count;
        unsigned int autoidle;
@@ -311,11 +310,12 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
                                 enum isp_pipeline_stream_state state);
 void omap3isp_configure_bridge(struct isp_device *isp,
                               enum ccdc_input_entity input,
-                              const struct isp_parallel_platform_data *pdata);
+                              const struct isp_parallel_platform_data *pdata,
+                              unsigned int shift);
 
-#define ISP_XCLK_NONE                  -1
-#define ISP_XCLK_A                     0
-#define ISP_XCLK_B                     1
+#define ISP_XCLK_NONE                  0
+#define ISP_XCLK_A                     1
+#define ISP_XCLK_B                     2
 
 struct isp_device *omap3isp_get(struct isp_device *isp);
 void omap3isp_put(struct isp_device *isp);
index 5ff9d14ce71099cc672e71e2bd1d7ca619bbcc98..39d501bda6362c485468dcc714b1a7fe3375dd8c 100644 (file)
@@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
 
 static const unsigned int ccdc_fmts[] = {
        V4L2_MBUS_FMT_Y8_1X8,
+       V4L2_MBUS_FMT_Y10_1X10,
+       V4L2_MBUS_FMT_Y12_1X12,
+       V4L2_MBUS_FMT_SGRBG8_1X8,
+       V4L2_MBUS_FMT_SRGGB8_1X8,
+       V4L2_MBUS_FMT_SBGGR8_1X8,
+       V4L2_MBUS_FMT_SGBRG8_1X8,
        V4L2_MBUS_FMT_SGRBG10_1X10,
        V4L2_MBUS_FMT_SRGGB10_1X10,
        V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -1110,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        struct isp_parallel_platform_data *pdata = NULL;
        struct v4l2_subdev *sensor;
        struct v4l2_mbus_framefmt *format;
+       const struct isp_format_info *fmt_info;
+       struct v4l2_subdev_format fmt_src;
+       unsigned int depth_out;
+       unsigned int depth_in = 0;
        struct media_pad *pad;
        unsigned long flags;
+       unsigned int shift;
        u32 syn_mode;
        u32 ccdc_pattern;
 
-       if (ccdc->input == CCDC_INPUT_PARALLEL) {
-               pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
-               sensor = media_entity_to_v4l2_subdev(pad->entity);
+       pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+       sensor = media_entity_to_v4l2_subdev(pad->entity);
+       if (ccdc->input == CCDC_INPUT_PARALLEL)
                pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
                        ->bus.parallel;
+
+       /* Compute shift value for lane shifter to configure the bridge. */
+       fmt_src.pad = pad->index;
+       fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
+               fmt_info = omap3isp_video_format_info(fmt_src.format.code);
+               depth_in = fmt_info->bpp;
        }
 
-       omap3isp_configure_bridge(isp, ccdc->input, pdata);
+       fmt_info = omap3isp_video_format_info
+               (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+       depth_out = fmt_info->bpp;
+
+       shift = depth_in - depth_out;
+       omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
 
-       ccdc->syncif.datsz = pdata ? pdata->width : 10;
+       ccdc->syncif.datsz = depth_out;
        ccdc_config_sync_if(ccdc, &ccdc->syncif);
 
        /* CCDC_PAD_SINK */
@@ -1338,7 +1361,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
  * @ccdc: Pointer to ISP CCDC device.
  * @event: Pointing which event trigger handler
  *
- * Return 1 when the event and stopping request combination is satisfyied,
+ * Return 1 when the event and stopping request combination is satisfied,
  * zero otherwise.
  */
 static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
@@ -1618,7 +1641,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 
        ccdc_set_outaddr(ccdc, buffer->isp_addr);
 
-       /* We now have a buffer queued on the output, restart the pipeline in
+       /* We now have a buffer queued on the output, restart the pipeline
         * on the next CCDC interrupt if running in continuous mode (or when
         * starting the stream).
         */
index 2b16988a501d563ba15cfc17cb4f02987e3d3c4f..aba537af87e43fec1109c5d2dfada0ac88464eca 100644 (file)
@@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = {
  * @configs - pointer to update config structure.
  * @config - return pointer to appropriate structure field.
  * @bit - for which feature to return pointers.
- * Return size of coresponding prev_params member
+ * Return size of corresponding prev_params member
  */
 static u32
 __preview_get_ptrs(struct prev_params *params, void **param,
index 8fddc5806b0d81365d67a8ee0c9195cc2b3d4262..9c317148205f82a73cb774607ca0a2ea412d2ea6 100644 (file)
@@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
        up_read(&current->mm->mmap_sem);
 
        if (ret != buf->npages) {
-               buf->npages = ret;
+               buf->npages = ret < 0 ? 0 : ret;
                isp_video_buffer_cleanup(buf);
                return -EFAULT;
        }
@@ -408,8 +408,8 @@ done:
  * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
  *
  * This function locates the VMAs for the buffer's userspace address and checks
- * that their flags match. The onlflag that we need to care for at the moment is
- * VM_PFNMAP.
+ * that their flags match. The only flag that we need to care for at the moment
+ * is VM_PFNMAP.
  *
  * The buffer vm_flags field is set to the first VMA flags.
  *
index 653f88ba56db85f9deb786f1512ea3db200490b5..0bb0f8cd36f51c312979719b1515b8b52f029929 100644 (file)
@@ -714,19 +714,50 @@ static void resizer_print_status(struct isp_res_device *res)
  * iw and ih are the input width and height after cropping. Those equations need
  * to be satisfied exactly for the resizer to work correctly.
  *
- * Reverting the equations, we can compute the resizing ratios with
+ * The equations can't be easily reverted, as the >> 8 operation is not linear.
+ * In addition, not all input sizes can be achieved for a given output size. To
+ * get the highest input size lower than or equal to the requested input size,
+ * we need to compute the highest resizing ratio that satisfies the following
+ * inequality (taking the 4-tap mode width equation as an example)
+ *
+ *     iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
+ *
+ * (where iw is the requested input width) which can be rewritten as
+ *
+ *       iw - 7            >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
+ *      (iw - 7) << 8      >=  32 * sph + (ow - 1) * hrsz + 16 - b
+ *     ((iw - 7) << 8) + b >=  32 * sph + (ow - 1) * hrsz + 16
+ *
+ * where b is the value of the 8 least significant bits of the right hand side
+ * expression of the last inequality. The highest resizing ratio value will be
+ * achieved when b is equal to its maximum value of 255. That resizing ratio
+ * value will still satisfy the original inequality, as b will disappear when
+ * the expression will be shifted right by 8.
+ *
+ * The reverted the equations thus become
  *
  * - 8-phase, 4-tap mode
- *     hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
- *     vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
+ *     hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
+ *     vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
  * - 4-phase, 7-tap mode
- *     hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
- *     vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
+ *     hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
+ *     vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
  *
- * The ratios are integer values, and must be rounded down to ensure that the
- * cropped input size is not bigger than the uncropped input size. As the ratio
- * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
- * 7-tap mode equations to compute a ratio approximation.
+ * The ratios are integer values, and are rounded down to ensure that the
+ * cropped input size is not bigger than the uncropped input size.
+ *
+ * As the number of phases/taps, used to select the correct equations to compute
+ * the ratio, depends on the ratio, we start with the 4-tap mode equations to
+ * compute an approximation of the ratio, and switch to the 7-tap mode equations
+ * if the approximation is higher than the ratio threshold.
+ *
+ * As the 7-tap mode equations will return a ratio smaller than or equal to the
+ * 4-tap mode equations, the resulting ratio could become lower than or equal to
+ * the ratio threshold. This 'equations loop' isn't an issue as long as the
+ * correct equations are used to compute the final input size. Starting with the
+ * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
+ * loop', the smallest of the ratio values will be used, never exceeding the
+ * requested input size.
  *
  * We first clamp the output size according to the hardware capabilitie to avoid
  * auto-cropping the input more than required to satisfy the TRM equations. The
@@ -775,6 +806,8 @@ static void resizer_calc_ratios(struct isp_res_device *res,
        unsigned int max_width;
        unsigned int max_height;
        unsigned int width_alignment;
+       unsigned int width;
+       unsigned int height;
 
        /*
         * Clamp the output height based on the hardware capabilities and
@@ -786,19 +819,22 @@ static void resizer_calc_ratios(struct isp_res_device *res,
        max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
        output->height = clamp(output->height, min_height, max_height);
 
-       ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
+       ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
                    / (output->height - 1);
+       if (ratio->vert > MID_RESIZE_VALUE)
+               ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
+                           / (output->height - 1);
        ratio->vert = clamp_t(unsigned int, ratio->vert,
                              MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
 
        if (ratio->vert <= MID_RESIZE_VALUE) {
                upscaled_height = (output->height - 1) * ratio->vert
                                + 32 * spv + 16;
-               input->height = (upscaled_height >> 8) + 4;
+               height = (upscaled_height >> 8) + 4;
        } else {
                upscaled_height = (output->height - 1) * ratio->vert
                                + 64 * spv + 32;
-               input->height = (upscaled_height >> 8) + 7;
+               height = (upscaled_height >> 8) + 7;
        }
 
        /*
@@ -854,20 +890,29 @@ static void resizer_calc_ratios(struct isp_res_device *res,
                              max_width & ~(width_alignment - 1));
        output->width = ALIGN(output->width, width_alignment);
 
-       ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
+       ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
                    / (output->width - 1);
+       if (ratio->horz > MID_RESIZE_VALUE)
+               ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
+                           / (output->width - 1);
        ratio->horz = clamp_t(unsigned int, ratio->horz,
                              MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
 
        if (ratio->horz <= MID_RESIZE_VALUE) {
                upscaled_width = (output->width - 1) * ratio->horz
                               + 32 * sph + 16;
-               input->width = (upscaled_width >> 8) + 7;
+               width = (upscaled_width >> 8) + 7;
        } else {
                upscaled_width = (output->width - 1) * ratio->horz
                               + 64 * sph + 32;
-               input->width = (upscaled_width >> 8) + 7;
+               width = (upscaled_width >> 8) + 7;
        }
+
+       /* Center the new crop rectangle. */
+       input->left += (input->width - width) / 2;
+       input->top += (input->height - height) / 2;
+       input->width = width;
+       input->height = height;
 }
 
 /*
index 820950c9ef464d0f9f0b419f14d89549c33e63eb..d86da94fa50dcb292e7c4899de498767ad954237 100644 (file)
@@ -131,9 +131,9 @@ struct ispstat {
 struct ispstat_generic_config {
        /*
         * Fields must be in the same order as in:
-        *  - isph3a_aewb_config
-        *  - isph3a_af_config
-        *  - isphist_config
+        *  - omap3isp_h3a_aewb_config
+        *  - omap3isp_h3a_af_config
+        *  - omap3isp_hist_config
         */
        u32 buf_size;
        u16 config_counter;
index 208a7ec739d711d11d2330b9af1e06cc36086006..9cd8f1aa567b9ce2f094b00a4d42f7c6132dd92c 100644 (file)
 
 static struct isp_format_info formats[] = {
        { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
-         V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, },
+         V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_GREY, 8, },
+       { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y10, 10, },
+       { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y12, 12, },
+       { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR8, 8, },
+       { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG8, 8, },
+       { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG8, 8, },
+       { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB8, 8, },
        { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
-         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+         V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+         V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
        { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
-         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, },
+         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR10, 10, },
        { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
-         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, },
+         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG10, 10, },
        { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
-         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, },
+         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG10, 10, },
        { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
-         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, },
+         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB10, 10, },
        { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
-         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, },
+         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR12, 12, },
        { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
-         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, },
+         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG12, 12, },
        { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
-         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, },
+         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG12, 12, },
        { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
-         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, },
+         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB12, 12, },
        { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
-         V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, },
+         V4L2_MBUS_FMT_UYVY8_1X16, 0,
+         V4L2_PIX_FMT_UYVY, 16, },
        { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
-         V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, },
+         V4L2_MBUS_FMT_YUYV8_1X16, 0,
+         V4L2_PIX_FMT_YUYV, 16, },
 };
 
 const struct isp_format_info *
@@ -85,6 +115,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
        return NULL;
 }
 
+/*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in,
+               enum v4l2_mbus_pixelcode out,
+               unsigned int additional_shift)
+{
+       const struct isp_format_info *in_info, *out_info;
+
+       if (in == out)
+               return true;
+
+       in_info = omap3isp_video_format_info(in);
+       out_info = omap3isp_video_format_info(out);
+
+       if ((in_info->flavor == 0) || (out_info->flavor == 0))
+               return false;
+
+       if (in_info->flavor != out_info->flavor)
+               return false;
+
+       return in_info->bpp - out_info->bpp + additional_shift <= 6;
+}
+
 /*
  * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
  * @video: ISP video instance
@@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                return -EPIPE;
 
        while (1) {
+               unsigned int shifter_link;
                /* Retrieve the sink format */
                pad = &subdev->entity.pads[0];
                if (!(pad->flags & MEDIA_PAD_FL_SINK))
@@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                                return -ENOSPC;
                }
 
+               /* If sink pad is on CCDC, the link has the lane shifter
+                * in the middle of it. */
+               shifter_link = subdev == &isp->isp_ccdc.subdev;
+
                /* Retrieve the source format */
                pad = media_entity_remote_source(pad);
                if (pad == NULL ||
@@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                        return -EPIPE;
 
                /* Check if the two ends match */
-               if (fmt_source.format.code != fmt_sink.format.code ||
-                   fmt_source.format.width != fmt_sink.format.width ||
+               if (fmt_source.format.width != fmt_sink.format.width ||
                    fmt_source.format.height != fmt_sink.format.height)
                        return -EPIPE;
+
+               if (shifter_link) {
+                       unsigned int parallel_shift = 0;
+                       if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
+                               struct isp_parallel_platform_data *pdata =
+                                       &((struct isp_v4l2_subdevs_group *)
+                                             subdev->host_priv)->bus.parallel;
+                               parallel_shift = pdata->data_lane_shift * 2;
+                       }
+                       if (!isp_video_is_shiftable(fmt_source.format.code,
+                                               fmt_sink.format.code,
+                                               parallel_shift))
+                               return -EPIPE;
+               } else if (fmt_source.format.code != fmt_sink.format.code)
+                       return -EPIPE;
        }
 
        return 0;
index 524a1acd0906db272119820bf4c911324f2e426f..911bea64e78a318deded72ceac1701e1b55e8b6b 100644 (file)
@@ -49,6 +49,8 @@ struct v4l2_pix_format;
  *     bits. Identical to @code if the format is 10 bits wide or less.
  * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
  *     format. Identical to @code if the format is not DPCM compressed.
+ * @flavor: V4L2 media bus format code for the same pixel layout but
+ *     shifted to be 8 bits per pixel. =0 if format is not shiftable.
  * @pixelformat: V4L2 pixel format FCC identifier
  * @bpp: Bits per pixel
  */
@@ -56,6 +58,7 @@ struct isp_format_info {
        enum v4l2_mbus_pixelcode code;
        enum v4l2_mbus_pixelcode truncated;
        enum v4l2_mbus_pixelcode uncompressed;
+       enum v4l2_mbus_pixelcode flavor;
        u32 pixelformat;
        unsigned int bpp;
 };
index 95f8b4e11e46f71773b9f8f2556a06be094e9510..d142b40ea64efd1135dbfc242b5fd7d4c7092697 100644 (file)
@@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
        if (ret)
                return ret;
 
-       if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
+       if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
                return -EBUSY;
 
        frame = &ctx->d_frame;
@@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       for (i = 0; i < frame->fmt->colplanes; i++)
-               frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+       for (i = 0; i < frame->fmt->colplanes; i++) {
+               frame->payload[i] =
+                       (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
+       }
 
        /* Output DMA frame pixel size and offsets. */
        frame->f_width = pix->plane_fmt[0].bytesperline * 8
index 6c919b38a3d89c17c33d4cd5d4beee2252f23929..dc91a8511af66ca1bb0f898a68dba0ac4c873257 100644 (file)
@@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
 {
        struct fimc_vid_cap *cap = &fimc->vid_cap;
        struct fimc_vid_buffer *v_buf;
+       struct timeval *tv;
+       struct timespec ts;
 
        if (!list_empty(&cap->active_buf_q) &&
            test_bit(ST_CAPT_RUN, &fimc->state)) {
+               ktime_get_real_ts(&ts);
+
                v_buf = active_queue_pop(cap);
+
+               tv = &v_buf->vb.v4l2_buf.timestamp;
+               tv->tv_sec = ts.tv_sec;
+               tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+               v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
+
                vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
        }
 
@@ -758,7 +768,7 @@ static void fimc_unlock(struct vb2_queue *vq)
        mutex_unlock(&ctx->fimc_dev->lock);
 }
 
-struct vb2_ops fimc_qops = {
+static struct vb2_ops fimc_qops = {
        .queue_setup     = fimc_queue_setup,
        .buf_prepare     = fimc_buf_prepare,
        .buf_queue       = fimc_buf_queue,
@@ -927,23 +937,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
        pix->num_planes = fmt->memplanes;
        pix->colorspace = V4L2_COLORSPACE_JPEG;
 
-       for (i = 0; i < pix->num_planes; ++i) {
-               int bpl = pix->plane_fmt[i].bytesperline;
 
-               dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
-                   i, bpl, fmt->depth[i], pix->width, pix->height);
+       for (i = 0; i < pix->num_planes; ++i) {
+               u32 bpl = pix->plane_fmt[i].bytesperline;
+               u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
 
-               if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
-                       bpl = (pix->width * fmt->depth[0]) >> 3;
+               if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
+                       bpl = pix->width; /* Planar */
 
-               if (!pix->plane_fmt[i].sizeimage)
-                       pix->plane_fmt[i].sizeimage = pix->height * bpl;
+               if (fmt->colplanes == 1 && /* Packed */
+                   (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
+                       bpl = (pix->width * fmt->depth[0]) / 8;
 
-               pix->plane_fmt[i].bytesperline = bpl;
+               if (i == 0) /* Same bytesperline for each plane. */
+                       mod_x = bpl;
 
-               dbg("[%d]: bpl: %d, sizeimage: %d",
-                   i, pix->plane_fmt[i].bytesperline,
-                   pix->plane_fmt[i].sizeimage);
+               pix->plane_fmt[i].bytesperline = mod_x;
+               *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
        }
 
        return 0;
@@ -965,7 +975,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 
-       if (vb2_is_streaming(vq)) {
+       if (vb2_is_busy(vq)) {
                v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type);
                return -EBUSY;
        }
@@ -985,8 +995,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
        if (!frame->fmt)
                return -EINVAL;
 
-       for (i = 0; i < frame->fmt->colplanes; i++)
-               frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+       for (i = 0; i < frame->fmt->colplanes; i++) {
+               frame->payload[i] =
+                       (pix->width * pix->height * frame->fmt->depth[i]) / 8;
+       }
 
        frame->f_width  = pix->plane_fmt[0].bytesperline * 8 /
                frame->fmt->depth[0];
@@ -1750,7 +1762,7 @@ static int __devexit fimc_remove(struct platform_device *pdev)
 }
 
 /* Image pixel limits, similar across several FIMC HW revisions. */
-static struct fimc_pix_limit s5p_pix_limit[3] = {
+static struct fimc_pix_limit s5p_pix_limit[4] = {
        [0] = {
                .scaler_en_w    = 3264,
                .scaler_dis_w   = 8192,
@@ -1775,6 +1787,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = {
                .out_rot_en_w   = 1280,
                .out_rot_dis_w  = 1920,
        },
+       [3] = {
+               .scaler_en_w    = 1920,
+               .scaler_dis_w   = 8192,
+               .in_rot_en_h    = 1366,
+               .in_rot_dis_w   = 8192,
+               .out_rot_en_w   = 1366,
+               .out_rot_dis_w  = 1920,
+       },
 };
 
 static struct samsung_fimc_variant fimc0_variant_s5p = {
@@ -1827,7 +1847,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
        .pix_limit       = &s5p_pix_limit[2],
 };
 
-static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
+static struct samsung_fimc_variant fimc0_variant_exynos4 = {
        .pix_hoff        = 1,
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
@@ -1840,7 +1860,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
        .pix_limit       = &s5p_pix_limit[1],
 };
 
-static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
+static struct samsung_fimc_variant fimc2_variant_exynos4 = {
        .pix_hoff        = 1,
        .has_cistatus2   = 1,
        .has_mainscaler_ext = 1,
@@ -1848,7 +1868,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
        .min_out_pixsize = 16,
        .hor_offs_align  = 1,
        .out_buf_count   = 32,
-       .pix_limit       = &s5p_pix_limit[2],
+       .pix_limit       = &s5p_pix_limit[3],
 };
 
 /* S5PC100 */
@@ -1874,12 +1894,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
 };
 
 /* S5PV310, S5PC210 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = {
+static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
        .variant = {
-               [0] = &fimc0_variant_s5pv310,
-               [1] = &fimc0_variant_s5pv310,
-               [2] = &fimc0_variant_s5pv310,
-               [3] = &fimc2_variant_s5pv310,
+               [0] = &fimc0_variant_exynos4,
+               [1] = &fimc0_variant_exynos4,
+               [2] = &fimc0_variant_exynos4,
+               [3] = &fimc2_variant_exynos4,
        },
        .num_entities = 4,
        .lclk_frequency = 166000000UL,
@@ -1893,8 +1913,8 @@ static struct platform_device_id fimc_driver_ids[] = {
                .name           = "s5pv210-fimc",
                .driver_data    = (unsigned long)&fimc_drvdata_s5pv210,
        }, {
-               .name           = "s5pv310-fimc",
-               .driver_data    = (unsigned long)&fimc_drvdata_s5pv310,
+               .name           = "exynos4-fimc",
+               .driver_data    = (unsigned long)&fimc_drvdata_exynos4,
        },
        {},
 };
index 3fe54bf41142d025437859ea71dbd0765bc67d0c..134e86bf6d9750e3c1f2db2685fc10d91c4a32d9 100644 (file)
@@ -922,7 +922,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                        /* Try 2560x1920, 1280x960, 640x480, 320x240 */
                        mf.width        = 2560 >> shift;
                        mf.height       = 1920 >> shift;
-                       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
                                                         s_mbus_fmt, &mf);
                        if (ret < 0)
                                return ret;
@@ -1224,7 +1224,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
        struct v4l2_cropcap cap;
        int ret;
 
-       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+       ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
                                         s_mbus_fmt, mf);
        if (ret < 0)
                return ret;
@@ -1254,7 +1254,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
                tmp_h = min(2 * tmp_h, max_height);
                mf->width = tmp_w;
                mf->height = tmp_h;
-               ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+               ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
                                                 s_mbus_fmt, mf);
                dev_geo(dev, "Camera scaled to %ux%u\n",
                        mf->width, mf->height);
@@ -1658,7 +1658,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        mf.code         = xlate->code;
        mf.colorspace   = pix->colorspace;
 
-       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
+       ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf);
        if (ret < 0)
                return ret;
 
@@ -1682,7 +1682,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                         */
                        mf.width = 2560;
                        mf.height = 1920;
-                       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video,
                                                         try_mbus_fmt, &mf);
                        if (ret < 0) {
                                /* Shouldn't actually happen... */
index dd1b81b1442bcbaa194f9f4830140e184a3d84af..98b87481fa94ba232e586323ebd3bb912abf11d5 100644 (file)
@@ -38,6 +38,8 @@ struct sh_csi2 {
        void __iomem                    *base;
        struct platform_device          *pdev;
        struct sh_csi2_client_config    *client;
+       unsigned long (*query_bus_param)(struct soc_camera_device *);
+       int (*set_bus_param)(struct soc_camera_device *, unsigned long);
 };
 
 static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
@@ -208,6 +210,7 @@ static int sh_csi2_notify(struct notifier_block *nb,
        case BUS_NOTIFY_BOUND_DRIVER:
                snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
                         dev_name(v4l2_dev->dev), ".mipi-csi");
+               priv->subdev.grp_id = (long)icd;
                ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
                dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
                if (ret < 0)
@@ -215,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb,
 
                priv->client = pdata->clients + i;
 
+               priv->set_bus_param             = icd->ops->set_bus_param;
+               priv->query_bus_param           = icd->ops->query_bus_param;
                icd->ops->set_bus_param         = sh_csi2_set_bus_param;
                icd->ops->query_bus_param       = sh_csi2_query_bus_param;
 
@@ -226,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb,
                priv->client = NULL;
 
                /* Driver is about to be unbound */
-               icd->ops->set_bus_param         = NULL;
-               icd->ops->query_bus_param       = NULL;
+               icd->ops->set_bus_param         = priv->set_bus_param;
+               icd->ops->query_bus_param       = priv->query_bus_param;
+               priv->set_bus_param             = NULL;
+               priv->query_bus_param           = NULL;
 
                v4l2_device_unregister_subdev(&priv->subdev);
 
index 46284489e4eb8b89e96e354e4defca8bd1710ebd..3973f9a94753258da45666085da2b35f9d4ae986 100644 (file)
@@ -996,10 +996,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
 {
        struct i2c_client *client =
                to_i2c_client(to_soc_camera_control(icd));
+       struct i2c_adapter *adap = client->adapter;
        dev_set_drvdata(&icd->dev, NULL);
        v4l2_device_unregister_subdev(i2c_get_clientdata(client));
        i2c_unregister_device(client);
-       i2c_put_adapter(client->adapter);
+       i2c_put_adapter(adap);
 }
 #else
 #define soc_camera_init_i2c(icd, icl)  (-ENODEV)
@@ -1071,6 +1072,9 @@ static int soc_camera_probe(struct device *dev)
                }
        }
 
+       sd = soc_camera_to_subdev(icd);
+       sd->grp_id = (long)icd;
+
        /* At this point client .probe() should have run already */
        ret = soc_camera_init_user_formats(icd);
        if (ret < 0)
@@ -1092,7 +1096,6 @@ static int soc_camera_probe(struct device *dev)
                goto evidstart;
 
        /* Try to improve our guess of a reasonable window format */
-       sd = soc_camera_to_subdev(icd);
        if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
                icd->user_width         = mf.width;
                icd->user_height        = mf.height;
index 5d4cf3b3d435076a2f8db0ff102aa1815894bbea..22fa8202d5ca314466c4c11d8f13c877777db454 100644 (file)
@@ -171,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
index 19621ed523ec605c6f55945eb43c1cf19dd5febb..827425c5b866e9e895e8393a7d8e5c5c8ca98723 100644 (file)
@@ -152,7 +152,7 @@ static int tea6415c_probe(struct i2c_client *client,
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
-       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
index 5ea840401f21865120623691ecc0d20cc084decc..f350b6c24500110dbce1f064e24365dc5974fe7b 100644 (file)
@@ -125,7 +125,7 @@ static int tea6420_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
index f8138c75be8be3a25834ca4471da721b5163e5d1..1aab96a882034a41867641e3d1022a3643303dc2 100644 (file)
@@ -230,7 +230,7 @@ static int upd64031a_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
index 28e0e6b6ca8491d815de9f822e19fae412b23ca6..9bbe61700fd5c238d253d309ea37a21a4f3ca6a1 100644 (file)
@@ -202,7 +202,7 @@ static int upd64083_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
index 498e6742579e76bb400f79af9dac37d1d7fe10b4..6dc7196296b341bdf87956a600ae74ebb522835e 100644 (file)
@@ -389,7 +389,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
        video_get(vdev);
        mutex_unlock(&videodev_lock);
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+           vdev->vfl_type != VFL_TYPE_SUBDEV) {
                entity = media_entity_get(&vdev->entity);
                if (!entity) {
                        ret = -EBUSY;
@@ -415,7 +416,8 @@ err:
        /* decrease the refcount in case of an error */
        if (ret) {
 #if defined(CONFIG_MEDIA_CONTROLLER)
-               if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+               if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+                   vdev->vfl_type != VFL_TYPE_SUBDEV)
                        media_entity_put(entity);
 #endif
                video_put(vdev);
@@ -437,7 +439,8 @@ static int v4l2_release(struct inode *inode, struct file *filp)
                        mutex_unlock(vdev->lock);
        }
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+           vdev->vfl_type != VFL_TYPE_SUBDEV)
                media_entity_put(&vdev->entity);
 #endif
        /* decrease the refcount unconditionally since the release()
@@ -686,7 +689,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
        /* Part 5: Register the entity. */
-       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+           vdev->vfl_type != VFL_TYPE_SUBDEV) {
                vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
                vdev->entity.name = vdev->name;
                vdev->entity.v4l.major = VIDEO_MAJOR;
@@ -733,7 +737,8 @@ void video_unregister_device(struct video_device *vdev)
                return;
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+           vdev->vfl_type != VFL_TYPE_SUBDEV)
                media_device_unregister_entity(&vdev->entity);
 #endif
 
index c4742fc15529a97cf4472dde06717f9ef7d31233..c9691115f2d26787fa9d85ae98382539d78a8a98 100644 (file)
@@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        retval = remap_pfn_range(vma, vma->vm_start,
-                                PFN_DOWN(virt_to_phys(mem->vaddr)),
+                                mem->dma_handle >> PAGE_SHIFT,
                                 size, vma->vm_page_prot);
        if (retval) {
                dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
index 6698c77e0f64c7f5667c1bb8556597f77675483b..6ba1461d51ef9456be18be6421837c0c279064b8 100644 (file)
@@ -37,6 +37,9 @@ module_param(debug, int, 0644);
 #define call_qop(q, op, args...)                                       \
        (((q)->ops->op) ? ((q)->ops->op(args)) : 0)
 
+#define V4L2_BUFFER_STATE_FLAGS        (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
+                                V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR)
+
 /**
  * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
  */
@@ -51,7 +54,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
        for (plane = 0; plane < vb->num_planes; ++plane) {
                mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
                                        plane_sizes[plane]);
-               if (!mem_priv)
+               if (IS_ERR_OR_NULL(mem_priv))
                        goto free;
 
                /* Associate allocator private data with this plane */
@@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
        struct vb2_queue *q = vb->vb2_queue;
        int ret = 0;
 
-       /* Copy back data such as timestamp, input, etc. */
+       /* Copy back data such as timestamp, flags, input, etc. */
        memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
        b->input = vb->v4l2_buf.input;
        b->reserved = vb->v4l2_buf.reserved;
@@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
                        b->m.userptr = vb->v4l2_planes[0].m.userptr;
        }
 
-       b->flags = 0;
+       /*
+        * Clear any buffer state related flags.
+        */
+       b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
 
        switch (vb->state) {
        case VB2_BUF_STATE_QUEUED:
@@ -519,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
        num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
        memset(plane_sizes, 0, sizeof(plane_sizes));
        memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
+       q->memory = req->memory;
 
        /*
         * Ask the driver how many buffers and planes per buffer it requires.
@@ -560,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                ret = num_buffers;
        }
 
-       q->memory = req->memory;
-
        /*
         * Return the number of successfully allocated buffers
         * to the userspace.
@@ -715,6 +720,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
 
        vb->v4l2_buf.field = b->field;
        vb->v4l2_buf.timestamp = b->timestamp;
+       vb->v4l2_buf.input = b->input;
+       vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
 
        return 0;
 }
index 58205d5961386cec699b9c680087619e603f0084..a790a5f8c06ff5e48566bfeb41a512975fc26d4f 100644 (file)
@@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
                                        GFP_KERNEL);
        if (!buf->vaddr) {
                dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
-                       buf->size);
+                       size);
                kfree(buf);
                return ERR_PTR(-ENOMEM);
        }
index d01574d98870a0473b56be995cd0341786b9b767..f4c8c844b913060c6e0bb12f35db8cba983a81dc 100644 (file)
@@ -55,6 +55,19 @@ int mfd_cell_disable(struct platform_device *pdev)
 }
 EXPORT_SYMBOL(mfd_cell_disable);
 
+static int mfd_platform_add_cell(struct platform_device *pdev,
+                                const struct mfd_cell *cell)
+{
+       if (!cell)
+               return 0;
+
+       pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL);
+       if (!pdev->mfd_cell)
+               return -ENOMEM;
+
+       return 0;
+}
+
 static int mfd_add_device(struct device *parent, int id,
                          const struct mfd_cell *cell,
                          struct resource *mem_base,
@@ -75,7 +88,7 @@ static int mfd_add_device(struct device *parent, int id,
 
        pdev->dev.parent = parent;
 
-       ret = platform_device_add_data(pdev, cell, sizeof(*cell));
+       ret = mfd_platform_add_cell(pdev, cell);
        if (ret)
                goto fail_res;
 
@@ -123,7 +136,6 @@ static int mfd_add_device(struct device *parent, int id,
 
        return 0;
 
-/*     platform_device_del(pdev); */
 fail_res:
        kfree(res);
 fail_device:
index 53450f433f1018dbf042b2dbf1ccaa490f802b60..2e165117457b482ad3e679d48ff9d203a69cd6f8 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
 #include <plat/usb.h>
 
 #define USBHS_DRIVER_NAME      "usbhs-omap"
@@ -700,8 +699,7 @@ static int usbhs_enable(struct device *dev)
        dev_dbg(dev, "starting TI HSUSB Controller\n");
        if (!pdata) {
                dev_dbg(dev, "missing platform_data\n");
-               ret =  -ENODEV;
-               goto end_enable;
+               return  -ENODEV;
        }
 
        spin_lock_irqsave(&omap->lock, flags);
@@ -915,7 +913,8 @@ static int usbhs_enable(struct device *dev)
 
 end_count:
        omap->count++;
-       goto end_enable;
+       spin_unlock_irqrestore(&omap->lock, flags);
+       return 0;
 
 err_tll:
        if (pdata->ehci_data->phy_reset) {
@@ -931,8 +930,6 @@ err_tll:
        clk_disable(omap->usbhost_fs_fck);
        clk_disable(omap->usbhost_hs_fck);
        clk_disable(omap->usbhost_ick);
-
-end_enable:
        spin_unlock_irqrestore(&omap->lock, flags);
        return ret;
 }
index 20e4e9395b61ca1c6d85b09511b88f535a8ec120..ecafa4ba238b3ca4991a20dc5e6bb88458aee8de 100644 (file)
@@ -348,15 +348,15 @@ static unsigned long gru_chiplet_cpu_to_mmr(int chiplet, int cpu, int *corep)
 
 static int gru_irq_count[GRU_CHIPLETS_PER_BLADE];
 
-static void gru_noop(unsigned int irq)
+static void gru_noop(struct irq_data *d)
 {
 }
 
 static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = {
        [0 ... GRU_CHIPLETS_PER_BLADE - 1] {
-               .mask           = gru_noop,
-               .unmask         = gru_noop,
-               .ack            = gru_noop
+               .irq_mask       = gru_noop,
+               .irq_unmask     = gru_noop,
+               .irq_ack        = gru_noop
        }
 };
 
index 63667a8f140c458722c54b33b3e91d54e4cca029..d6d62fd07ee9fd0b492d6c7e0a80d116840009b2 100644 (file)
@@ -284,6 +284,7 @@ int mmc_add_card(struct mmc_card *card)
                type = "SD-combo";
                if (mmc_card_blockaddr(card))
                        type = "SDHC-combo";
+               break;
        default:
                type = "?";
                break;
index 461e6a17fb90e8526d96054f2ec90f44a85e70c3..2b200c1cfbba151a3348706d6a61668280119b0a 100644 (file)
@@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
                spin_unlock_irqrestore(&host->clk_lock, flags);
                return;
        }
-       mutex_lock(&host->clk_gate_mutex);
+       mmc_claim_host(host);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (!host->clk_requests) {
                spin_unlock_irqrestore(&host->clk_lock, flags);
@@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
                pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
        }
        spin_unlock_irqrestore(&host->clk_lock, flags);
-       mutex_unlock(&host->clk_gate_mutex);
+       mmc_release_host(host);
 }
 
 /*
@@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host)
 {
        unsigned long flags;
 
-       mutex_lock(&host->clk_gate_mutex);
+       mmc_claim_host(host);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (host->clk_gated) {
                spin_unlock_irqrestore(&host->clk_lock, flags);
@@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host)
        }
        host->clk_requests++;
        spin_unlock_irqrestore(&host->clk_lock, flags);
-       mutex_unlock(&host->clk_gate_mutex);
+       mmc_release_host(host);
 }
 
 /**
@@ -215,7 +215,6 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
        host->clk_gated = false;
        INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
        spin_lock_init(&host->clk_lock);
-       mutex_init(&host->clk_gate_mutex);
 }
 
 /**
index 2e032f0e8cf47e45730d99e8f9554c688eb756b1..a6c329040140420ab73ded04fa08c7ca9cdaa07e 100644 (file)
@@ -832,7 +832,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
                return IRQ_HANDLED;
        }
 
-       if (end_command)
+       if (end_command && host->cmd)
                mmc_omap_cmd_done(host, host->cmd);
        if (host->data != NULL) {
                if (transfer_error)
index a136be7063478bc9f9f6b130cc92010c47737fc5..f8b5f37007b2a0b8115e62032664e6d96a04e214 100644 (file)
@@ -957,6 +957,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        host->ioaddr = pci_ioremap_bar(pdev, bar);
        if (!host->ioaddr) {
                dev_err(&pdev->dev, "failed to remap registers\n");
+               ret = -ENOMEM;
                goto release;
        }
 
index 9e15f41f87be8f4a79bd61b94ace660942512eb6..5d20661bc357ba387601b6b2089185bceb144aac 100644 (file)
@@ -1334,6 +1334,13 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        host = (struct sdhci_host*)param;
 
+        /*
+         * If this tasklet gets rescheduled while running, it will
+         * be run again afterwards but without any active request.
+         */
+       if (!host->mrq)
+               return;
+
        spin_lock_irqsave(&host->lock, flags);
 
        del_timer(&host->timer);
@@ -1345,7 +1352,7 @@ static void sdhci_tasklet_finish(unsigned long param)
         * upon error conditions.
         */
        if (!(host->flags & SDHCI_DEVICE_DEAD) &&
-               (mrq->cmd->error ||
+           ((mrq->cmd && mrq->cmd->error) ||
                 (mrq->data && (mrq->data->error ||
                  (mrq->data->stop && mrq->data->stop->error))) ||
                   (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
index 62d37de6de76d7551d575f22df39909479030aec..710339a85c84676d9c72e2105f24108344248da2 100644 (file)
@@ -728,15 +728,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                tmio_mmc_set_clock(host, ios->clock);
 
        /* Power sequence - OFF -> UP -> ON */
-       if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
+       if (ios->power_mode == MMC_POWER_UP) {
+               /* power up SD bus */
+               if (host->set_pwr)
+                       host->set_pwr(host->pdev, 1);
+       } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* power down SD bus */
                if (ios->power_mode == MMC_POWER_OFF && host->set_pwr)
                        host->set_pwr(host->pdev, 0);
                tmio_mmc_clk_stop(host);
-       } else if (ios->power_mode == MMC_POWER_UP) {
-               /* power up SD bus */
-               if (host->set_pwr)
-                       host->set_pwr(host->pdev, 1);
        } else {
                /* start bus clock */
                tmio_mmc_clk_start(host);
index 96c0b34ba8dbcfb18b564cabf3c22f3bc74f5a19..657b9f4b6f9ba288ad4dbd5f7f1450e440e84360 100644 (file)
@@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
        doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
        doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 
-       /* We can't' use dev_ready here, but at least we wait for the
+       /* We can't use dev_ready here, but at least we wait for the
         * command to complete
         */
        udelay(50);
index 88495c48a81d3fef21340997537e5ed4f460ec2e..241b185e6569da605eea3fcdd089098b42262a6e 100644 (file)
@@ -106,7 +106,7 @@ MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "M
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
 module_param_array(speed_duplex, int, NULL, 0);
-MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
+MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
 module_param_array(coalesce, bool, NULL, 0);
 MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable");
 module_param_array(dynamic_ipg, bool, NULL, 0);
index 7cb375e0e29cd5e3219a86106f2288201cf20635..925929d764ca50eff2812842c611e0cfbdb3005a 100644 (file)
@@ -566,9 +566,9 @@ struct atl1c_adapter {
 #define __AT_TESTING        0x0001
 #define __AT_RESETTING      0x0002
 #define __AT_DOWN           0x0003
-       u8 work_event;
-#define ATL1C_WORK_EVENT_RESET                 0x01
-#define ATL1C_WORK_EVENT_LINK_CHANGE   0x02
+       unsigned long work_event;
+#define        ATL1C_WORK_EVENT_RESET          0
+#define        ATL1C_WORK_EVENT_LINK_CHANGE    1
        u32 msg_enable;
 
        bool have_msi;
index 7d9d5067a65ce1bb368bd2128d75c5ef87446828..a6e1c36e48e6812b7590a0e2e595abb956b417ab 100644 (file)
@@ -325,7 +325,7 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
                }
        }
 
-       adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE;
+       set_bit(ATL1C_WORK_EVENT_LINK_CHANGE, &adapter->work_event);
        schedule_work(&adapter->common_task);
 }
 
@@ -337,20 +337,16 @@ static void atl1c_common_task(struct work_struct *work)
        adapter = container_of(work, struct atl1c_adapter, common_task);
        netdev = adapter->netdev;
 
-       if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
-               adapter->work_event &= ~ATL1C_WORK_EVENT_RESET;
+       if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) {
                netif_device_detach(netdev);
                atl1c_down(adapter);
                atl1c_up(adapter);
                netif_device_attach(netdev);
-               return;
        }
 
-       if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) {
-               adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE;
+       if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE,
+               &adapter->work_event))
                atl1c_check_link_status(adapter);
-       }
-       return;
 }
 
 
@@ -369,7 +365,7 @@ static void atl1c_tx_timeout(struct net_device *netdev)
        struct atl1c_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
-       adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+       set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event);
        schedule_work(&adapter->common_task);
 }
 
index 7cb5a114c7338af0c584607c7bcd1e33dba4c0e2..02a0443d1821d56f5c4ed61d713b2b186f6dc62e 100644 (file)
@@ -1873,6 +1873,7 @@ static void be_worker(struct work_struct *work)
                be_detect_dump_ue(adapter);
 
 reschedule:
+       adapter->work_counter++;
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
 }
 
index e3de0b8625cde247ee69f5fd45f06c32cfda53a2..7581518ecfa2eade4c4bb4cba60601e5f39b7be2 100644 (file)
@@ -38,6 +38,8 @@
 #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
 #define bfa_ioc_notify_fail(__ioc)                     \
                        ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
+#define bfa_ioc_sync_start(__ioc)               \
+                       ((__ioc)->ioc_hwif->ioc_sync_start(__ioc))
 #define bfa_ioc_sync_join(__ioc)                       \
                        ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
 #define bfa_ioc_sync_leave(__ioc)                      \
@@ -602,7 +604,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
        switch (event) {
        case IOCPF_E_SEMLOCKED:
                if (bfa_ioc_firmware_lock(ioc)) {
-                       if (bfa_ioc_sync_complete(ioc)) {
+                       if (bfa_ioc_sync_start(ioc)) {
                                iocpf->retry_count = 0;
                                bfa_ioc_sync_join(ioc);
                                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
@@ -1314,7 +1316,7 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
  * execution context (driver/bios) must match.
  */
 static bool
-bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
+bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env)
 {
        struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
 
@@ -1325,7 +1327,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
        if (fwhdr.signature != drv_fwhdr->signature)
                return false;
 
-       if (fwhdr.exec != drv_fwhdr->exec)
+       if (swab32(fwhdr.param) != boot_env)
                return false;
 
        return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
@@ -1352,9 +1354,12 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
 {
        enum bfi_ioc_state ioc_fwstate;
        bool fwvalid;
+       u32 boot_env;
 
        ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
 
+       boot_env = BFI_BOOT_LOADER_OS;
+
        if (force)
                ioc_fwstate = BFI_IOC_UNINIT;
 
@@ -1362,10 +1367,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
         * check if firmware is valid
         */
        fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
-               false : bfa_ioc_fwver_valid(ioc);
+               false : bfa_ioc_fwver_valid(ioc, boot_env);
 
        if (!fwvalid) {
-               bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+               bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env);
                return;
        }
 
@@ -1396,7 +1401,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
        /**
         * Initialize the h/w for any other states.
         */
-       bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+       bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env);
 }
 
 void
@@ -1506,7 +1511,7 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc)
  */
 static void
 bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
-                   u32 boot_param)
+                   u32 boot_env)
 {
        u32 *fwimg;
        u32 pgnum, pgoff;
@@ -1558,10 +1563,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
        /*
         * Set boot type and boot param at the end.
        */
-       writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start)
+       writel(boot_type, ((ioc->ioc_regs.smem_page_start)
                        + (BFI_BOOT_TYPE_OFF)));
-       writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start)
-                       + (BFI_BOOT_PARAM_OFF)));
+       writel(boot_env, ((ioc->ioc_regs.smem_page_start)
+                       + (BFI_BOOT_LOADER_OFF)));
 }
 
 static void
@@ -1721,7 +1726,7 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc)
  * as the entry vector.
  */
 static void
-bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
+bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env)
 {
        void __iomem *rb;
 
@@ -1734,7 +1739,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
         * Initialize IOC state of all functions on a chip reset.
         */
        rb = ioc->pcidev.pci_bar_kva;
-       if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+       if (boot_type == BFI_BOOT_TYPE_MEMTEST) {
                writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
                writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
        } else {
@@ -1743,7 +1748,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
        }
 
        bfa_ioc_msgflush(ioc);
-       bfa_ioc_download_fw(ioc, boot_type, boot_param);
+       bfa_ioc_download_fw(ioc, boot_type, boot_env);
 
        /**
         * Enable interrupts just before starting LPU
index e4974bc24ef69b3d05229398cc15b4977997226e..bd48abee781f17ed340d18317e07374d2000b8bb 100644 (file)
@@ -194,6 +194,7 @@ struct bfa_ioc_hwif {
                                        bool msix);
        void            (*ioc_notify_fail)      (struct bfa_ioc *ioc);
        void            (*ioc_ownership_reset)  (struct bfa_ioc *ioc);
+       bool            (*ioc_sync_start)       (struct bfa_ioc *ioc);
        void            (*ioc_sync_join)        (struct bfa_ioc *ioc);
        void            (*ioc_sync_leave)       (struct bfa_ioc *ioc);
        void            (*ioc_sync_ack)         (struct bfa_ioc *ioc);
index 469997c4ffd196a4609c58daf83c6112d4fc4995..87aecdf22cf9c29adf4379685d9813bbbebd2cd5 100644 (file)
@@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
 static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
+static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc);
@@ -63,6 +64,7 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
        nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
        nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
        nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+       nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start;
        nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
        nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
        nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
@@ -342,6 +344,32 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
        bfa_nw_ioc_hw_sem_release(ioc);
 }
 
+/**
+ * Synchronized IOC failure processing routines
+ */
+static bool
+bfa_ioc_ct_sync_start(struct bfa_ioc *ioc)
+{
+       u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+       u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+
+       /*
+        * Driver load time.  If the sync required bit for this PCI fn
+        * is set, it is due to an unclean exit by the driver for this
+        * PCI fn in the previous incarnation. Whoever comes here first
+        * should clean it up, no matter which PCI fn.
+        */
+
+       if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) {
+               writel(0, ioc->ioc_regs.ioc_fail_sync);
+               writel(1, ioc->ioc_regs.ioc_usage_reg);
+               writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+               writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
+               return true;
+       }
+
+       return bfa_ioc_ct_sync_complete(ioc);
+}
 /**
  * Synchronized IOC failure processing routines
  */
index a97396811050eaccc1bcd31064c0088c29479413..6050379526f74f737ed2ef8a12c8f44ece1241d5 100644 (file)
@@ -184,12 +184,14 @@ enum bfi_mclass {
 #define BFI_IOC_MSGLEN_MAX     32      /* 32 bytes */
 
 #define BFI_BOOT_TYPE_OFF              8
-#define BFI_BOOT_PARAM_OFF             12
+#define BFI_BOOT_LOADER_OFF            12
 
-#define BFI_BOOT_TYPE_NORMAL           0       /* param is device id */
+#define BFI_BOOT_TYPE_NORMAL           0
 #define        BFI_BOOT_TYPE_FLASH             1
 #define        BFI_BOOT_TYPE_MEMTEST           2
 
+#define BFI_BOOT_LOADER_OS             0
+
 #define BFI_BOOT_MEMTEST_RES_ADDR   0x900
 #define BFI_BOOT_MEMTEST_RES_SIG    0xA0A1A2A3
 
index 9f356d5d0f3318c42630cd0ce2b479e73a28b75b..8e6ceab9f4d800e4cbfee2cac22a297d0d987396 100644 (file)
@@ -1837,7 +1837,6 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
        /* Initialize the Rx event handlers */
        rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
        rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy;
-       rx_cbfn.rcb_destroy_cbfn = NULL;
        rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
        rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
        rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup;
index 8e6d618b53052139981cf5cc6df6720d11382a0c..d8383a9af9ad21a756a090bc1fd7342f3af005ee 100644 (file)
@@ -8413,6 +8413,8 @@ bnx2_remove_one(struct pci_dev *pdev)
 
        unregister_netdev(dev);
 
+       del_timer_sync(&bp->timer);
+
        if (bp->mips_firmware)
                release_firmware(bp->mips_firmware);
        if (bp->rv2p_firmware)
index e83ac6dd6fc076b85b752957b9d7a88985cb0412..16581df5ee4e62936afd0ac74ad50dbd108f5782 100644 (file)
@@ -2019,15 +2019,23 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
 static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
        u32 *parsing_data, u32 xmit_type)
 {
-       *parsing_data |= ((tcp_hdrlen(skb)/4) <<
-               ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
-               ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
+       *parsing_data |=
+                       ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
+                       ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+                       ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
 
-       *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
-               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
-               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
+       if (xmit_type & XMIT_CSUM_TCP) {
+               *parsing_data |= ((tcp_hdrlen(skb) / 4) <<
+                       ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
+                       ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
-       return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
+               return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
+       } else
+               /* We support checksum offload for TCP and UDP only.
+                * No need to pass the UDP header length - it's a constant.
+                */
+               return skb_transport_header(skb) +
+                               sizeof(struct udphdr) - skb->data;
 }
 
 /**
@@ -2043,7 +2051,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
        struct eth_tx_parse_bd_e1x *pbd,
        u32 xmit_type)
 {
-       u8 hlen = (skb_network_header(skb) - skb->data) / 2;
+       u8 hlen = (skb_network_header(skb) - skb->data) >> 1;
 
        /* for now NS flag is not used in Linux */
        pbd->global_data =
@@ -2051,9 +2059,15 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
                         ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
 
        pbd->ip_hlen_w = (skb_transport_header(skb) -
-                       skb_network_header(skb)) / 2;
+                       skb_network_header(skb)) >> 1;
 
-       hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2;
+       hlen += pbd->ip_hlen_w;
+
+       /* We support checksum offload for TCP and UDP only */
+       if (xmit_type & XMIT_CSUM_TCP)
+               hlen += tcp_hdrlen(skb) / 2;
+       else
+               hlen += sizeof(struct udphdr) / 2;
 
        pbd->total_hlen_w = cpu_to_le16(hlen);
        hlen = hlen*2;
index f5050155c6b5e04d87a62be1f8f22a78dc953d9e..89cb977898cb5cfbce98bd53422c9d27128761e5 100644 (file)
@@ -2114,19 +2114,18 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
        for (i = 0; i < (data * 2); i++) {
                if ((i % 2) == 0)
                        bnx2x_set_led(&bp->link_params, &bp->link_vars,
-                                     LED_MODE_OPER, SPEED_1000);
+                                     LED_MODE_ON, SPEED_1000);
                else
                        bnx2x_set_led(&bp->link_params, &bp->link_vars,
-                                     LED_MODE_OFF, 0);
+                                     LED_MODE_FRONT_PANEL_OFF, 0);
 
                msleep_interruptible(500);
                if (signal_pending(current))
                        break;
        }
 
-       if (bp->link_vars.link_up)
-               bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER,
-                             bp->link_vars.line_speed);
+       bnx2x_set_led(&bp->link_params, &bp->link_vars,
+                     LED_MODE_OPER, bp->link_vars.line_speed);
 
        return 0;
 }
index 494bf960442d3ff533507661ce394d0d128a3d6f..31912f17653f74173368e36a03c924a4b1443975 100644 (file)
@@ -1482,8 +1482,11 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
 
 static int agg_device_up(const struct aggregator *agg)
 {
-       return (netif_running(agg->slave->dev) &&
-               netif_carrier_ok(agg->slave->dev));
+       struct port *port = agg->lag_ports;
+       if (!port)
+               return 0;
+       return (netif_running(port->slave->dev) &&
+               netif_carrier_ok(port->slave->dev));
 }
 
 /**
index 9bc5de3e04a8375894e040cd3cb794a0fff5f90c..ba715826e2a8f1c7cf66213f777527d5db053d4c 100644 (file)
@@ -176,7 +176,7 @@ static int tlb_initialize(struct bonding *bond)
        bond_info->tx_hashtbl = new_hashtbl;
 
        for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
-               tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
+               tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
        }
 
        _unlock_tx_hashtbl(bond);
@@ -701,7 +701,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
                 */
                rlb_choose_channel(skb, bond);
 
-               /* The ARP relpy packets must be delayed so that
+               /* The ARP reply packets must be delayed so that
                 * they can cancel out the influence of the ARP request.
                 */
                bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY;
@@ -1042,7 +1042,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
  *
  * If the permanent hw address of @slave is @bond's hw address, we need to
  * find a different hw address to give @slave, that isn't in use by any other
- * slave in the bond. This address must be, of course, one of the premanent
+ * slave in the bond. This address must be, of course, one of the permanent
  * addresses of the other slaves.
  *
  * We go over the slave list, and for each slave there we compare its
index 86861f08b24d1ec91f3b80e8efe4f83999b404a7..8ca7158b2dda412f158ae790050c380e2abd2971 100644 (file)
@@ -75,7 +75,7 @@ struct tlb_client_info {
                                 * gave this entry index.
                                 */
        u32 tx_bytes;           /* Each Client accumulates the BytesTx that
-                                * were tranmitted to it, and after each
+                                * were transmitted to it, and after each
                                 * CallBack the LoadHistory is divided
                                 * by the balance interval
                                 */
@@ -122,7 +122,6 @@ struct tlb_slave_info {
 };
 
 struct alb_bond_info {
-       struct timer_list       alb_timer;
        struct tlb_client_info  *tx_hashtbl; /* Dynamically allocated */
        spinlock_t              tx_hashtbl_lock;
        u32                     unbalanced_load;
@@ -140,7 +139,6 @@ struct alb_bond_info {
        struct slave            *next_rx_slave;/* next slave to be assigned
                                                * to a new rx client for
                                                */
-       u32                     rlb_interval_counter;
        u8                      primary_is_promisc;        /* boolean */
        u32                     rlb_promisc_timeout_counter;/* counts primary
                                                             * promiscuity time
index c0a1bc5b14352288d5c73238031547e4afd9ee98..bd1d811c204f276cbf2aa74f07035cd8ae0875ef 100644 (file)
@@ -260,7 +260,7 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
 
        if (!ofdev->dev.of_match)
                return -EINVAL;
-       data = (struct mpc5xxx_can_data *)of_dev->dev.of_match->data;
+       data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data;
 
        base = of_iomap(np, 0);
        if (!base) {
index f75d3144b8a508e9668c48be6592eff49fbb7e3f..53c0f04b1b2322ccee9c53e19e71f5321e81cb8a 100644 (file)
@@ -3040,11 +3040,14 @@ static void ehea_rereg_mrs(void)
 
                                        if (dev->flags & IFF_UP) {
                                                mutex_lock(&port->port_lock);
-                                               port_napi_enable(port);
                                                ret = ehea_restart_qps(dev);
-                                               check_sqs(port);
-                                               if (!ret)
+                                               if (!ret) {
+                                                       check_sqs(port);
+                                                       port_napi_enable(port);
                                                        netif_wake_queue(dev);
+                                               } else {
+                                                       netdev_err(dev, "Unable to restart QPS\n");
+                                               }
                                                mutex_unlock(&port->port_lock);
                                        }
                                }
index 61035fc5599b1bd552bf05e1a77289bd24bee53f..b9fbc83d64a7faa09acfdc2537427bda5f4c6f14 100644 (file)
@@ -226,8 +226,8 @@ static void set_multicast_finish(struct net_device *dev)
        }
 
        FC(fecp, r_cntrl, FEC_RCNTRL_PROM);
-       FW(fecp, hash_table_high, fep->fec.hthi);
-       FW(fecp, hash_table_low, fep->fec.htlo);
+       FW(fecp, grp_hash_table_high, fep->fec.hthi);
+       FW(fecp, grp_hash_table_low, fep->fec.htlo);
 }
 
 static void set_multicast_list(struct net_device *dev)
@@ -273,8 +273,8 @@ static void restart(struct net_device *dev)
        /*
         * Reset all multicast.
         */
-       FW(fecp, hash_table_high, fep->fec.hthi);
-       FW(fecp, hash_table_low, fep->fec.htlo);
+       FW(fecp, grp_hash_table_high, fep->fec.hthi);
+       FW(fecp, grp_hash_table_low, fep->fec.htlo);
 
        /*
         * Set maximum receive buffer size.
index a31661948c420e0d467c7e8b7bb4ecae4c078de0..9bd7746cbfcfd1fc6b294cbdb2f499e7f21d5e96 100644 (file)
@@ -139,11 +139,11 @@ static int ftmac100_reset(struct ftmac100 *priv)
                         * that hardware reset completed (what the f*ck).
                         * We still need to wait for a while.
                         */
-                       usleep_range(500, 1000);
+                       udelay(500);
                        return 0;
                }
 
-               usleep_range(1000, 10000);
+               udelay(1000);
        }
 
        netdev_err(netdev, "software reset failed\n");
@@ -772,7 +772,7 @@ static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
                if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
                        return phycr & FTMAC100_PHYCR_MIIRDATA;
 
-               usleep_range(100, 1000);
+               udelay(100);
        }
 
        netdev_err(netdev, "mdio read timed out\n");
@@ -801,7 +801,7 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
                if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
                        return;
 
-               usleep_range(100, 1000);
+               udelay(100);
        }
 
        netdev_err(netdev, "mdio write timed out\n");
index ea0dc451da9c874716c689a051cb967082c8bf6b..d70fb76edb7717062544a3c87d27e5799d0348c9 100644 (file)
@@ -173,7 +173,8 @@ static void loopback_setup(struct net_device *dev)
                | NETIF_F_RXCSUM
                | NETIF_F_HIGHDMA
                | NETIF_F_LLTX
-               | NETIF_F_NETNS_LOCAL;
+               | NETIF_F_NETNS_LOCAL
+               | NETIF_F_VLAN_CHALLENGED;
        dev->ethtool_ops        = &loopback_ethtool_ops;
        dev->header_ops         = &eth_header_ops;
        dev->netdev_ops         = &loopback_ops;
index 0a6c6a2e7550f17235827811be88140ba891a0f6..d4fc00b1ff93442f699844517736a0ac1b6a0bde 100644 (file)
@@ -49,6 +49,10 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
                result |= ADVERTISED_100baseT_Half;
        if (advert & ADVERTISE_100FULL)
                result |= ADVERTISED_100baseT_Full;
+       if (advert & ADVERTISE_PAUSE_CAP)
+               result |= ADVERTISED_Pause;
+       if (advert & ADVERTISE_PAUSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
 
        return result;
 }
index aa2813e06d0033ebcc48f07967c884d9b20735d8..1074231f0a0d722a803bcc968372d9705b582a53 100644 (file)
@@ -860,6 +860,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
                prev_eedata = eedata;
        }
 
+       /* Store MAC Address in perm_addr */
+       memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
        dev->base_addr = (unsigned long __force) ioaddr;
        dev->irq = irq;
 
index dfb67eb2a94b726cb590f8b3a015d98a719866d1..eb41e44921e665c3863dd82860b7c44413c7ef5e 100644 (file)
@@ -671,6 +671,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
                goto done;
 
        spin_lock_irqsave(&target_list_lock, flags);
+restart:
        list_for_each_entry(nt, &target_list, list) {
                netconsole_target_get(nt);
                if (nt->np.dev == dev) {
@@ -683,9 +684,16 @@ static int netconsole_netdev_event(struct notifier_block *this,
                                 * rtnl_lock already held
                                 */
                                if (nt->np.dev) {
+                                       spin_unlock_irqrestore(
+                                                             &target_list_lock,
+                                                             flags);
                                        __netpoll_cleanup(&nt->np);
+                                       spin_lock_irqsave(&target_list_lock,
+                                                         flags);
                                        dev_put(nt->np.dev);
                                        nt->np.dev = NULL;
+                                       netconsole_target_put(nt);
+                                       goto restart;
                                }
                                /* Fall through */
                        case NETDEV_GOING_DOWN:
index d7299f1a49401dc57d84610696008e63b90efe98..679dc8519c5b6db3c5916f81197b7413b66c44cc 100644 (file)
 
 #define        MAX_NUM_CARDS           4
 
-#define MAX_BUFFERS_PER_CMD    32
+#define NETXEN_MAX_FRAGS_PER_TX        14
 #define MAX_TSO_HEADER_DESC    2
 #define MGMT_CMD_DESC_RESV     4
 #define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
@@ -558,7 +558,7 @@ struct netxen_recv_crb {
  */
 struct netxen_cmd_buffer {
        struct sk_buff *skb;
-       struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
+       struct netxen_skb_frag frag_array[MAX_SKB_FRAGS + 1];
        u32 frag_count;
 };
 
index 83348dc4b184c5f8afbafc892b0c91dccd0dce13..e8a4b66559999b2fef6e375fb568abfa8f663786 100644 (file)
@@ -1844,6 +1844,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct cmd_desc_type0 *hwdesc, *first_desc;
        struct pci_dev *pdev;
        int i, k;
+       int delta = 0;
+       struct skb_frag_struct *frag;
 
        u32 producer;
        int frag_count, no_of_desc;
@@ -1851,6 +1853,21 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        frag_count = skb_shinfo(skb)->nr_frags + 1;
 
+       /* 14 frags supported for normal packet and
+        * 32 frags supported for TSO packet
+        */
+       if (!skb_is_gso(skb) && frag_count > NETXEN_MAX_FRAGS_PER_TX) {
+
+               for (i = 0; i < (frag_count - NETXEN_MAX_FRAGS_PER_TX); i++) {
+                       frag = &skb_shinfo(skb)->frags[i];
+                       delta += frag->size;
+               }
+
+               if (!__pskb_pull_tail(skb, delta))
+                       goto drop_packet;
+
+               frag_count = 1 + skb_shinfo(skb)->nr_frags;
+       }
        /* 4 fragments per cmd des */
        no_of_desc = (frag_count + 3) >> 2;
 
index dc44564ef6f9984fdc9a214491d9bdced015eb80..b0dead00b2d1d6b7809bd2b01906b5bff5a786b5 100644 (file)
@@ -99,6 +99,7 @@
 #define TX_UDPV6_PKT   0x0c
 
 /* Tx defines */
+#define QLCNIC_MAX_FRAGS_PER_TX        14
 #define MAX_TSO_HEADER_DESC    2
 #define MGMT_CMD_DESC_RESV     4
 #define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
index cd88c7e1bfa9c76c3ae156da021a020f27346be5..cb1a1ef36c0ade56ddb5dfb98c2ef2ce8813b100 100644 (file)
@@ -2099,6 +2099,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct cmd_desc_type0 *hwdesc, *first_desc;
        struct pci_dev *pdev;
        struct ethhdr *phdr;
+       int delta = 0;
        int i, k;
 
        u32 producer;
@@ -2118,6 +2119,19 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        frag_count = skb_shinfo(skb)->nr_frags + 1;
+       /* 14 frags supported for normal packet and
+        * 32 frags supported for TSO packet
+        */
+       if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
+
+               for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
+                       delta += skb_shinfo(skb)->frags[i].size;
+
+               if (!__pskb_pull_tail(skb, delta))
+                       goto drop_packet;
+
+               frag_count = 1 + skb_shinfo(skb)->nr_frags;
+       }
 
        /* 4 fragments per cmd des */
        no_of_desc = (frag_count + 3) >> 2;
index 493b0de3848bf17fadd6741ad57d5b4701b2f074..397c36810a159ad7dfc143a819303e059008fe56 100644 (file)
@@ -170,6 +170,16 @@ static const struct {
 };
 #undef _R
 
+static const struct rtl_firmware_info {
+       int mac_version;
+       const char *fw_name;
+} rtl_firmware_infos[] = {
+       { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 },
+       { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 },
+       { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 },
+       { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 }
+};
+
 enum cfg_version {
        RTL_CFG_0 = 0x00,
        RTL_CFG_1,
@@ -565,6 +575,7 @@ struct rtl8169_private {
        u32 saved_wolopts;
 
        const struct firmware *fw;
+#define RTL_FIRMWARE_UNKNOWN   ERR_PTR(-EAGAIN);
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -1789,25 +1800,26 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
 
 static void rtl_release_firmware(struct rtl8169_private *tp)
 {
-       release_firmware(tp->fw);
-       tp->fw = NULL;
+       if (!IS_ERR_OR_NULL(tp->fw))
+               release_firmware(tp->fw);
+       tp->fw = RTL_FIRMWARE_UNKNOWN;
 }
 
-static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name)
+static void rtl_apply_firmware(struct rtl8169_private *tp)
 {
-       const struct firmware **fw = &tp->fw;
-       int rc = !*fw;
-
-       if (rc) {
-               rc = request_firmware(fw, fw_name, &tp->pci_dev->dev);
-               if (rc < 0)
-                       goto out;
-       }
+       const struct firmware *fw = tp->fw;
 
        /* TODO: release firmware once rtl_phy_write_fw signals failures. */
-       rtl_phy_write_fw(tp, *fw);
-out:
-       return rc;
+       if (!IS_ERR_OR_NULL(fw))
+               rtl_phy_write_fw(tp, fw);
+}
+
+static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
+{
+       if (rtl_readphy(tp, reg) != val)
+               netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
+       else
+               rtl_apply_firmware(tp);
 }
 
 static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
@@ -2246,10 +2258,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if ((rtl_readphy(tp, 0x06) != 0xbf00) ||
-           (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) {
-               netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
-       }
+
+       rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
 
        rtl_writephy(tp, 0x1f, 0x0000);
 }
@@ -2351,10 +2361,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if ((rtl_readphy(tp, 0x06) != 0xb300) ||
-           (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) {
-               netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
-       }
+
+       rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
 
        rtl_writephy(tp, 0x1f, 0x0000);
 }
@@ -2474,8 +2482,7 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
        rtl_writephy(tp, 0x18, 0x0310);
        msleep(100);
 
-       if (rtl_apply_firmware(tp, FIRMWARE_8105E_1) < 0)
-               netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
+       rtl_apply_firmware(tp);
 
        rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 }
@@ -3237,6 +3244,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->timer.data = (unsigned long) dev;
        tp->timer.function = rtl8169_phy_timer;
 
+       tp->fw = RTL_FIRMWARE_UNKNOWN;
+
        rc = register_netdev(dev);
        if (rc < 0)
                goto err_out_msi_4;
@@ -3288,10 +3297,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 
        cancel_delayed_work_sync(&tp->task);
 
-       rtl_release_firmware(tp);
-
        unregister_netdev(dev);
 
+       rtl_release_firmware(tp);
+
        if (pci_dev_run_wake(pdev))
                pm_runtime_get_noresume(&pdev->dev);
 
@@ -3303,6 +3312,37 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
 }
 
+static void rtl_request_firmware(struct rtl8169_private *tp)
+{
+       int i;
+
+       /* Return early if the firmware is already loaded / cached. */
+       if (!IS_ERR(tp->fw))
+               goto out;
+
+       for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) {
+               const struct rtl_firmware_info *info = rtl_firmware_infos + i;
+
+               if (info->mac_version == tp->mac_version) {
+                       const char *name = info->fw_name;
+                       int rc;
+
+                       rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev);
+                       if (rc < 0) {
+                               netif_warn(tp, ifup, tp->dev, "unable to load "
+                                       "firmware patch %s (%d)\n", name, rc);
+                               goto out_disable_request_firmware;
+                       }
+                       goto out;
+               }
+       }
+
+out_disable_request_firmware:
+       tp->fw = NULL;
+out:
+       return;
+}
+
 static int rtl8169_open(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -3334,11 +3374,13 @@ static int rtl8169_open(struct net_device *dev)
 
        smp_mb();
 
+       rtl_request_firmware(tp);
+
        retval = request_irq(dev->irq, rtl8169_interrupt,
                             (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
                             dev->name, dev);
        if (retval < 0)
-               goto err_release_ring_2;
+               goto err_release_fw_2;
 
        napi_enable(&tp->napi);
 
@@ -3359,7 +3401,8 @@ static int rtl8169_open(struct net_device *dev)
 out:
        return retval;
 
-err_release_ring_2:
+err_release_fw_2:
+       rtl_release_firmware(tp);
        rtl8169_rx_clear(tp);
 err_free_rx_1:
        dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
index d890679e4c4d293538b0e8d98cb1f34466e23947..a3c2aab53de8d29407e11386e51c7fefcd00c402 100644 (file)
@@ -328,7 +328,8 @@ static int efx_poll(struct napi_struct *napi, int budget)
  * processing to finish, then directly poll (and ack ) the eventq.
  * Finally reenable NAPI and interrupts.
  *
- * Since we are touching interrupts the caller should hold the suspend lock
+ * This is for use only during a loopback self-test.  It must not
+ * deliver any packets up the stack as this can result in deadlock.
  */
 void efx_process_channel_now(struct efx_channel *channel)
 {
@@ -336,6 +337,7 @@ void efx_process_channel_now(struct efx_channel *channel)
 
        BUG_ON(channel->channel >= efx->n_channels);
        BUG_ON(!channel->enabled);
+       BUG_ON(!efx->loopback_selftest);
 
        /* Disable interrupts and wait for ISRs to complete */
        efx_nic_disable_interrupts(efx);
@@ -1436,7 +1438,7 @@ static void efx_start_all(struct efx_nic *efx)
         * restart the transmit interface early so the watchdog timer stops */
        efx_start_port(efx);
 
-       if (efx_dev_registered(efx))
+       if (efx_dev_registered(efx) && !efx->port_inhibited)
                netif_tx_wake_all_queues(efx->net_dev);
 
        efx_for_each_channel(channel, efx)
index d9d8c2ef1074a3de6278eff70d7894cc8cc65991..cc978803d484bf84510ca5beb24ca41dd83a93ba 100644 (file)
@@ -152,6 +152,7 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
 
        spin_lock_irqsave(&efx->biu_lock, flags);
        value->u32[0] = _efx_readd(efx, reg + 0);
+       rmb();
        value->u32[1] = _efx_readd(efx, reg + 4);
        value->u32[2] = _efx_readd(efx, reg + 8);
        value->u32[3] = _efx_readd(efx, reg + 12);
@@ -174,6 +175,7 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
        value->u64[0] = (__force __le64)__raw_readq(membase + addr);
 #else
        value->u32[0] = (__force __le32)__raw_readl(membase + addr);
+       rmb();
        value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
 #endif
        spin_unlock_irqrestore(&efx->biu_lock, flags);
index 9ffa9a6b55a0b3cf76009bf146b7eee0c74a3750..191a311da2dc77b4bfa65bcb927148cf791a54a0 100644 (file)
@@ -330,7 +330,6 @@ enum efx_rx_alloc_method {
  * @eventq_mask: Event queue pointer mask
  * @eventq_read_ptr: Event queue read pointer
  * @last_eventq_read_ptr: Last event queue read pointer value.
- * @magic_count: Event queue test event count
  * @irq_count: Number of IRQs since last adaptive moderation decision
  * @irq_mod_score: IRQ moderation score
  * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
@@ -360,7 +359,6 @@ struct efx_channel {
        unsigned int eventq_mask;
        unsigned int eventq_read_ptr;
        unsigned int last_eventq_read_ptr;
-       unsigned int magic_count;
 
        unsigned int irq_count;
        unsigned int irq_mod_score;
index e8396614daf38b4e7d7c923a65d2bb109f066d98..10f1cb79c1472cfb91f9a50f16f827248bd00c96 100644 (file)
@@ -84,7 +84,8 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
 static inline efx_qword_t *efx_event(struct efx_channel *channel,
                                     unsigned int index)
 {
-       return ((efx_qword_t *) (channel->eventq.addr)) + index;
+       return ((efx_qword_t *) (channel->eventq.addr)) +
+               (index & channel->eventq_mask);
 }
 
 /* See if an event is present
@@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
        efx_dword_t reg;
        struct efx_nic *efx = channel->efx;
 
-       EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr);
+       EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR,
+                            channel->eventq_read_ptr & channel->eventq_mask);
        efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base,
                         channel->channel);
 }
@@ -908,7 +910,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
 
        code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
        if (code == EFX_CHANNEL_MAGIC_TEST(channel))
-               ++channel->magic_count;
+               ; /* ignore */
        else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
                /* The queue must be empty, so we won't receive any rx
                 * events, so efx_process_channel() won't refill the
@@ -1015,8 +1017,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
                /* Clear this event by marking it all ones */
                EFX_SET_QWORD(*p_event);
 
-               /* Increment read pointer */
-               read_ptr = (read_ptr + 1) & channel->eventq_mask;
+               ++read_ptr;
 
                ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE);
 
@@ -1060,6 +1061,13 @@ out:
        return spent;
 }
 
+/* Check whether an event is present in the eventq at the current
+ * read pointer.  Only useful for self-test.
+ */
+bool efx_nic_event_present(struct efx_channel *channel)
+{
+       return efx_event_present(efx_event(channel, channel->eventq_read_ptr));
+}
 
 /* Allocate buffer table entries for event queue */
 int efx_nic_probe_eventq(struct efx_channel *channel)
@@ -1165,7 +1173,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
        unsigned int read_ptr = channel->eventq_read_ptr;
-       unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask;
+       unsigned int end_ptr = read_ptr + channel->eventq_mask - 1;
 
        do {
                efx_qword_t *event = efx_event(channel, read_ptr);
@@ -1205,7 +1213,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
                 * it's ok to throw away every non-flush event */
                EFX_SET_QWORD(*event);
 
-               read_ptr = (read_ptr + 1) & channel->eventq_mask;
+               ++read_ptr;
        } while (read_ptr != end_ptr);
 
        channel->eventq_read_ptr = read_ptr;
index d9de1b647d416b601f62cb1e6a1a6f56f09a4830..a42db6e35be39166d86f72887def5619c581dc58 100644 (file)
@@ -184,6 +184,7 @@ extern void efx_nic_fini_eventq(struct efx_channel *channel);
 extern void efx_nic_remove_eventq(struct efx_channel *channel);
 extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota);
 extern void efx_nic_eventq_read_ack(struct efx_channel *channel);
+extern bool efx_nic_event_present(struct efx_channel *channel);
 
 /* MAC/PHY */
 extern void falcon_drain_tx_fifo(struct efx_nic *efx);
index a0f49b348d62872be7512019083badfc50ab9db8..50ad3bcaf68a243ec41d78d72e1cd358c0455e59 100644 (file)
@@ -131,8 +131,6 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
 static int efx_test_interrupts(struct efx_nic *efx,
                               struct efx_self_tests *tests)
 {
-       struct efx_channel *channel;
-
        netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n");
        tests->interrupt = -1;
 
@@ -140,15 +138,6 @@ static int efx_test_interrupts(struct efx_nic *efx,
        efx->last_irq_cpu = -1;
        smp_wmb();
 
-       /* ACK each interrupting event queue. Receiving an interrupt due to
-        * traffic before a test event is raised is considered a pass */
-       efx_for_each_channel(channel, efx) {
-               if (channel->work_pending)
-                       efx_process_channel_now(channel);
-               if (efx->last_irq_cpu >= 0)
-                       goto success;
-       }
-
        efx_nic_generate_interrupt(efx);
 
        /* Wait for arrival of test interrupt. */
@@ -173,13 +162,13 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
                               struct efx_self_tests *tests)
 {
        struct efx_nic *efx = channel->efx;
-       unsigned int magic_count, count;
+       unsigned int read_ptr, count;
 
        tests->eventq_dma[channel->channel] = -1;
        tests->eventq_int[channel->channel] = -1;
        tests->eventq_poll[channel->channel] = -1;
 
-       magic_count = channel->magic_count;
+       read_ptr = channel->eventq_read_ptr;
        channel->efx->last_irq_cpu = -1;
        smp_wmb();
 
@@ -190,10 +179,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
        do {
                schedule_timeout_uninterruptible(HZ / 100);
 
-               if (channel->work_pending)
-                       efx_process_channel_now(channel);
-
-               if (channel->magic_count != magic_count)
+               if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr)
                        goto eventq_ok;
        } while (++count < 2);
 
@@ -211,8 +197,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
        }
 
        /* Check to see if event was received even if interrupt wasn't */
-       efx_process_channel_now(channel);
-       if (channel->magic_count != magic_count) {
+       if (efx_nic_event_present(channel)) {
                netif_err(efx, drv, efx->net_dev,
                          "channel %d event was generated, but "
                          "failed to trigger an interrupt\n", channel->channel);
@@ -770,6 +755,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        __efx_reconfigure_port(efx);
        mutex_unlock(&efx->mac_lock);
 
+       netif_tx_wake_all_queues(efx->net_dev);
+
        return rc_test;
 }
 
index 13980190821762aa47a31729b688e5b36001ef77..d2c85dfdf3bf3a338349dbe21a5547d99cd6c98a 100644 (file)
@@ -435,7 +435,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
         * queue state. */
        smp_mb();
        if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) &&
-           likely(efx->port_enabled)) {
+           likely(efx->port_enabled) &&
+           likely(!efx->port_inhibited)) {
                fill_level = tx_queue->insert_count - tx_queue->read_count;
                if (fill_level < EFX_TXQ_THRESHOLD(efx)) {
                        EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
index cb317cd069ffcb5d13fa2fe5a5d920049b23ffeb..484f795a779dbca9b20e4f089d06cf1b9e253a50 100644 (file)
@@ -240,7 +240,8 @@ static const struct ethtool_ops sis900_ethtool_ops;
  *     @net_dev: the net device to get address for
  *
  *     Older SiS900 and friends, use EEPROM to store MAC address.
- *     MAC address is read from read_eeprom() into @net_dev->dev_addr.
+ *     MAC address is read from read_eeprom() into @net_dev->dev_addr and
+ *     @net_dev->perm_addr.
  */
 
 static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
@@ -261,6 +262,9 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
        for (i = 0; i < 3; i++)
                ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
 
+       /* Store MAC Address in perm_addr */
+       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
+
        return 1;
 }
 
@@ -271,7 +275,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
  *
  *     SiS630E model, use APC CMOS RAM to store MAC address.
  *     APC CMOS RAM is accessed through ISA bridge.
- *     MAC address is read into @net_dev->dev_addr.
+ *     MAC address is read into @net_dev->dev_addr and
+ *     @net_dev->perm_addr.
  */
 
 static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
@@ -296,6 +301,10 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
                outb(0x09 + i, 0x70);
                ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
        }
+
+       /* Store MAC Address in perm_addr */
+       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
+
        pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
        pci_dev_put(isa_bridge);
 
@@ -310,7 +319,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
  *
  *     SiS635 model, set MAC Reload Bit to load Mac address from APC
  *     to rfdr. rfdr is accessed through rfcr. MAC address is read into
- *     @net_dev->dev_addr.
+ *     @net_dev->dev_addr and @net_dev->perm_addr.
  */
 
 static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev,
@@ -334,6 +343,9 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev,
                *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr);
        }
 
+       /* Store MAC Address in perm_addr */
+       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
+
        /* enable packet filtering */
        outl(rfcrSave | RFEN, rfcr + ioaddr);
 
@@ -353,7 +365,7 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev,
  *     EEDONE signal to refuse EEPROM access by LAN.
  *     The EEPROM map of SiS962 or SiS963 is different to SiS900.
  *     The signature field in SiS962 or SiS963 spec is meaningless.
- *     MAC address is read into @net_dev->dev_addr.
+ *     MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr.
  */
 
 static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev,
@@ -372,6 +384,9 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev,
                        for (i = 0; i < 3; i++)
                                ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
 
+                       /* Store MAC Address in perm_addr */
+                       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
+
                        outl(EEDONE, ee_addr);
                        return 1;
                } else {
index d65fab1ba790dfd0dba7af94bbf2506fc5566d7f..e25093510b0cd462af521f45aa5b3f43c98c0213 100644 (file)
@@ -26,9 +26,9 @@
 
 #undef DWMAC_DMA_DEBUG
 #ifdef DWMAC_DMA_DEBUG
-#define DBG(fmt, args...)  printk(fmt, ## args)
+#define DWMAC_LIB_DBG(fmt, args...)  printk(fmt, ## args)
 #else
-#define DBG(fmt, args...)  do { } while (0)
+#define DWMAC_LIB_DBG(fmt, args...)  do { } while (0)
 #endif
 
 /* CSR1 enables the transmit DMA to check for new descriptor */
@@ -152,7 +152,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
        /* read the status register (CSR5) */
        u32 intr_status = readl(ioaddr + DMA_STATUS);
 
-       DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
+       DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
 #ifdef DWMAC_DMA_DEBUG
        /* It displays the DMA process states (CSR5 register) */
        show_tx_process_state(intr_status);
@@ -160,43 +160,43 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
 #endif
        /* ABNORMAL interrupts */
        if (unlikely(intr_status & DMA_STATUS_AIS)) {
-               DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
+               DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: ");
                if (unlikely(intr_status & DMA_STATUS_UNF)) {
-                       DBG(INFO, "transmit underflow\n");
+                       DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n");
                        ret = tx_hard_error_bump_tc;
                        x->tx_undeflow_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_TJT)) {
-                       DBG(INFO, "transmit jabber\n");
+                       DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n");
                        x->tx_jabber_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_OVF)) {
-                       DBG(INFO, "recv overflow\n");
+                       DWMAC_LIB_DBG(KERN_INFO "recv overflow\n");
                        x->rx_overflow_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_RU)) {
-                       DBG(INFO, "receive buffer unavailable\n");
+                       DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n");
                        x->rx_buf_unav_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_RPS)) {
-                       DBG(INFO, "receive process stopped\n");
+                       DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n");
                        x->rx_process_stopped_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_RWT)) {
-                       DBG(INFO, "receive watchdog\n");
+                       DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n");
                        x->rx_watchdog_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_ETI)) {
-                       DBG(INFO, "transmit early interrupt\n");
+                       DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n");
                        x->tx_early_irq++;
                }
                if (unlikely(intr_status & DMA_STATUS_TPS)) {
-                       DBG(INFO, "transmit process stopped\n");
+                       DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n");
                        x->tx_process_stopped_irq++;
                        ret = tx_hard_error;
                }
                if (unlikely(intr_status & DMA_STATUS_FBI)) {
-                       DBG(INFO, "fatal bus error\n");
+                       DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n");
                        x->fatal_bus_error_irq++;
                        ret = tx_hard_error;
                }
@@ -215,7 +215,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
        /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
        writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
 
-       DBG(INFO, "\n\n");
+       DWMAC_LIB_DBG(KERN_INFO "\n\n");
        return ret;
 }
 
index 0e5f03135b50abd053712ca6ddaf1e14df76a241..cc973fc384052bc2a5315aa982237b5bbc31015f 100644 (file)
@@ -750,7 +750,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
                        priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
                        priv->xstats.threshold = tc;
                }
-               stmmac_tx_err(priv);
        } else if (unlikely(status == tx_hard_error))
                stmmac_tx_err(priv);
 }
@@ -781,21 +780,6 @@ static int stmmac_open(struct net_device *dev)
 
        stmmac_verify_args();
 
-       ret = stmmac_init_phy(dev);
-       if (unlikely(ret)) {
-               pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
-               return ret;
-       }
-
-       /* Request the IRQ lines */
-       ret = request_irq(dev->irq, stmmac_interrupt,
-                         IRQF_SHARED, dev->name, dev);
-       if (unlikely(ret < 0)) {
-               pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
-                      __func__, dev->irq, ret);
-               return ret;
-       }
-
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
        if (unlikely(priv->tm == NULL)) {
@@ -814,6 +798,11 @@ static int stmmac_open(struct net_device *dev)
        } else
                priv->tm->enable = 1;
 #endif
+       ret = stmmac_init_phy(dev);
+       if (unlikely(ret)) {
+               pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
+               goto open_error;
+       }
 
        /* Create and initialize the TX/RX descriptors chains. */
        priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
@@ -822,12 +811,11 @@ static int stmmac_open(struct net_device *dev)
        init_dma_desc_rings(dev);
 
        /* DMA initialization and SW reset */
-       if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl,
-                                        priv->dma_tx_phy,
-                                        priv->dma_rx_phy) < 0)) {
-
+       ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl,
+                                 priv->dma_tx_phy, priv->dma_rx_phy);
+       if (ret < 0) {
                pr_err("%s: DMA initialization failed\n", __func__);
-               return -1;
+               goto open_error;
        }
 
        /* Copy the MAC addr into the HW  */
@@ -848,6 +836,15 @@ static int stmmac_open(struct net_device *dev)
        writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
        writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK);
 
+       /* Request the IRQ lines */
+       ret = request_irq(dev->irq, stmmac_interrupt,
+                        IRQF_SHARED, dev->name, dev);
+       if (unlikely(ret < 0)) {
+               pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
+                      __func__, dev->irq, ret);
+               goto open_error;
+       }
+
        /* Enable the MAC Rx/Tx */
        stmmac_enable_mac(priv->ioaddr);
 
@@ -878,7 +875,17 @@ static int stmmac_open(struct net_device *dev)
        napi_enable(&priv->napi);
        skb_queue_head_init(&priv->rx_recycle);
        netif_start_queue(dev);
+
        return 0;
+
+open_error:
+#ifdef CONFIG_STMMAC_TIMER
+       kfree(priv->tm);
+#endif
+       if (priv->phydev)
+               phy_disconnect(priv->phydev);
+
+       return ret;
 }
 
 /**
index b8c5f35577e45eb81e5f6a847b2831f9ce6f3619..7a5daefb6f3311e6e6d169113d7977e908045cbb 100644 (file)
@@ -12327,8 +12327,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                if (val & VCPU_CFGSHDW_ASPM_DBNC)
                        tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
                if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
-                   (val & VCPU_CFGSHDW_WOL_MAGPKT))
+                   (val & VCPU_CFGSHDW_WOL_MAGPKT)) {
                        tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+                       device_set_wakeup_enable(&tp->pdev->dev, true);
+               }
                goto done;
        }
 
@@ -12461,8 +12463,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
                if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
-                   (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE))
+                   (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) {
                        tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+                       device_set_wakeup_enable(&tp->pdev->dev, true);
+               }
 
                if (cfg2 & (1 << 17))
                        tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING;
index 8a3b191b195b8bc015694b5042fd67a340ecd421..ff32befd84433c98867a6b7a9d8824978e9e8557 100644 (file)
@@ -1251,7 +1251,7 @@ static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev)
 /* 
  * The NIC has told us that a packet has been downloaded onto the card, we must
  * find out which packet it has done, clear the skb and information for the packet
- * then advance around the ring for all tranmitted packets
+ * then advance around the ring for all transmitted packets
  */
 
 static void xl_dn_comp(struct net_device *dev) 
@@ -1568,7 +1568,7 @@ static void xl_arb_cmd(struct net_device *dev)
                        if (lan_status_diff & LSC_SOFT_ERR)
                                        printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN) 
-                                       printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
+                                       printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name);
                        if (lan_status_diff & LSC_SS) 
                                        printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
index 5bd140704533f353fa6b7ee05a6cbd9445aec7ad..9354ca9da576c97f7ff54ed014480d29e877ec48 100644 (file)
@@ -1675,7 +1675,7 @@ drop_frame:
                        if (lan_status_diff & LSC_SOFT_ERR)
                                printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n", dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN)
-                               printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n", dev->name);
+                               printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n", dev->name);
                        if (lan_status_diff & LSC_SS)
                                printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
index 3d2fbe60b46e07f57e97f418ad62a903e908b26f..2684003b8ab6478037d1047328c61be4f02a8837 100644 (file)
@@ -1500,7 +1500,7 @@ drop_frame:
                        if (lan_status_diff & LSC_SOFT_ERR)
                                        printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN) 
-                                       printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
+                                       printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name);
                        if (lan_status_diff & LSC_SS) 
                                        printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
index 341f7056a800ec2146c6187e3e9aca5ff6f7be5d..a301479ecc60a5f750e743cbed6f0104e0163ddb 100644 (file)
@@ -460,7 +460,7 @@ static const struct driver_info     cdc_info = {
        .manage_power = cdc_manage_power,
 };
 
-static const struct driver_info mbm_info = {
+static const struct driver_info wwan_info = {
        .description =  "Mobile Broadband Network Device",
        .flags =        FLAG_WWAN,
        .bind =         usbnet_cdc_bind,
@@ -471,6 +471,7 @@ static const struct driver_info mbm_info = {
 
 /*-------------------------------------------------------------------------*/
 
+#define HUAWEI_VENDOR_ID       0x12D1
 
 static const struct usb_device_id      products [] = {
 /*
@@ -587,8 +588,17 @@ static const struct usb_device_id  products [] = {
 }, {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
                        USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long)&mbm_info,
+       .driver_info = (unsigned long)&wwan_info,
 
+}, {
+       /* Various Huawei modems with a network port like the UMG1831 */
+       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
+                | USB_DEVICE_ID_MATCH_INT_INFO,
+       .idVendor               = HUAWEI_VENDOR_ID,
+       .bInterfaceClass        = USB_CLASS_COMM,
+       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
+       .bInterfaceProtocol     = 255,
+       .driver_info = (unsigned long)&wwan_info,
 },
        { },            // END
 };
index 967371f04454205a1b147bddf27443a1e14f003a..1033ef6476a41a67ab0f8201dc0ad9218a8fe6de 100644 (file)
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "7-Feb-2011"
+#define        DRIVER_VERSION                          "23-Apr-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
 
 /* Maximum NTB length */
-#define        CDC_NCM_NTB_MAX_SIZE_TX                 16384   /* bytes */
+#define        CDC_NCM_NTB_MAX_SIZE_TX                 (16384 + 4) /* bytes, must be short terminated */
 #define        CDC_NCM_NTB_MAX_SIZE_RX                 16384   /* bytes */
 
 /* Minimum value for MaxDatagramSize, ch. 6.2.9 */
index 47a6c870b51fae361b39de950ee4a523ced52475..48d4efdb4959a61b6704d58178879593ca4edad2 100644 (file)
@@ -730,7 +730,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
                msleep(10);
                bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
                timeout++;
-       } while ((bmcr & MII_BMCR) && (timeout < 100));
+       } while ((bmcr & BMCR_RESET) && (timeout < 100));
 
        if (timeout >= 100) {
                netdev_warn(dev->net, "timeout on PHY Reset");
index 069c1cf0fdf73675dbb865b27ee4d673bd773840..009bba3d753e7798f5a2331c233ee7c99884d6bd 100644 (file)
@@ -736,6 +736,7 @@ int usbnet_open (struct net_device *net)
                }
        }
 
+       set_bit(EVENT_DEV_OPEN, &dev->flags);
        netif_start_queue (net);
        netif_info(dev, ifup, dev->net,
                   "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n",
@@ -1259,6 +1260,9 @@ void usbnet_disconnect (struct usb_interface *intf)
        if (dev->driver_info->unbind)
                dev->driver_info->unbind (dev, intf);
 
+       usb_kill_urb(dev->interrupt);
+       usb_free_urb(dev->interrupt);
+
        free_netdev(net);
        usb_put_dev (xdev);
 }
@@ -1498,6 +1502,10 @@ int usbnet_resume (struct usb_interface *intf)
        int                     retval;
 
        if (!--dev->suspend_count) {
+               /* resume interrupt URBs */
+               if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags))
+                       usb_submit_urb(dev->interrupt, GFP_NOIO);
+
                spin_lock_irq(&dev->txq.lock);
                while ((res = usb_get_from_anchor(&dev->deferred))) {
 
index 2de9b90c5f8f079859b695979acb4871c5a0ea08..3b99f64104fd528f7e1582931cacb58ff3bf7a92 100644 (file)
@@ -403,6 +403,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
        if (tb[IFLA_ADDRESS] == NULL)
                random_ether_addr(dev->dev_addr);
 
+       if (tb[IFLA_IFNAME])
+               nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
+       else
+               snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
+
+       if (strchr(dev->name, '%')) {
+               err = dev_alloc_name(dev, dev->name);
+               if (err < 0)
+                       goto err_alloc_name;
+       }
+
        err = register_netdevice(dev);
        if (err < 0)
                goto err_register_dev;
@@ -422,6 +433,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
 
 err_register_dev:
        /* nothing to do */
+err_alloc_name:
 err_configure_peer:
        unregister_netdevice(peer);
        return err;
index f1b8af64569cbdeea7d80316d071aea329eab494..2d10239ce8295e2633699c6680a9f1b7072703e1 100644 (file)
@@ -1040,7 +1040,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
        }
 
        ret = ath9k_htc_hw_init(hif_dev->htc_handle,
-                               &hif_dev->udev->dev, hif_dev->device_id,
+                               &interface->dev, hif_dev->device_id,
                                hif_dev->udev->product, id->driver_info);
        if (ret) {
                ret = -EINVAL;
@@ -1158,7 +1158,7 @@ fail_resume:
 #endif
 
 static struct usb_driver ath9k_hif_usb_driver = {
-       .name = "ath9k_hif_usb",
+       .name = KBUILD_MODNAME,
        .probe = ath9k_hif_usb_probe,
        .disconnect = ath9k_hif_usb_disconnect,
 #ifdef CONFIG_PM
index 1ec9bcd6b2815c28b34cfd4b2a232c8b055dd716..c95bc5cc1a1fbb4bad3d2e816477c5cfbe96fb97 100644 (file)
@@ -1254,15 +1254,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ah->txchainmask = common->tx_chainmask;
        ah->rxchainmask = common->rx_chainmask;
 
-       if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) {
-               ath9k_hw_abortpcurecv(ah);
-               if (!ath9k_hw_stopdmarecv(ah)) {
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "Failed to stop receive dma\n");
-                       bChannelChange = false;
-               }
-       }
-
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
index 562257ac52cfecf77ee58cd7f1318507f14d9b75..edc1cbbfecaf6fbd153ce00237f1101f49096edc 100644 (file)
@@ -751,28 +751,47 @@ void ath9k_hw_abortpcurecv(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_abortpcurecv);
 
-bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
+bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
 {
 #define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
 #define AH_RX_TIME_QUANTUM     100     /* usec */
        struct ath_common *common = ath9k_hw_common(ah);
+       u32 mac_status, last_mac_status = 0;
        int i;
 
+       /* Enable access to the DMA observation bus */
+       REG_WRITE(ah, AR_MACMISC,
+                 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+                  (AR_MACMISC_MISC_OBS_BUS_1 <<
+                   AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
        REG_WRITE(ah, AR_CR, AR_CR_RXD);
 
        /* Wait for rx enable bit to go low */
        for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
                if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
                        break;
+
+               if (!AR_SREV_9300_20_OR_LATER(ah)) {
+                       mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0;
+                       if (mac_status == 0x1c0 && mac_status == last_mac_status) {
+                               *reset = true;
+                               break;
+                       }
+
+                       last_mac_status = mac_status;
+               }
+
                udelay(AH_TIME_QUANTUM);
        }
 
        if (i == 0) {
                ath_err(common,
-                       "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+                       "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
                        AH_RX_STOP_DMA_TIMEOUT / 1000,
                        REG_READ(ah, AR_CR),
-                       REG_READ(ah, AR_DIAG_SW));
+                       REG_READ(ah, AR_DIAG_SW),
+                       REG_READ(ah, AR_DMADBG_7));
                return false;
        } else {
                return true;
index b2b2ff852c328142a55396801010c46e32c72432..c2a59386fb9cf05a7eabb12214e613103e0c08b0 100644 (file)
@@ -695,7 +695,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
 void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_abortpcurecv(struct ath_hw *ah);
-bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
+bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset);
 int ath9k_hw_beaconq_setup(struct ath_hw *ah);
 
 /* Interrupt Handling */
index dddb85de622d2ea253152032ec8edf86df475754..17d04ff8d678021aaf0f52f2da55794e017272b5 100644 (file)
@@ -1376,7 +1376,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
 
        ath9k_calculate_iter_data(hw, vif, &iter_data);
 
-       ath9k_ps_wakeup(sc);
        /* Set BSSID mask. */
        memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
        ath_hw_setbssidmask(common);
@@ -1411,7 +1410,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
        }
 
        ath9k_hw_set_interrupts(ah, ah->imask);
-       ath9k_ps_restore(sc);
 
        /* Set up ANI */
        if ((iter_data.naps + iter_data.nadhocs) > 0) {
@@ -1457,6 +1455,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        struct ath_vif *avp = (void *)vif->drv_priv;
        int ret = 0;
 
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
        switch (vif->type) {
@@ -1503,6 +1502,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        ath9k_do_vif_add_setup(hw, vif);
 out:
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
        return ret;
 }
 
@@ -1517,6 +1517,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
 
        ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
        mutex_lock(&sc->mutex);
+       ath9k_ps_wakeup(sc);
 
        /* See if new interface type is valid. */
        if ((new_type == NL80211_IFTYPE_ADHOC) &&
@@ -1546,6 +1547,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
 
        ath9k_do_vif_add_setup(hw, vif);
 out:
+       ath9k_ps_restore(sc);
        mutex_unlock(&sc->mutex);
        return ret;
 }
@@ -1558,6 +1560,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
        ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
 
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
        sc->nvifs--;
@@ -1569,6 +1572,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
        ath9k_calculate_summary_state(hw, NULL);
 
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
 }
 
 static void ath9k_enable_ps(struct ath_softc *sc)
@@ -1809,6 +1813,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
        txq = sc->tx.txq_map[queue];
 
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
        memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -1832,6 +1837,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
                        ath_beaconq_config(sc);
 
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
 
        return ret;
 }
@@ -1894,6 +1900,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        int slottime;
        int error;
 
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
        if (changed & BSS_CHANGED_BSSID) {
@@ -1994,6 +2001,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
 }
 
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
index a9c3f4672aa0e12736a24c8ddb4e4c280d635d29..b29c80def35e89f10284ae794d267ca3a19d3e55 100644 (file)
@@ -486,12 +486,12 @@ start_recv:
 bool ath_stoprecv(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
-       bool stopped;
+       bool stopped, reset = false;
 
        spin_lock_bh(&sc->rx.rxbuflock);
        ath9k_hw_abortpcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
-       stopped = ath9k_hw_stopdmarecv(ah);
+       stopped = ath9k_hw_stopdmarecv(ah, &reset);
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ath_edma_stop_recv(sc);
@@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc)
                        "confusing the DMA engine when we start RX up\n");
                ATH_DBG_WARN_ON_ONCE(!stopped);
        }
-       return stopped;
+       return stopped && !reset;
 }
 
 void ath_flushrecv(struct ath_softc *sc)
index 248c670fdfbefe0bf06e3ace4e33b2e4bd43da05..5c2cfe6941524ccd7b05525a147b5ce6854c3133 100644 (file)
@@ -195,6 +195,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = {
        {APL9_WORLD, CTL_ETSI, CTL_ETSI},
 
        {APL3_FCCA, CTL_FCC, CTL_FCC},
+       {APL7_FCCA, CTL_FCC, CTL_FCC},
        {APL1_ETSIC, CTL_FCC, CTL_ETSI},
        {APL2_ETSIC, CTL_FCC, CTL_ETSI},
        {APL2_APLD, CTL_FCC, NO_CTL},
index d59b0168c14ad3b6c9b8b6c5ab40cbb524c0fb87..5af40d9170a096c4c598c9ae7c170cbb149c2f1a 100644 (file)
@@ -72,6 +72,7 @@ MODULE_FIRMWARE("b43/ucode11.fw");
 MODULE_FIRMWARE("b43/ucode13.fw");
 MODULE_FIRMWARE("b43/ucode14.fw");
 MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode16_mimo.fw");
 MODULE_FIRMWARE("b43/ucode5.fw");
 MODULE_FIRMWARE("b43/ucode9.fw");
 
index 2a45dd44cc127ba7abf3400012059ab90addcb73..aef65cd47661e39a62106b232eccb8054b382411 100644 (file)
@@ -1,6 +1,5 @@
 config IWLWIFI_LEGACY
-       tristate "Intel Wireless Wifi legacy devices"
-       depends on PCI && MAC80211
+       tristate
        select FW_LOADER
        select NEW_LEDS
        select LEDS_CLASS
@@ -65,7 +64,8 @@ endmenu
 
 config IWL4965
        tristate "Intel Wireless WiFi 4965AGN (iwl4965)"
-       depends on IWLWIFI_LEGACY
+       depends on PCI && MAC80211
+       select IWLWIFI_LEGACY
        ---help---
          This option enables support for
 
@@ -92,7 +92,8 @@ config IWL4965
 
 config IWL3945
        tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
-       depends on IWLWIFI_LEGACY
+       depends on PCI && MAC80211
+       select IWLWIFI_LEGACY
        ---help---
          Select to build the driver supporting the:
 
index 779d3cb86e2c86ad9c15f207288032064bca9dcf..5c3a68d3af12e3e7c7fe137a536d2759416f2443 100644 (file)
@@ -74,8 +74,6 @@
 /* RSSI to dBm */
 #define IWL39_RSSI_OFFSET      95
 
-#define IWL_DEFAULT_TX_POWER   0x0F
-
 /*
  * EEPROM related constants, enums, and structures.
  */
index 08b189c8472d214d20ed132a3f0849e693136a29..fc6fa2886d9c38f05099516147dacc3088afb748 100644 (file)
@@ -804,9 +804,6 @@ struct iwl4965_scd_bc_tbl {
 
 #define IWL4965_DEFAULT_TX_RETRY  15
 
-/* Limit range of txpower output target to be between these values */
-#define IWL4965_TX_POWER_TARGET_POWER_MIN      (0)     /* 0 dBm: 1 milliwatt */
-
 /* EEPROM */
 #define IWL4965_FIRST_AMPDU_QUEUE      10
 
index 5c40502f869a89458545456870826236a27904d5..79ac081832fb771ff6ce607f37ce50e9bd5bc783 100644 (file)
@@ -316,12 +316,18 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        hdr_len = ieee80211_hdrlen(fc);
 
-       /* Find index into station table for destination station */
-       sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-                              hdr->addr1);
-               goto drop_unlock;
+       /* For management frames use broadcast id to do not break aggregation */
+       if (!ieee80211_is_data(fc))
+               sta_id = ctx->bcast_sta_id;
+       else {
+               /* Find index into station table for destination station */
+               sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta);
+
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+                                      hdr->addr1);
+                       goto drop_unlock;
+               }
        }
 
        IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -1127,12 +1133,16 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwl4965_tx_status(priv, tx_info,
-                                txq_id >= IWL4965_FIRST_AMPDU_QUEUE);
+
+               if (WARN_ON_ONCE(tx_info->skb == NULL))
+                       continue;
 
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
-               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+               if (ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
+
+               iwl4965_tx_status(priv, tx_info,
+                                txq_id >= IWL4965_FIRST_AMPDU_QUEUE);
                tx_info->skb = NULL;
 
                priv->cfg->ops->lib->txq_free_tfd(priv, txq);
index 7007d61bb6b5c904aa62af13183bc67b24eb635f..c1511b14b239c69884292e5e8e33296debbdebc4 100644 (file)
@@ -160,6 +160,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv)
        struct ieee80211_channel *geo_ch;
        struct ieee80211_rate *rates;
        int i = 0;
+       s8 max_tx_power = 0;
 
        if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
            priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
@@ -235,8 +236,8 @@ int iwl_legacy_init_geos(struct iwl_priv *priv)
 
                        geo_ch->flags |= ch->ht40_extension_channel;
 
-                       if (ch->max_power_avg > priv->tx_power_device_lmt)
-                               priv->tx_power_device_lmt = ch->max_power_avg;
+                       if (ch->max_power_avg > max_tx_power)
+                               max_tx_power = ch->max_power_avg;
                } else {
                        geo_ch->flags |= IEEE80211_CHAN_DISABLED;
                }
@@ -249,6 +250,10 @@ int iwl_legacy_init_geos(struct iwl_priv *priv)
                                 geo_ch->flags);
        }
 
+       priv->tx_power_device_lmt = max_tx_power;
+       priv->tx_power_user_lmt = max_tx_power;
+       priv->tx_power_next = max_tx_power;
+
        if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
             priv->cfg->sku & IWL_SKU_A) {
                IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
@@ -1124,11 +1129,11 @@ int iwl_legacy_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        if (!priv->cfg->ops->lib->send_tx_power)
                return -EOPNOTSUPP;
 
-       if (tx_power < IWL4965_TX_POWER_TARGET_POWER_MIN) {
+       /* 0 dBm mean 1 milliwatt */
+       if (tx_power < 0) {
                IWL_WARN(priv,
-                        "Requested user TXPOWER %d below lower limit %d.\n",
-                        tx_power,
-                        IWL4965_TX_POWER_TARGET_POWER_MIN);
+                        "Requested user TXPOWER %d below 1 mW.\n",
+                        tx_power);
                return -EINVAL;
        }
 
index 04c5648027df8db645aa57d4f5535267c5a15d3b..cb346d1a9ffa6e5f581b5b9c9c0a52f6ffafed3a 100644 (file)
@@ -471,13 +471,6 @@ int iwl_legacy_init_channel_map(struct iwl_priv *priv)
                                             flags & EEPROM_CHANNEL_RADAR))
                                       ? "" : "not ");
 
-                       /* Set the tx_power_user_lmt to the highest power
-                        * supported by any channel */
-                       if (eeprom_ch_info[ch].max_power_avg >
-                                               priv->tx_power_user_lmt)
-                               priv->tx_power_user_lmt =
-                                   eeprom_ch_info[ch].max_power_avg;
-
                        ch_info++;
                }
        }
index 15eb8b70715741c0a92e347b0d087964df2b32f9..bda0d61b2c0d1e5aefaea5b13fd4e25a84832ec1 100644 (file)
@@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO);
 MODULE_PARM_DESC(led_mode, "0=system default, "
                "1=On(RF On)/Off(RF Off), 2=blinking");
 
+/* Throughput          OFF time(ms)    ON time (ms)
+ *     >300                    25              25
+ *     >200 to 300             40              40
+ *     >100 to 200             55              55
+ *     >70 to 100              65              65
+ *     >50 to 70               75              75
+ *     >20 to 50               85              85
+ *     >10 to 20               95              95
+ *     >5 to 10                110             110
+ *     >1 to 5                 130             130
+ *     >0 to 1                 167             167
+ *     <=0                                     SOLID ON
+ */
 static const struct ieee80211_tpt_blink iwl_blink[] = {
-       { .throughput = 0 * 1024 - 1, .blink_time = 334 },
+       { .throughput = 0, .blink_time = 334 },
        { .throughput = 1 * 1024 - 1, .blink_time = 260 },
        { .throughput = 5 * 1024 - 1, .blink_time = 220 },
        { .throughput = 10 * 1024 - 1, .blink_time = 190 },
@@ -101,6 +114,11 @@ static int iwl_legacy_led_cmd(struct iwl_priv *priv,
        if (priv->blink_on == on && priv->blink_off == off)
                return 0;
 
+       if (off == 0) {
+               /* led is SOLID_ON */
+               on = IWL_LED_SOLID;
+       }
+
        IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
                        priv->cfg->base_params->led_compensation);
        led_cmd.on = iwl_legacy_blink_compensation(priv, on,
index 28eb3d885ba176874a0896bcfa03c5c4953f9af3..cc7ebcee60e5bd6e9d49f2a1ae8c17dee1c31f21 100644 (file)
@@ -3825,10 +3825,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        priv->force_reset[IWL_FW_RESET].reset_duration =
                IWL_DELAY_NEXT_FORCE_FW_RELOAD;
 
-
-       priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
-       priv->tx_power_next = IWL_DEFAULT_TX_POWER;
-
        if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
                IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n",
                         eeprom->version);
index 91b3d8b9d7a5aceb2ecc0fbdc5d657dbe19a2cc8..a62fe24ee594cbbb5b462701ca3ec369b422a437 100644 (file)
@@ -2984,15 +2984,15 @@ static void iwl4965_bg_txpower_work(struct work_struct *work)
        struct iwl_priv *priv = container_of(work, struct iwl_priv,
                        txpower_work);
 
+       mutex_lock(&priv->mutex);
+
        /* If a scan happened to start before we got here
         * then just return; the statistics notification will
         * kick off another scheduled work to compensate for
         * any temperature delta we missed here. */
        if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
            test_bit(STATUS_SCANNING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
+               goto out;
 
        /* Regardless of if we are associated, we must reconfigure the
         * TX power since frames can be sent on non-radar channels while
@@ -3002,7 +3002,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work)
        /* Update last_temperature to keep is_calib_needed from running
         * when it isn't needed... */
        priv->last_temperature = priv->temperature;
-
+out:
        mutex_unlock(&priv->mutex);
 }
 
@@ -3140,12 +3140,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
 
        iwl_legacy_init_scan_params(priv);
 
-       /* Set the tx_power_user_lmt to the lowest power level
-        * this value will get overwritten by channel max power avg
-        * from eeprom */
-       priv->tx_power_user_lmt = IWL4965_TX_POWER_TARGET_POWER_MIN;
-       priv->tx_power_next = IWL4965_TX_POWER_TARGET_POWER_MIN;
-
        ret = iwl_legacy_init_channel_map(priv);
        if (ret) {
                IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
index 3ea31b659d1a5b620318d731c4036648e9ebd2b6..22e045b5bcee0a335baac193c8becdc8300314a1 100644 (file)
@@ -530,6 +530,9 @@ static struct iwl_ht_params iwl5000_ht_params = {
 struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
        IWL_DEVICE_5000,
+       /* at least EEPROM 0x11A has wrong info */
+       .valid_tx_ant = ANT_ABC,        /* .cfg overwrite */
+       .valid_rx_ant = ANT_ABC,        /* .cfg overwrite */
        .ht_params = &iwl5000_ht_params,
 };
 
index dfdbea6e8f99530f05ce3c7fec062f2a6ff1a381..fbbde0712fa58ffb495f66e5e31d1265c95c162e 100644 (file)
@@ -335,7 +335,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
        struct ieee80211_channel *channel = conf->channel;
        const struct iwl_channel_info *ch_info;
        int ret = 0;
-       bool ht_changed[NUM_IWL_RXON_CTX] = {};
 
        IWL_DEBUG_MAC80211(priv, "changed %#x", changed);
 
@@ -383,10 +382,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 
                for_each_context(priv, ctx) {
                        /* Configure HT40 channels */
-                       if (ctx->ht.enabled != conf_is_ht(conf)) {
+                       if (ctx->ht.enabled != conf_is_ht(conf))
                                ctx->ht.enabled = conf_is_ht(conf);
-                               ht_changed[ctx->ctxid] = true;
-                       }
 
                        if (ctx->ht.enabled) {
                                if (conf_is_ht40_minus(conf)) {
@@ -455,8 +452,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
                if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
                        continue;
                iwlagn_commit_rxon(priv, ctx);
-               if (ht_changed[ctx->ctxid])
-                       iwlagn_update_qos(priv, ctx);
        }
  out:
        mutex_unlock(&priv->mutex);
index a709d05c5868f3e6a19d586bcdffd560cb69bf6f..0712b67283a4f7e1b4a4ae702623ba32fd61a933 100644 (file)
@@ -568,12 +568,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        hdr_len = ieee80211_hdrlen(fc);
 
-       /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-                              hdr->addr1);
-               goto drop_unlock;
+       /* For management frames use broadcast id to do not break aggregation */
+       if (!ieee80211_is_data(fc))
+               sta_id = ctx->bcast_sta_id;
+       else {
+               /* Find index into station table for destination station */
+               sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+                                      hdr->addr1);
+                       goto drop_unlock;
+               }
        }
 
        IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -1224,12 +1229,16 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info,
-                                txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
+
+               if (WARN_ON_ONCE(tx_info->skb == NULL))
+                       continue;
 
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
-               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+               if (ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
+
+               iwlagn_tx_status(priv, tx_info,
+                                txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
                tx_info->skb = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
index 36952274950e3cf7537834a132d5374f7b2b7322..c1ceb4b23971ea884577bb876432e4a764301446 100644 (file)
@@ -137,6 +137,7 @@ struct mwl8k_tx_queue {
 struct mwl8k_priv {
        struct ieee80211_hw *hw;
        struct pci_dev *pdev;
+       int irq;
 
        struct mwl8k_device_info *device_info;
 
@@ -3761,9 +3762,11 @@ static int mwl8k_start(struct ieee80211_hw *hw)
        rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
                         IRQF_SHARED, MWL8K_NAME, hw);
        if (rc) {
+               priv->irq = -1;
                wiphy_err(hw->wiphy, "failed to register IRQ handler\n");
                return -EIO;
        }
+       priv->irq = priv->pdev->irq;
 
        /* Enable TX reclaim and RX tasklets.  */
        tasklet_enable(&priv->poll_tx_task);
@@ -3800,6 +3803,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
        if (rc) {
                iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
                free_irq(priv->pdev->irq, hw);
+               priv->irq = -1;
                tasklet_disable(&priv->poll_tx_task);
                tasklet_disable(&priv->poll_rx_task);
        }
@@ -3818,7 +3822,10 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
 
        /* Disable interrupts */
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
-       free_irq(priv->pdev->irq, hw);
+       if (priv->irq != -1) {
+               free_irq(priv->pdev->irq, hw);
+               priv->irq = -1;
+       }
 
        /* Stop finalize join worker */
        cancel_work_sync(&priv->finalize_join_worker);
index 7834c26c295438e39ab1c63d3e1b0444ca81ef2f..042842e704de17945d7f61b9c6069072ad5230fe 100644 (file)
@@ -703,7 +703,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct p54_tx_info *p54info;
        struct p54_hdr *hdr;
        struct p54_tx_data *txhdr;
-       unsigned int padding, len, extra_len;
+       unsigned int padding, len, extra_len = 0;
        int i, j, ridx;
        u16 hdr_flags = 0, aid = 0;
        u8 rate, queue = 0, crypt_offset = 0;
index a3755ffc03d468faf83d70e7a6a5a15a7214a6ac..bc8ce48f07781f00dccc0c856194926562af9cc3 100644 (file)
@@ -2550,7 +2550,6 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
                                         const struct parport_pc_via_data *via)
 {
        short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 };
-       struct resource *base_res;
        u32 ite8872set;
        u32 ite8872_lpt, ite8872_lpthi;
        u8 ite8872_irq, type;
@@ -2561,8 +2560,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
 
        /* make sure which one chip */
        for (i = 0; i < 5; i++) {
-               base_res = request_region(inta_addr[i], 32, "it887x");
-               if (base_res) {
+               if (request_region(inta_addr[i], 32, "it887x")) {
                        int test;
                        pci_write_config_dword(pdev, 0x60,
                                                0xe5000000 | inta_addr[i]);
@@ -2571,7 +2569,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
                        test = inb(inta_addr[i]);
                        if (test != 0xff)
                                break;
-                       release_region(inta_addr[i], 0x8);
+                       release_region(inta_addr[i], 32);
                }
        }
        if (i >= 5) {
@@ -2635,7 +2633,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
        /*
         * Release the resource so that parport_pc_probe_port can get it.
         */
-       release_resource(base_res);
+       release_region(inta_addr[i], 32);
        if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi,
                                   irq, PARPORT_DMA_NONE, &pdev->dev, 0)) {
                printk(KERN_INFO
index c8ff646c0b056e9fc8c81f3110fe53bb4b12df39..0fa466a91bf413995169f1751823e25784d70891 100644 (file)
@@ -88,4 +88,6 @@ config PCI_IOAPIC
        depends on HOTPLUG
        default y
 
-select NLS if (DMI || ACPI)
+config PCI_LABEL
+       def_bool y if (DMI || ACPI)
+       select NLS
index 98d61c8e984bc218c823fcaeecb02fdcf18183a3..c85f744270a56664cb91a720624cfc97dc29c6ee 100644 (file)
@@ -56,10 +56,10 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
 # ACPI Related PCI FW Functions
 # ACPI _DSM provided firmware instance and string name
 #
-obj-$(CONFIG_ACPI)    += pci-acpi.o pci-label.o
+obj-$(CONFIG_ACPI)    += pci-acpi.o
 
 # SMBIOS provided firmware instance and labels
-obj-$(CONFIG_DMI)    += pci-label.o
+obj-$(CONFIG_PCI_LABEL) += pci-label.o
 
 # Cardbus & CompactPCI use setup-bus
 obj-$(CONFIG_HOTPLUG) += setup-bus.o
index 505c1c7075f011df2e94755b2fb88f632a4c148c..d552d2c77844327010074ee71550e58ccb0a3280 100644 (file)
@@ -1299,7 +1299,7 @@ static void iommu_detach_domain(struct dmar_domain *domain,
 static struct iova_domain reserved_iova_list;
 static struct lock_class_key reserved_rbtree_key;
 
-static void dmar_init_reserved_ranges(void)
+static int dmar_init_reserved_ranges(void)
 {
        struct pci_dev *pdev = NULL;
        struct iova *iova;
@@ -1313,8 +1313,10 @@ static void dmar_init_reserved_ranges(void)
        /* IOAPIC ranges shouldn't be accessed by DMA */
        iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
                IOVA_PFN(IOAPIC_RANGE_END));
-       if (!iova)
+       if (!iova) {
                printk(KERN_ERR "Reserve IOAPIC range failed\n");
+               return -ENODEV;
+       }
 
        /* Reserve all PCI MMIO to avoid peer-to-peer access */
        for_each_pci_dev(pdev) {
@@ -1327,11 +1329,13 @@ static void dmar_init_reserved_ranges(void)
                        iova = reserve_iova(&reserved_iova_list,
                                            IOVA_PFN(r->start),
                                            IOVA_PFN(r->end));
-                       if (!iova)
+                       if (!iova) {
                                printk(KERN_ERR "Reserve iova failed\n");
+                               return -ENODEV;
+                       }
                }
        }
-
+       return 0;
 }
 
 static void domain_reserve_special_ranges(struct dmar_domain *domain)
@@ -1835,7 +1839,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 
        ret = iommu_attach_domain(domain, iommu);
        if (ret) {
-               domain_exit(domain);
+               free_domain_mem(domain);
                goto error;
        }
 
@@ -2213,7 +2217,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
        return 0;
 }
 
-int __init init_dmars(void)
+static int __init init_dmars(int force_on)
 {
        struct dmar_drhd_unit *drhd;
        struct dmar_rmrr_unit *rmrr;
@@ -2393,8 +2397,15 @@ int __init init_dmars(void)
         *   enable translation
         */
        for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
+               if (drhd->ignored) {
+                       /*
+                        * we always have to disable PMRs or DMA may fail on
+                        * this device
+                        */
+                       if (force_on)
+                               iommu_disable_protect_mem_regions(drhd->iommu);
                        continue;
+               }
                iommu = drhd->iommu;
 
                iommu_flush_write_buffer(iommu);
@@ -3240,9 +3251,15 @@ static int device_notifier(struct notifier_block *nb,
        if (!domain)
                return 0;
 
-       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
+       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
                domain_remove_one_dev_info(domain, pdev);
 
+               if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
+                   !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
+                   list_empty(&domain->devices))
+                       domain_exit(domain);
+       }
+
        return 0;
 }
 
@@ -3277,12 +3294,21 @@ int __init intel_iommu_init(void)
        if (no_iommu || dmar_disabled)
                return -ENODEV;
 
-       iommu_init_mempool();
-       dmar_init_reserved_ranges();
+       if (iommu_init_mempool()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize iommu memory\n");
+               return  -ENODEV;
+       }
+
+       if (dmar_init_reserved_ranges()) {
+               if (force_on)
+                       panic("tboot: Failed to reserve iommu ranges\n");
+               return  -ENODEV;
+       }
 
        init_no_remapping_devices();
 
-       ret = init_dmars();
+       ret = init_dmars(force_on);
        if (ret) {
                if (force_on)
                        panic("tboot: Failed to initialize DMARs\n");
@@ -3391,6 +3417,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
                domain->iommu_count--;
                domain_update_iommu_cap(domain);
                spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
+
+               spin_lock_irqsave(&iommu->lock, tmp_flags);
+               clear_bit(domain->id, iommu->domain_ids);
+               iommu->domains[domain->id] = NULL;
+               spin_unlock_irqrestore(&iommu->lock, tmp_flags);
        }
 
        spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -3607,9 +3638,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
 
                pte = dmar_domain->pgd;
                if (dma_pte_present(pte)) {
-                       free_pgtable_page(dmar_domain->pgd);
                        dmar_domain->pgd = (struct dma_pte *)
                                phys_to_virt(dma_pte_addr(pte));
+                       free_pgtable_page(pte);
                }
                dmar_domain->agaw--;
        }
index d86ea8b0113701ecbbcb26de06c20f6d60089510..135df164a4c1e897e4d36a7d5a49336518669480 100644 (file)
@@ -781,7 +781,7 @@ static int pci_pm_resume(struct device *dev)
 
 #endif /* !CONFIG_SUSPEND */
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 
 static int pci_pm_freeze(struct device *dev)
 {
@@ -970,7 +970,7 @@ static int pci_pm_restore(struct device *dev)
        return error;
 }
 
-#else /* !CONFIG_HIBERNATION */
+#else /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #define pci_pm_freeze          NULL
 #define pci_pm_freeze_noirq    NULL
@@ -981,7 +981,7 @@ static int pci_pm_restore(struct device *dev)
 #define pci_pm_restore         NULL
 #define pci_pm_restore_noirq   NULL
 
-#endif /* !CONFIG_HIBERNATION */
+#endif /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #ifdef CONFIG_PM_RUNTIME
 
index fe77e822384134b49e7da159aa5352826c8feb03..e8c19def1b0f501863008b3dc892d18bd4cdbe5c 100644 (file)
@@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev,
        c = p_dev->function_config;
 
        if (!(c->state & CONFIG_LOCKED)) {
-               dev_dbg(&p_dev->dev, "Configuration isn't't locked\n");
+               dev_dbg(&p_dev->dev, "Configuration isn't locked\n");
                mutex_unlock(&s->ops_mutex);
                return -EACCES;
        }
index 453c54c97612833b341a1e9787d9a8d51c7ec223..4c3e94c0ae85336a9fcee6511d570e1ab4b058e5 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <mach/balloon3.h>
 
+#include <asm/mach-types.h>
+
 #include "soc_common.h"
 
 /*
@@ -127,6 +129,9 @@ static int __init balloon3_pcmcia_init(void)
 {
        int ret;
 
+       if (!machine_is_balloon3())
+               return -ENODEV;
+
        balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
        if (!balloon3_pcmcia_device)
                return -ENOMEM;
index b7e596620db16c594a7ba3cc73c2bbd9643b0e43..b829e655457b7df517175dae74099d7275d0c1e3 100644 (file)
@@ -69,15 +69,15 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        for (i = 0; i < ARRAY_SIZE(irqs); i++) {
                if (irqs[i].sock != skt->nr)
                        continue;
-               if (gpio_request(IRQ_TO_GPIO(irqs[i].irq), irqs[i].str) < 0) {
+               if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) {
                        pr_err("%s: sock %d unable to request gpio %d\n",
-                               __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
+                               __func__, skt->nr, irq_to_gpio(irqs[i].irq));
                        ret = -EBUSY;
                        goto error;
                }
-               if (gpio_direction_input(IRQ_TO_GPIO(irqs[i].irq)) < 0) {
+               if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) {
                        pr_err("%s: sock %d unable to set input gpio %d\n",
-                               __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
+                               __func__, skt->nr, irq_to_gpio(irqs[i].irq));
                        ret = -EINVAL;
                        goto error;
                }
@@ -86,7 +86,7 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 
 error:
        for (; i >= 0; i--) {
-               gpio_free(IRQ_TO_GPIO(irqs[i].irq));
+               gpio_free(irq_to_gpio(irqs[i].irq));
        }
        return (ret);
 }
@@ -97,7 +97,7 @@ static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
        /* free allocated gpio's */
        gpio_free(GPIO_PRDY);
        for (i = 0; i < ARRAY_SIZE(irqs); i++)
-               gpio_free(IRQ_TO_GPIO(irqs[i].irq));
+               gpio_free(irq_to_gpio(irqs[i].irq));
 }
 
 static unsigned long trizeps_pcmcia_status[2];
@@ -226,6 +226,9 @@ static int __init trizeps_pcmcia_init(void)
 {
        int ret;
 
+       if (!machine_is_trizeps4() && !machine_is_trizeps4wl())
+               return -ENODEV;
+
        trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
        if (!trizeps_pcmcia_device)
                return -ENOMEM;
index 2ee442c2a5db094df620a50bcbdf03072fc64336..0485e394712aa4645cc695230f2dcaaca1664af3 100644 (file)
@@ -187,7 +187,8 @@ config MSI_LAPTOP
        depends on ACPI
        depends on BACKLIGHT_CLASS_DEVICE
        depends on RFKILL
-       depends on SERIO_I8042
+       depends on INPUT && SERIO_I8042
+       select INPUT_SPARSEKMAP
        ---help---
          This is a driver for laptops built by MSI (MICRO-STAR
          INTERNATIONAL):
index 5ea6c3477d17da4f17f3f07059329fdff1212da3..ac4e7f83ce6c8a4914af0e2df7080bd956b26f6f 100644 (file)
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
 #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
 
 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
-MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3");
+MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
 MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
 
 enum acer_wmi_event_ids {
index efc776cb0c664e0c8bf19c092c0a48367d4e1043..832a3fd7c1c8538ef77fd26c628e0ddd2c1644d6 100644 (file)
@@ -201,8 +201,8 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
        if (!asus->inputdev)
                return -ENOMEM;
 
-       asus->inputdev->name = asus->driver->input_phys;
-       asus->inputdev->phys = asus->driver->input_name;
+       asus->inputdev->name = asus->driver->input_name;
+       asus->inputdev->phys = asus->driver->input_phys;
        asus->inputdev->id.bustype = BUS_HOST;
        asus->inputdev->dev.parent = &asus->platform_device->dev;
 
index 5f2dd386152b52236991b73c60b61fa361555af9..2c1abf63957f23d0353c209af843f8e8bcf3c50c 100644 (file)
@@ -585,8 +585,9 @@ static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
        return true;
 }
 
-static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
+static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
 {
+       struct pci_dev *port;
        struct pci_dev *dev;
        struct pci_bus *bus;
        bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
@@ -599,9 +600,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
        mutex_lock(&eeepc->hotplug_lock);
 
        if (eeepc->hotplug_slot) {
-               bus = pci_find_bus(0, 1);
+               port = acpi_get_pci_dev(handle);
+               if (!port) {
+                       pr_warning("Unable to find port\n");
+                       goto out_unlock;
+               }
+
+               bus = port->subordinate;
+
                if (!bus) {
-                       pr_warning("Unable to find PCI bus 1?\n");
+                       pr_warning("Unable to find PCI bus?\n");
                        goto out_unlock;
                }
 
@@ -609,6 +617,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
                        pr_err("Unable to read PCI config space?\n");
                        goto out_unlock;
                }
+
                absent = (l == 0xffffffff);
 
                if (blocked != absent) {
@@ -647,6 +656,17 @@ out_unlock:
        mutex_unlock(&eeepc->hotplug_lock);
 }
 
+static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)
+{
+       acpi_status status = AE_OK;
+       acpi_handle handle;
+
+       status = acpi_get_handle(NULL, node, &handle);
+
+       if (ACPI_SUCCESS(status))
+               eeepc_rfkill_hotplug(eeepc, handle);
+}
+
 static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
 {
        struct eeepc_laptop *eeepc = data;
@@ -654,7 +674,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
        if (event != ACPI_NOTIFY_BUS_CHECK)
                return;
 
-       eeepc_rfkill_hotplug(eeepc);
+       eeepc_rfkill_hotplug(eeepc, handle);
 }
 
 static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
@@ -672,6 +692,11 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
                                                     eeepc);
                if (ACPI_FAILURE(status))
                        pr_warning("Failed to register notify on %s\n", node);
+               /*
+                * Refresh pci hotplug in case the rfkill state was
+                * changed during setup.
+                */
+               eeepc_rfkill_hotplug(eeepc, handle);
        } else
                return -ENODEV;
 
@@ -693,6 +718,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
                if (ACPI_FAILURE(status))
                        pr_err("Error removing rfkill notify handler %s\n",
                                node);
+                       /*
+                        * Refresh pci hotplug in case the rfkill
+                        * state was changed after
+                        * eeepc_unregister_rfkill_notifier()
+                        */
+               eeepc_rfkill_hotplug(eeepc, handle);
        }
 }
 
@@ -816,11 +847,7 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
                rfkill_destroy(eeepc->wlan_rfkill);
                eeepc->wlan_rfkill = NULL;
        }
-       /*
-        * Refresh pci hotplug in case the rfkill state was changed after
-        * eeepc_unregister_rfkill_notifier()
-        */
-       eeepc_rfkill_hotplug(eeepc);
+
        if (eeepc->hotplug_slot)
                pci_hp_deregister(eeepc->hotplug_slot);
 
@@ -889,11 +916,6 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
        eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
        eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
        eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
-       /*
-        * Refresh pci hotplug in case the rfkill state was changed during
-        * setup.
-        */
-       eeepc_rfkill_hotplug(eeepc);
 
 exit:
        if (result && result != -ENODEV)
@@ -928,8 +950,11 @@ static int eeepc_hotk_restore(struct device *device)
        struct eeepc_laptop *eeepc = dev_get_drvdata(device);
 
        /* Refresh both wlan rfkill state and pci hotplug */
-       if (eeepc->wlan_rfkill)
-               eeepc_rfkill_hotplug(eeepc);
+       if (eeepc->wlan_rfkill) {
+               eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5");
+               eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6");
+               eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7");
+       }
 
        if (eeepc->bluetooth_rfkill)
                rfkill_set_sw_state(eeepc->bluetooth_rfkill,
index 0ddc434fb93ba2bdb8144f5937ba66707d3c72f5..649dcadd8ea372973cd45db1b5b8274847baff36 100644 (file)
@@ -67,9 +67,11 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_KEY, 0x82, { KEY_CAMERA } },
        { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
        { KE_KEY, 0x88, { KEY_WLAN } },
+       { KE_KEY, 0xbd, { KEY_CAMERA } },
        { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
        { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
+       { KE_KEY, 0xe8, { KEY_SCREENLOCK } },
        { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
        { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
        { KE_KEY, 0xec, { KEY_CAMERA_UP } },
index d653104b59cb25540d17a85d78f298eea75fd48a..464bb3fc4d88b1c7d8fc9583b48fee3fec610a4f 100644 (file)
@@ -74,6 +74,19 @@ struct pmic_gpio {
        u32                     trigger_type;
 };
 
+static void pmic_program_irqtype(int gpio, int type)
+{
+       if (type & IRQ_TYPE_EDGE_RISING)
+               intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
+       else
+               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
+       else
+               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
+};
+
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        if (offset > 8) {
@@ -166,16 +179,38 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
        return pg->irq_base + offset;
 }
 
+static void pmic_bus_lock(struct irq_data *data)
+{
+       struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&pg->buslock);
+}
+
+static void pmic_bus_sync_unlock(struct irq_data *data)
+{
+       struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+
+       if (pg->update_type) {
+               unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE;
+
+               pmic_program_irqtype(gpio, pg->trigger_type);
+               pg->update_type = 0;
+       }
+       mutex_unlock(&pg->buslock);
+}
+
 /* the gpiointr register is read-clear, so just do nothing. */
 static void pmic_irq_unmask(struct irq_data *data) { }
 
 static void pmic_irq_mask(struct irq_data *data) { }
 
 static struct irq_chip pmic_irqchip = {
-       .name           = "PMIC-GPIO",
-       .irq_mask       = pmic_irq_mask,
-       .irq_unmask     = pmic_irq_unmask,
-       .irq_set_type   = pmic_irq_type,
+       .name                   = "PMIC-GPIO",
+       .irq_mask               = pmic_irq_mask,
+       .irq_unmask             = pmic_irq_unmask,
+       .irq_set_type           = pmic_irq_type,
+       .irq_bus_lock           = pmic_bus_lock,
+       .irq_bus_sync_unlock    = pmic_bus_sync_unlock,
 };
 
 static irqreturn_t pmic_irq_handler(int irq, void *data)
index de434c6dc2d661133175ddf11464b4dac48f118e..d347116d150e38146eedf6e817e51afc84898169 100644 (file)
@@ -570,6 +570,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "R410 Plus",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
+                       DMI_MATCH(DMI_BOARD_NAME, "R460"),
+               },
+               .callback = dmi_check_cb,
+       },
        {
                .ident = "R518",
                .matches = {
@@ -591,12 +601,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                .callback = dmi_check_cb,
        },
        {
-               .ident = "N150/N210/N220",
+               .ident = "N150/N210/N220/N230",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR,
                                        "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
+                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
                },
                .callback = dmi_check_cb,
        },
@@ -771,6 +781,7 @@ static int __init samsung_init(void)
 
        /* create a backlight device to talk to this one */
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = sabi_config->max_brightness;
        backlight_device = backlight_device_register("samsung", &sdev->dev,
                                                     NULL, &backlight_ops,
index e642f5f295046edf07f9d16aed5bc26f5dde8731..6fe8cd6e23b5f89fd1efc1145796a9e6c530aa8e 100644 (file)
@@ -138,6 +138,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
                 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
                 "(default: 0)");
 
+static void sony_nc_kbd_backlight_resume(void);
+
 enum sony_nc_rfkill {
        SONY_WIFI,
        SONY_BLUETOOTH,
@@ -771,11 +773,6 @@ static int sony_nc_handles_setup(struct platform_device *pd)
        if (!handles)
                return -ENOMEM;
 
-       sysfs_attr_init(&handles->devattr.attr);
-       handles->devattr.attr.name = "handles";
-       handles->devattr.attr.mode = S_IRUGO;
-       handles->devattr.show = sony_nc_handles_show;
-
        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
                if (!acpi_callsetfunc(sony_nc_acpi_handle,
                                        "SN00", i + 0x20, &result)) {
@@ -785,11 +782,18 @@ static int sony_nc_handles_setup(struct platform_device *pd)
                }
        }
 
-       /* allow reading capabilities via sysfs */
-       if (device_create_file(&pd->dev, &handles->devattr)) {
-               kfree(handles);
-               handles = NULL;
-               return -1;
+       if (debug) {
+               sysfs_attr_init(&handles->devattr.attr);
+               handles->devattr.attr.name = "handles";
+               handles->devattr.attr.mode = S_IRUGO;
+               handles->devattr.show = sony_nc_handles_show;
+
+               /* allow reading capabilities via sysfs */
+               if (device_create_file(&pd->dev, &handles->devattr)) {
+                       kfree(handles);
+                       handles = NULL;
+                       return -1;
+               }
        }
 
        return 0;
@@ -798,7 +802,8 @@ static int sony_nc_handles_setup(struct platform_device *pd)
 static int sony_nc_handles_cleanup(struct platform_device *pd)
 {
        if (handles) {
-               device_remove_file(&pd->dev, &handles->devattr);
+               if (debug)
+                       device_remove_file(&pd->dev, &handles->devattr);
                kfree(handles);
                handles = NULL;
        }
@@ -808,6 +813,11 @@ static int sony_nc_handles_cleanup(struct platform_device *pd)
 static int sony_find_snc_handle(int handle)
 {
        int i;
+
+       /* not initialized yet, return early */
+       if (!handles)
+               return -1;
+
        for (i = 0; i < 0x10; i++) {
                if (handles->cap[i] == handle) {
                        dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
@@ -924,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 /*
  * Backlight device
  */
+struct sony_backlight_props {
+       struct backlight_device *dev;
+       int                     handle;
+       u8                      offset;
+       u8                      maxlvl;
+};
+struct sony_backlight_props sony_bl_props;
+
 static int sony_backlight_update_status(struct backlight_device *bd)
 {
        return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
@@ -944,21 +962,26 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd)
 {
        int result;
        int *handle = (int *)bl_get_data(bd);
+       struct sony_backlight_props *sdev =
+               (struct sony_backlight_props *)bl_get_data(bd);
 
-       sony_call_snc_handle(*handle, 0x0200, &result);
+       sony_call_snc_handle(sdev->handle, 0x0200, &result);
 
-       return result & 0xff;
+       return (result & 0xff) - sdev->offset;
 }
 
 static int sony_nc_update_status_ng(struct backlight_device *bd)
 {
        int value, result;
        int *handle = (int *)bl_get_data(bd);
+       struct sony_backlight_props *sdev =
+               (struct sony_backlight_props *)bl_get_data(bd);
 
-       value = bd->props.brightness;
-       sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result);
+       value = bd->props.brightness + sdev->offset;
+       if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
+               return -EIO;
 
-       return sony_nc_get_brightness_ng(bd);
+       return value;
 }
 
 static const struct backlight_ops sony_backlight_ops = {
@@ -971,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = {
        .update_status = sony_nc_update_status_ng,
        .get_brightness = sony_nc_get_brightness_ng,
 };
-static int backlight_ng_handle;
-static struct backlight_device *sony_backlight_device;
 
 /*
  * New SNC-only Vaios event mapping to driver known keys
@@ -1168,6 +1189,9 @@ static int sony_nc_resume(struct acpi_device *device)
        /* re-read rfkill state */
        sony_nc_rfkill_update();
 
+       /* restore kbd backlight states */
+       sony_nc_kbd_backlight_resume();
+
        return 0;
 }
 
@@ -1355,6 +1379,7 @@ out_no_enum:
 #define KBDBL_HANDLER  0x137
 #define KBDBL_PRESENT  0xB00
 #define        SET_MODE        0xC00
+#define SET_STATE      0xD00
 #define SET_TIMEOUT    0xE00
 
 struct kbd_backlight {
@@ -1377,6 +1402,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
                                (value << 0x10) | SET_MODE, &result))
                return -EIO;
 
+       /* Try to turn the light on/off immediately */
+       sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
+                       &result);
+
        kbdbl_handle->mode = value;
 
        return 0;
@@ -1458,7 +1487,7 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
 {
        int result;
 
-       if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
+       if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
                return 0;
        if (!(result & 0x02))
                return 0;
@@ -1501,13 +1530,105 @@ outkzalloc:
 static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
 {
        if (kbdbl_handle) {
+               int result;
+
                device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
                device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
+
+               /* restore the default hw behaviour */
+               sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
+               sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
+
                kfree(kbdbl_handle);
        }
        return 0;
 }
 
+static void sony_nc_kbd_backlight_resume(void)
+{
+       int ignore = 0;
+
+       if (!kbdbl_handle)
+               return;
+
+       if (kbdbl_handle->mode == 0)
+               sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
+
+       if (kbdbl_handle->timeout != 0)
+               sony_call_snc_handle(KBDBL_HANDLER,
+                               (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
+                               &ignore);
+}
+
+static void sony_nc_backlight_ng_read_limits(int handle,
+               struct sony_backlight_props *props)
+{
+       int offset;
+       acpi_status status;
+       u8 brlvl, i;
+       u8 min = 0xff, max = 0x00;
+       struct acpi_object_list params;
+       union acpi_object in_obj;
+       union acpi_object *lvl_enum;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       props->handle = handle;
+       props->offset = 0;
+       props->maxlvl = 0xff;
+
+       offset = sony_find_snc_handle(handle);
+       if (offset < 0)
+               return;
+
+       /* try to read the boundaries from ACPI tables, if we fail the above
+        * defaults should be reasonable
+        */
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_INTEGER;
+       in_obj.integer.value = offset;
+       status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
+                       &buffer);
+       if (ACPI_FAILURE(status))
+               return;
+
+       lvl_enum = (union acpi_object *) buffer.pointer;
+       if (!lvl_enum) {
+               pr_err("No SN06 return object.");
+               return;
+       }
+       if (lvl_enum->type != ACPI_TYPE_BUFFER) {
+               pr_err("Invalid SN06 return object 0x%.2x\n",
+                      lvl_enum->type);
+               goto out_invalid;
+       }
+
+       /* the buffer lists brightness levels available, brightness levels are
+        * from 0 to 8 in the array, other values are used by ALS control.
+        */
+       for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
+
+               brlvl = *(lvl_enum->buffer.pointer + i);
+               dprintk("Brightness level: %d\n", brlvl);
+
+               if (!brlvl)
+                       break;
+
+               if (brlvl > max)
+                       max = brlvl;
+               if (brlvl < min)
+                       min = brlvl;
+       }
+       props->offset = min;
+       props->maxlvl = max;
+       dprintk("Brightness levels: min=%d max=%d\n", props->offset,
+                       props->maxlvl);
+
+out_invalid:
+       kfree(buffer.pointer);
+       return;
+}
+
 static void sony_nc_backlight_setup(void)
 {
        acpi_handle unused;
@@ -1516,14 +1637,14 @@ static void sony_nc_backlight_setup(void)
        struct backlight_properties props;
 
        if (sony_find_snc_handle(0x12f) != -1) {
-               backlight_ng_handle = 0x12f;
                ops = &sony_backlight_ng_ops;
-               max_brightness = 0xff;
+               sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
+               max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
        } else if (sony_find_snc_handle(0x137) != -1) {
-               backlight_ng_handle = 0x137;
                ops = &sony_backlight_ng_ops;
-               max_brightness = 0xff;
+               sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
+               max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
        } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
                                                &unused))) {
@@ -1536,22 +1657,22 @@ static void sony_nc_backlight_setup(void)
        memset(&props, 0, sizeof(struct backlight_properties));
        props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = max_brightness;
-       sony_backlight_device = backlight_device_register("sony", NULL,
-                                                         &backlight_ng_handle,
-                                                         ops, &props);
+       sony_bl_props.dev = backlight_device_register("sony", NULL,
+                                                     &sony_bl_props,
+                                                     ops, &props);
 
-       if (IS_ERR(sony_backlight_device)) {
-               pr_warning(DRV_PFX "unable to register backlight device\n");
-               sony_backlight_device = NULL;
+       if (IS_ERR(sony_bl_props.dev)) {
+               pr_warn(DRV_PFX "unable to register backlight device\n");
+               sony_bl_props.dev = NULL;
        } else
-               sony_backlight_device->props.brightness =
-                   ops->get_brightness(sony_backlight_device);
+               sony_bl_props.dev->props.brightness =
+                       ops->get_brightness(sony_bl_props.dev);
 }
 
 static void sony_nc_backlight_cleanup(void)
 {
-       if (sony_backlight_device)
-               backlight_device_unregister(sony_backlight_device);
+       if (sony_bl_props.dev)
+               backlight_device_unregister(sony_bl_props.dev);
 }
 
 static int sony_nc_add(struct acpi_device *device)
@@ -2549,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
        mutex_lock(&spic_dev.lock);
        switch (cmd) {
        case SONYPI_IOCGBRT:
-               if (sony_backlight_device == NULL) {
+               if (sony_bl_props.dev == NULL) {
                        ret = -EIO;
                        break;
                }
@@ -2562,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
                                ret = -EFAULT;
                break;
        case SONYPI_IOCSBRT:
-               if (sony_backlight_device == NULL) {
+               if (sony_bl_props.dev == NULL) {
                        ret = -EIO;
                        break;
                }
@@ -2576,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
                        break;
                }
                /* sync the backlight device status */
-               sony_backlight_device->props.brightness =
-                   sony_backlight_get_brightness(sony_backlight_device);
+               sony_bl_props.dev->props.brightness =
+                   sony_backlight_get_brightness(sony_bl_props.dev);
                break;
        case SONYPI_IOCGBAT1CAP:
                if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
index a08561f5349ef038decaf8edcd73528f30f056a9..562fcf0dd2b5b083b7d45aeeb7e78a7c6809425f 100644 (file)
@@ -128,7 +128,8 @@ enum {
 };
 
 /* ACPI HIDs */
-#define TPACPI_ACPI_HKEY_HID           "IBM0068"
+#define TPACPI_ACPI_IBM_HKEY_HID       "IBM0068"
+#define TPACPI_ACPI_LENOVO_HKEY_HID    "LEN0068"
 #define TPACPI_ACPI_EC_HID             "PNP0C09"
 
 /* Input IDs */
@@ -3879,7 +3880,8 @@ errexit:
 }
 
 static const struct acpi_device_id ibm_htk_device_ids[] = {
-       {TPACPI_ACPI_HKEY_HID, 0},
+       {TPACPI_ACPI_IBM_HKEY_HID, 0},
+       {TPACPI_ACPI_LENOVO_HKEY_HID, 0},
        {"", 0},
 };
 
@@ -8618,8 +8620,7 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
                tpacpi_is_fw_digit(s[1]) &&
                s[2] == t && s[3] == 'T' &&
                tpacpi_is_fw_digit(s[4]) &&
-               tpacpi_is_fw_digit(s[5]) &&
-               s[6] == 'W' && s[7] == 'W';
+               tpacpi_is_fw_digit(s[5]);
 }
 
 /* returns 0 - probe ok, or < 0 - probe error.
index c29719cacbca00e108203361a25ee70cb5c8017f..86c9a091a2ffdbfb3cac0868f17824ee9f4e5b6d 100644 (file)
@@ -1171,16 +1171,17 @@ static int rio_hdid_setup(char *str)
 
 __setup("riohdid=", rio_hdid_setup);
 
-void rio_register_mport(struct rio_mport *port)
+int rio_register_mport(struct rio_mport *port)
 {
        if (next_portid >= RIO_MAX_MPORTS) {
                pr_err("RIO: reached specified max number of mports\n");
-               return;
+               return 1;
        }
 
        port->id = next_portid++;
        port->host_deviceid = rio_get_hdid(port->id);
        list_add_tail(&port->node, &rio_mports);
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(rio_local_get_device_id);
index 095016a9dec16930f7ed0947c0e607717678b16a..ac2701b22e7133f8239a3136b18a5f85799f8578 100644 (file)
@@ -418,3 +418,4 @@ DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
 DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
 DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init);
 DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1432, idtg2_switch_init);
index 09b4437b3e616aa57cdfec861b2b2ddf0ff9dd59..39013867cbd6cf0deeffcd59cb4c43280cac4618 100644 (file)
@@ -171,7 +171,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        err = __rtc_read_alarm(rtc, &alrm);
 
        if (!err && !rtc_valid_tm(&alrm.time))
-               rtc_set_alarm(rtc, &alrm);
+               rtc_initialize_alarm(rtc, &alrm);
 
        strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
        dev_set_name(&rtc->dev, "rtc%d", id);
index 23719f0acbf64b6cc240b75a72f0c274be4078cf..ef6316acec43a3312c00c6d8ca27b5ec8314f526 100644 (file)
@@ -375,6 +375,32 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 }
 EXPORT_SYMBOL_GPL(rtc_set_alarm);
 
+/* Called once per device from rtc_device_register */
+int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+       int err;
+
+       err = rtc_valid_tm(&alarm->time);
+       if (err != 0)
+               return err;
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return err;
+
+       rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
+       rtc->aie_timer.period = ktime_set(0, 0);
+       if (alarm->enabled) {
+               rtc->aie_timer.enabled = 1;
+               timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
+       }
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
+
+
+
 int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 {
        int err = mutex_lock_interruptible(&rtc->ops_lock);
index a0fc4cf42abf36b8c54a5e9a9d082648f87a4244..90d866272c8ea5095981afaa62396f03d92343b6 100644 (file)
@@ -250,6 +250,8 @@ static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
                bfin_rtc_int_set_alarm(rtc);
        else
                bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+
+       return 0;
 }
 
 static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
index 316f484999b55fb861667b5c6950654959ab7b75..80f9c88214c5e61987001d10479094cb8787f2a6 100644 (file)
@@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
        }
        clk_disable(rtap->clk);
 
+       platform_set_drvdata(pdev, rtap);
        rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops,
                                         THIS_MODULE);
        if (IS_ERR(rtap->rtc)) {
@@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev)
                goto out_no_rtc;
        }
 
-       platform_set_drvdata(pdev, rtap);
-
        return 0;
 
  out_no_rtc:
+       platform_set_drvdata(pdev, NULL);
  out_no_clk_enable:
        clk_put(rtap->clk);
  out_no_clk:
index 174036dda78652ce106afc23d12699f1d310000b..20494b5edc3c74cc787df17a0d25f554bcf37370 100644 (file)
@@ -257,6 +257,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
                goto out_irq;
        }
 
+       dev_set_drvdata(&pdev->dev, info);
+
        info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
                                        &max8925_rtc_ops, THIS_MODULE);
        ret = PTR_ERR(info->rtc_dev);
@@ -265,7 +267,6 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
                goto out_rtc;
        }
 
-       dev_set_drvdata(&pdev->dev, info);
        platform_set_drvdata(pdev, info);
 
        return 0;
index c420064695598edbe9cdc42c5767d35cc21d2811..c5ac03793e7910fec863f70130496cd3a3d60e9c 100644 (file)
@@ -401,6 +401,7 @@ const struct platform_device_id mc13xxx_rtc_idtable[] = {
        }, {
                .name = "mc13892-rtc",
        },
+       { }
 };
 
 static struct platform_driver mc13xxx_rtc_driver = {
index de0dd7b1f146e0e7fff07bd30487b1da9add0ca1..bcae8dd41496ab089d43e6639fedfd4272dca035 100644 (file)
@@ -394,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
        return 0;
 
 fail2:
-       free_irq(omap_rtc_timer, NULL);
+       free_irq(omap_rtc_timer, rtc);
 fail1:
        rtc_device_unregister(rtc);
 fail0:
index 714964913e5eb37d9c9dff9f0f346bbe6d41d5e7..b3466c491cd35cbbd93a64df0f1dbcf070c84e6c 100644 (file)
@@ -336,7 +336,6 @@ static void s3c_rtc_release(struct device *dev)
 
        /* do not clear AIE here, it may be needed for wake */
 
-       s3c_rtc_setpie(dev, 0);
        free_irq(s3c_rtc_alarmno, rtc_dev);
        free_irq(s3c_rtc_tickno, rtc_dev);
 }
@@ -408,7 +407,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
        platform_set_drvdata(dev, NULL);
        rtc_device_unregister(rtc);
 
-       s3c_rtc_setpie(&dev->dev, 0);
        s3c_rtc_setaie(&dev->dev, 0);
 
        clk_disable(rtc_clk);
index 4d2df2f76ea0daa718215c179e88fe2b45249516..475e603fc584f8547e6171eaf8cdb325ec085d1f 100644 (file)
@@ -2314,15 +2314,14 @@ static void dasd_flush_request_queue(struct dasd_block *block)
 
 static int dasd_open(struct block_device *bdev, fmode_t mode)
 {
-       struct dasd_block *block = bdev->bd_disk->private_data;
        struct dasd_device *base;
        int rc;
 
-       if (!block)
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
                return -ENODEV;
 
-       base = block->base;
-       atomic_inc(&block->open_count);
+       atomic_inc(&base->block->open_count);
        if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
                rc = -ENODEV;
                goto unlock;
@@ -2355,21 +2354,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
                goto out;
        }
 
+       dasd_put_device(base);
        return 0;
 
 out:
        module_put(base->discipline->owner);
 unlock:
-       atomic_dec(&block->open_count);
+       atomic_dec(&base->block->open_count);
+       dasd_put_device(base);
        return rc;
 }
 
 static int dasd_release(struct gendisk *disk, fmode_t mode)
 {
-       struct dasd_block *block = disk->private_data;
+       struct dasd_device *base;
 
-       atomic_dec(&block->open_count);
-       module_put(block->base->discipline->owner);
+       base = dasd_device_from_gendisk(disk);
+       if (!base)
+               return -ENODEV;
+
+       atomic_dec(&base->block->open_count);
+       module_put(base->discipline->owner);
+       dasd_put_device(base);
        return 0;
 }
 
@@ -2378,20 +2384,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode)
  */
 static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct dasd_block *block;
        struct dasd_device *base;
 
-       block = bdev->bd_disk->private_data;
-       if (!block)
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
                return -ENODEV;
-       base = block->base;
 
        if (!base->discipline ||
-           !base->discipline->fill_geometry)
+           !base->discipline->fill_geometry) {
+               dasd_put_device(base);
                return -EINVAL;
-
-       base->discipline->fill_geometry(block, geo);
-       geo->start = get_start_sect(bdev) >> block->s2b_shift;
+       }
+       base->discipline->fill_geometry(base->block, geo);
+       geo->start = get_start_sect(bdev) >> base->block->s2b_shift;
+       dasd_put_device(base);
        return 0;
 }
 
@@ -2528,7 +2534,6 @@ void dasd_generic_remove(struct ccw_device *cdev)
        dasd_set_target_state(device, DASD_STATE_NEW);
        /* dasd_delete_device destroys the device reference. */
        block = device->block;
-       device->block = NULL;
        dasd_delete_device(device);
        /*
         * life cycle of block is bound to device, so delete it after
@@ -2650,7 +2655,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
        dasd_set_target_state(device, DASD_STATE_NEW);
        /* dasd_delete_device destroys the device reference. */
        block = device->block;
-       device->block = NULL;
        dasd_delete_device(device);
        /*
         * life cycle of block is bound to device, so delete it after
index 42e1bf35f6893d53e3374eba20673b1d27d095f7..d71511c7850a8560014ceee03c468e4da24c361a 100644 (file)
@@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev)
        return device;
 }
 
+void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device)
+{
+       struct dasd_devmap *devmap;
+
+       devmap = dasd_find_busid(dev_name(&device->cdev->dev));
+       if (IS_ERR(devmap))
+               return;
+       spin_lock(&dasd_devmap_lock);
+       gdp->private_data = devmap;
+       spin_unlock(&dasd_devmap_lock);
+}
+
+struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
+{
+       struct dasd_device *device;
+       struct dasd_devmap *devmap;
+
+       if (!gdp->private_data)
+               return NULL;
+       device = NULL;
+       spin_lock(&dasd_devmap_lock);
+       devmap = gdp->private_data;
+       if (devmap && devmap->device) {
+               device = devmap->device;
+               dasd_get_device(device);
+       }
+       spin_unlock(&dasd_devmap_lock);
+       return device;
+}
+
 /*
  * SECTION: files in sysfs
  */
index 29143eda9dd903b4a8f897ade5eee20dcaecaf91..85dddb1e4126be512d843ceef08123fd86cc1b0d 100644 (file)
@@ -239,7 +239,6 @@ static void dasd_ext_handler(unsigned int ext_int_code,
        addr_t ip;
        int rc;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++;
        switch (ext_int_code >> 24) {
        case DASD_DIAG_CODE_31BIT:
                ip = (addr_t) param32;
@@ -250,6 +249,7 @@ static void dasd_ext_handler(unsigned int ext_int_code,
        default:
                return;
        }
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++;
        if (!ip) {              /* no intparm: unsolicited interrupt */
                DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited "
                              "interrupt");
index db8005d9f2fd2fe2effb667659228e4f3d38ba9f..3ebdf5f92f8f945fabad2e9744fa82f106b8a33b 100644 (file)
@@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
                return;
 
        /* summary unit check */
-       if ((sense[7] == 0x0D) &&
+       if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) &&
            (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
                dasd_alias_handle_summary_unit_check(device, irb);
                return;
@@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
        /* loss of device reservation is handled via base devices only
         * as alias devices may be used with several bases
         */
-       if (device->block && (sense[7] == 0x3F) &&
+       if (device->block && (sense[27] & DASD_SENSE_BIT_0) &&
+           (sense[7] == 0x3F) &&
            (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
            test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
                if (device->features & DASD_FEATURE_FAILONSLCK)
index 5505bc07e1e7cccccb84549943d89b772533d199..19a1ff03d65ef25c5320585c04064916827a41bb 100644 (file)
@@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block)
        if (base->features & DASD_FEATURE_READONLY ||
            test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
                set_disk_ro(gdp, 1);
-       gdp->private_data = block;
+       dasd_add_link_to_gendisk(gdp, base);
        gdp->queue = block->request_queue;
        block->gdp = gdp;
        set_capacity(block->gdp, 0);
index df9f6999411def84414938e65df42d699b33bfcc..d1e4f2c1264c54225a70307b0830343a5e5c5f0c 100644 (file)
@@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
 struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
 struct dasd_device *dasd_device_from_devindex(int);
 
+void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *);
+struct dasd_device *dasd_device_from_gendisk(struct gendisk *);
+
 int dasd_parse(void);
 int dasd_busid_known(const char *);
 
index 26075e95b1bad786db8ff7b0e8504521fe8f3d68..72261e4c516de89e836a2afb3d646d24b947ecfd 100644 (file)
@@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp)
 static int
 dasd_ioctl_enable(struct block_device *bdev)
 {
-       struct dasd_block *block = bdev->bd_disk->private_data;
+       struct dasd_device *base;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       dasd_enable_device(block->base);
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
+
+       dasd_enable_device(base);
        /* Formatting the dasd device can change the capacity. */
        mutex_lock(&bdev->bd_mutex);
-       i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
+       i_size_write(bdev->bd_inode,
+                    (loff_t)get_capacity(base->block->gdp) << 9);
        mutex_unlock(&bdev->bd_mutex);
+       dasd_put_device(base);
        return 0;
 }
 
@@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev)
 static int
 dasd_ioctl_disable(struct block_device *bdev)
 {
-       struct dasd_block *block = bdev->bd_disk->private_data;
+       struct dasd_device *base;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
        /*
         * Man this is sick. We don't do a real disable but only downgrade
         * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
@@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev)
         * using the BIODASDFMT ioctl. Therefore the correct state for the
         * device is DASD_STATE_BASIC that allows to do basic i/o.
         */
-       dasd_set_target_state(block->base, DASD_STATE_BASIC);
+       dasd_set_target_state(base, DASD_STATE_BASIC);
        /*
         * Set i_size to zero, since read, write, etc. check against this
         * value.
@@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev)
        mutex_lock(&bdev->bd_mutex);
        i_size_write(bdev->bd_inode, 0);
        mutex_unlock(&bdev->bd_mutex);
+       dasd_put_device(base);
        return 0;
 }
 
@@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
 static int
 dasd_ioctl_format(struct block_device *bdev, void __user *argp)
 {
-       struct dasd_block *block = bdev->bd_disk->private_data;
+       struct dasd_device *base;
        struct format_data_t fdata;
+       int rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
        if (!argp)
                return -EINVAL;
-
-       if (block->base->features & DASD_FEATURE_READONLY ||
-           test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
+       if (base->features & DASD_FEATURE_READONLY ||
+           test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
+               dasd_put_device(base);
                return -EROFS;
-       if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
+       }
+       if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) {
+               dasd_put_device(base);
                return -EFAULT;
+       }
        if (bdev != bdev->bd_contains) {
                pr_warning("%s: The specified DASD is a partition and cannot "
                           "be formatted\n",
-                          dev_name(&block->base->cdev->dev));
+                          dev_name(&base->cdev->dev));
+               dasd_put_device(base);
                return -EINVAL;
        }
-       return dasd_format(block, &fdata);
+       rc = dasd_format(base->block, &fdata);
+       dasd_put_device(base);
+       return rc;
 }
 
 #ifdef CONFIG_DASD_PROFILE
@@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block,
 static int
 dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
 {
-       struct dasd_block *block =  bdev->bd_disk->private_data;
-       int intval;
+       struct dasd_device *base;
+       int intval, rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
                return -EINVAL;
        if (get_user(intval, (int __user *)argp))
                return -EFAULT;
-       if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
+       if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
+               dasd_put_device(base);
                return -EROFS;
+       }
        set_disk_ro(bdev->bd_disk, intval);
-       return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
+       rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval);
+       dasd_put_device(base);
+       return rc;
 }
 
 static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
@@ -372,59 +399,78 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
 int dasd_ioctl(struct block_device *bdev, fmode_t mode,
               unsigned int cmd, unsigned long arg)
 {
-       struct dasd_block *block = bdev->bd_disk->private_data;
+       struct dasd_block *block;
+       struct dasd_device *base;
        void __user *argp;
+       int rc;
 
        if (is_compat_task())
                argp = compat_ptr(arg);
        else
                argp = (void __user *)arg;
 
-       if (!block)
-                return -ENODEV;
-
        if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
                PRINT_DEBUG("empty data ptr");
                return -EINVAL;
        }
 
+       base = dasd_device_from_gendisk(bdev->bd_disk);
+       if (!base)
+               return -ENODEV;
+       block = base->block;
+       rc = 0;
        switch (cmd) {
        case BIODASDDISABLE:
-               return dasd_ioctl_disable(bdev);
+               rc = dasd_ioctl_disable(bdev);
+               break;
        case BIODASDENABLE:
-               return dasd_ioctl_enable(bdev);
+               rc = dasd_ioctl_enable(bdev);
+               break;
        case BIODASDQUIESCE:
-               return dasd_ioctl_quiesce(block);
+               rc = dasd_ioctl_quiesce(block);
+               break;
        case BIODASDRESUME:
-               return dasd_ioctl_resume(block);
+               rc = dasd_ioctl_resume(block);
+               break;
        case BIODASDFMT:
-               return dasd_ioctl_format(bdev, argp);
+               rc = dasd_ioctl_format(bdev, argp);
+               break;
        case BIODASDINFO:
-               return dasd_ioctl_information(block, cmd, argp);
+               rc = dasd_ioctl_information(block, cmd, argp);
+               break;
        case BIODASDINFO2:
-               return dasd_ioctl_information(block, cmd, argp);
+               rc = dasd_ioctl_information(block, cmd, argp);
+               break;
        case BIODASDPRRD:
-               return dasd_ioctl_read_profile(block, argp);
+               rc = dasd_ioctl_read_profile(block, argp);
+               break;
        case BIODASDPRRST:
-               return dasd_ioctl_reset_profile(block);
+               rc = dasd_ioctl_reset_profile(block);
+               break;
        case BLKROSET:
-               return dasd_ioctl_set_ro(bdev, argp);
+               rc = dasd_ioctl_set_ro(bdev, argp);
+               break;
        case DASDAPIVER:
-               return dasd_ioctl_api_version(argp);
+               rc = dasd_ioctl_api_version(argp);
+               break;
        case BIODASDCMFENABLE:
-               return enable_cmf(block->base->cdev);
+               rc = enable_cmf(base->cdev);
+               break;
        case BIODASDCMFDISABLE:
-               return disable_cmf(block->base->cdev);
+               rc = disable_cmf(base->cdev);
+               break;
        case BIODASDREADALLCMB:
-               return dasd_ioctl_readall_cmb(block, cmd, argp);
+               rc = dasd_ioctl_readall_cmb(block, cmd, argp);
+               break;
        default:
                /* if the discipline has an ioctl method try it. */
-               if (block->base->discipline->ioctl) {
-                       int rval = block->base->discipline->ioctl(block, cmd, argp);
-                       if (rval != -ENOIOCTLCMD)
-                               return rval;
-               }
-
-               return -EINVAL;
+               if (base->discipline->ioctl) {
+                       rc = base->discipline->ioctl(block, cmd, argp);
+                       if (rc == -ENOIOCTLCMD)
+                               rc = -EINVAL;
+               } else
+                       rc = -EINVAL;
        }
+       dasd_put_device(base);
+       return rc;
 }
index c532ba929ccde2c0c802edcf4ad870a7a78cf484..e8f267eb88873b2a65e8d0cb05bcce3dc5c2c33c 100644 (file)
@@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count)
        q->q_stats.nr_sbals[pos]++;
 }
 
-static void announce_buffer_error(struct qdio_q *q, int count)
+static void process_buffer_error(struct qdio_q *q, int count)
 {
+       unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT :
+                                       SLSB_P_OUTPUT_NOT_INIT;
+
        q->qdio_error |= QDIO_ERROR_SLSB_STATE;
 
        /* special handling for no target buffer empty */
@@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count)
        DBF_ERROR("F14:%2x F15:%2x",
                  q->sbal[q->first_to_check]->element[14].flags & 0xff,
                  q->sbal[q->first_to_check]->element[15].flags & 0xff);
+
+       /*
+        * Interrupts may be avoided as long as the error is present
+        * so change the buffer state immediately to avoid starvation.
+        */
+       set_buf_states(q, q->first_to_check, state, count);
 }
 
 static inline void inbound_primed(struct qdio_q *q, int count)
@@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
                        account_sbals(q, count);
                break;
        case SLSB_P_INPUT_ERROR:
-               announce_buffer_error(q, count);
-               /* process the buffer, the upper layer will take care of it */
+               process_buffer_error(q, count);
                q->first_to_check = add_buf(q->first_to_check, count);
                atomic_sub(count, &q->nr_buf_used);
                if (q->irq_ptr->perf_stat_enabled)
@@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
                        account_sbals(q, count);
                break;
        case SLSB_P_OUTPUT_ERROR:
-               announce_buffer_error(q, count);
-               /* process the buffer, the upper layer will take care of it */
+               process_buffer_error(q, count);
                q->first_to_check = add_buf(q->first_to_check, count);
                atomic_sub(count, &q->nr_buf_used);
                if (q->irq_ptr->perf_stat_enabled)
index 414427d64a8ff6f46b3b7e375c7db97a95a66dac..607998f0b7d8580c05c4fec47cf672bfad9d3c14 100644 (file)
@@ -381,10 +381,10 @@ static void kvm_extint_handler(unsigned int ext_int_code,
        u16 subcode;
        u32 param;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++;
        subcode = ext_int_code >> 16;
        if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
                return;
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++;
 
        /* The LSB might be overloaded, we have to mask it */
        vq = (struct virtqueue *)(param64 & ~1UL);
index 564e6ecd17c2d1feb7e9330aa129464f8b714bf0..0119b814779744ccfc448bceddcaac3a7e195fcc 100644 (file)
@@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
        unsigned long flags;
        struct scsi_device *sdev;
        struct scsi_device_handler *scsi_dh = NULL;
+       struct device *dev = NULL;
 
        spin_lock_irqsave(q->queue_lock, flags);
        sdev = q->queuedata;
        if (sdev && sdev->scsi_dh_data)
                scsi_dh = sdev->scsi_dh_data->scsi_dh;
-       if (!scsi_dh || !get_device(&sdev->sdev_gendev) ||
+       dev = get_device(&sdev->sdev_gendev);
+       if (!scsi_dh || !dev ||
            sdev->sdev_state == SDEV_CANCEL ||
            sdev->sdev_state == SDEV_DEL)
                err = SCSI_DH_NOSYS;
@@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
        if (err) {
                if (fn)
                        fn(data, err);
-               return err;
+               goto out;
        }
 
        if (scsi_dh->activate)
                err = scsi_dh->activate(sdev, fn, data);
-       put_device(&sdev->sdev_gendev);
+out:
+       put_device(dev);
        return err;
 }
 EXPORT_SYMBOL_GPL(scsi_dh_activate);
index 1c6d2b405eefb49e9913b48c2015c12028161971..d72f1f2b1392eb5c49ba5efd5f3fae06e69b0b3d 100644 (file)
@@ -688,6 +688,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                goto out;
        }
 
+       /* Check for overflow and wraparound */
+       if (karg.data_sge_offset * 4 > ioc->request_sz ||
+           karg.data_sge_offset > (UINT_MAX / 4)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        /* copy in request message frame from user */
        if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
                printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
@@ -1963,7 +1970,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
        Mpi2DiagBufferPostReply_t *mpi_reply;
        int rc, i;
        u8 buffer_type;
-       unsigned long timeleft;
+       unsigned long timeleft, request_size, copy_size;
        u16 smid;
        u16 ioc_status;
        u8 issue_reset = 0;
@@ -1999,6 +2006,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
                return -ENOMEM;
        }
 
+       request_size = ioc->diag_buffer_sz[buffer_type];
+
        if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
                printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "
                    "or bytes_to_read are not 4 byte aligned\n", ioc->name,
@@ -2006,13 +2015,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
                return -EINVAL;
        }
 
+       if (karg.starting_offset > request_size)
+               return -EINVAL;
+
        diag_data = (void *)(request_data + karg.starting_offset);
        dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "
            "offset(%d), sz(%d)\n", ioc->name, __func__,
            diag_data, karg.starting_offset, karg.bytes_to_read));
 
+       /* Truncate data on requests that are too large */
+       if ((diag_data + karg.bytes_to_read < diag_data) ||
+           (diag_data + karg.bytes_to_read > request_data + request_size))
+               copy_size = request_size - karg.starting_offset;
+       else
+               copy_size = karg.bytes_to_read;
+
        if (copy_to_user((void __user *)uarg->diagnostic_data,
-           diag_data, karg.bytes_to_read)) {
+           diag_data, copy_size)) {
                printk(MPT2SAS_ERR_FMT "%s: Unable to write "
                    "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
                    __func__, diag_data);
index 96d5ad0c1e420ed61c8f2b673997284e3b65bf4b..7f636b118287a7bb0f9e3ac7d1cdecb27ed0598d 100644 (file)
@@ -3814,6 +3814,9 @@ static long pmcraid_ioctl_passthrough(
                        rc = -EFAULT;
                        goto out_free_buffer;
                }
+       } else if (request_size < 0) {
+               rc = -EINVAL;
+               goto out_free_buffer;
        }
 
        /* check if we have any additional command parameters */
index 6d5c7ff43f5bdaf1984a62696e8acb03cdead3c5..0bac91e72370725cb79d8320b3a9daba01b1114c 100644 (file)
@@ -400,10 +400,15 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost)
 static void scsi_run_queue(struct request_queue *q)
 {
        struct scsi_device *sdev = q->queuedata;
-       struct Scsi_Host *shost = sdev->host;
+       struct Scsi_Host *shost;
        LIST_HEAD(starved_list);
        unsigned long flags;
 
+       /* if the device is dead, sdev will be NULL, so no queue to run */
+       if (!sdev)
+               return;
+
+       shost = sdev->host;
        if (scsi_target(sdev)->single_lun)
                scsi_single_lun_run(sdev);
 
@@ -411,8 +416,6 @@ static void scsi_run_queue(struct request_queue *q)
        list_splice_init(&shost->starved_list, &starved_list);
 
        while (!list_empty(&starved_list)) {
-               int flagset;
-
                /*
                 * As long as shost is accepting commands and we have
                 * starved queues, call blk_run_queue. scsi_request_fn
@@ -435,20 +438,7 @@ static void scsi_run_queue(struct request_queue *q)
                        continue;
                }
 
-               spin_unlock(shost->host_lock);
-
-               spin_lock(sdev->request_queue->queue_lock);
-               flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
-                               !test_bit(QUEUE_FLAG_REENTER,
-                                       &sdev->request_queue->queue_flags);
-               if (flagset)
-                       queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue);
-               __blk_run_queue(sdev->request_queue, false);
-               if (flagset)
-                       queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);
-               spin_unlock(sdev->request_queue->queue_lock);
-
-               spin_lock(shost->host_lock);
+               blk_run_queue_async(sdev->request_queue);
        }
        /* put any unprocessed entries back */
        list_splice(&starved_list, &shost->starved_list);
index e44ff64233fd5fbe00a4aa675081bcac319739af..e63912510fb9349b31ede55df1c0b20011b6235e 100644 (file)
@@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
                kfree(evt);
        }
 
-       if (sdev->request_queue) {
-               sdev->request_queue->queuedata = NULL;
-               /* user context needed to free queue */
-               scsi_free_queue(sdev->request_queue);
-               /* temporary expedient, try to catch use of queue lock
-                * after free of sdev */
-               sdev->request_queue = NULL;
-       }
+       /* NULL queue means the device can't be used */
+       sdev->request_queue = NULL;
 
        scsi_target_reap(scsi_target(sdev));
 
@@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev)
        if (sdev->host->hostt->slave_destroy)
                sdev->host->hostt->slave_destroy(sdev);
        transport_destroy_device(dev);
+
+       /* cause the request function to reject all I/O requests */
+       sdev->request_queue->queuedata = NULL;
+
+       /* Freeing the queue signals to block that we're done */
+       scsi_free_queue(sdev->request_queue);
        put_device(dev);
 }
 
index fdf3fa639056c42a61a099d2d6a69cc68c6caaa2..815069d13f9b57edc5ddaf22dbb223c452d74811 100644 (file)
@@ -3816,28 +3816,17 @@ fail_host_msg:
 static void
 fc_bsg_goose_queue(struct fc_rport *rport)
 {
-       int flagset;
-       unsigned long flags;
-
        if (!rport->rqst_q)
                return;
 
+       /*
+        * This get/put dance makes no sense
+        */
        get_device(&rport->dev);
-
-       spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
-       flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
-                 !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
-       if (flagset)
-               queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q);
-       __blk_run_queue(rport->rqst_q, false);
-       if (flagset)
-               queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
-       spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
-
+       blk_run_queue_async(rport->rqst_q);
        put_device(&rport->dev);
 }
 
-
 /**
  * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD
  * @q:         rport request queue
index dca4a0bb6ca9f1523f187a5eaddd90f19731a08b..e3786f161bc34676294d89a1bfa2182bf64e44c9 100644 (file)
@@ -131,8 +131,6 @@ source "drivers/staging/wlags49_h2/Kconfig"
 
 source "drivers/staging/wlags49_h25/Kconfig"
 
-source "drivers/staging/samsung-laptop/Kconfig"
-
 source "drivers/staging/sm7xx/Kconfig"
 
 source "drivers/staging/dt3155v4l/Kconfig"
index eb93012b6f5936a7648b6c396cac77ae15879f20..f0d5c53156123e15b73d91368f85e56d75237284 100644 (file)
@@ -48,7 +48,6 @@ obj-$(CONFIG_XVMALLOC)                += zram/
 obj-$(CONFIG_ZCACHE)           += zcache/
 obj-$(CONFIG_WLAGS49_H2)       += wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)      += wlags49_h25/
-obj-$(CONFIG_SAMSUNG_LAPTOP)   += samsung-laptop/
 obj-$(CONFIG_FB_SM7XX)         += sm7xx/
 obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l/
 obj-$(CONFIG_CRYSTALHD)                += crystalhd/
index eeb7dd43f9a8ef9128487fd977761d1fae8fbdf7..830822f86e410183c77641bddc9fbe6a29e54194 100644 (file)
@@ -2288,7 +2288,3 @@ err_dev:
        free_netdev(dev);
        return NULL;
 }
-
-EXPORT_SYMBOL(init_ft1000_card);
-EXPORT_SYMBOL(stop_ft1000_card);
-EXPORT_SYMBOL(flarion_ft1000_cnt);
index 935608e72007e25cb075f10f2940ba0977ea3ff0..bdfb1aec58df8a52eb7e42b60d698086abe19825 100644 (file)
@@ -214,6 +214,3 @@ void ft1000CleanupProc(struct net_device *dev)
        remove_proc_entry(FT1000_PROC, init_net.proc_net);
        unregister_netdevice_notifier(&ft1000_netdev_notifier);
 }
-
-EXPORT_SYMBOL(ft1000InitProc);
-EXPORT_SYMBOL(ft1000CleanupProc);
index 5501eb9b3355050eb33526829c51e0e9c94d2fa3..ce8bedaeaac21589f84768e4788bbc4939b36488 100644 (file)
@@ -1,6 +1,6 @@
 config DRM_PSB
        tristate "Intel GMA500 KMS Framebuffer"
-       depends on DRM && PCI
+       depends on DRM && PCI && X86
        select FB_CFB_COPYAREA
         select FB_CFB_FILLRECT
         select FB_CFB_IMAGEBLIT
index e9c182108243316bca5bc2fdf3b50d3733cdc971..971588ce26d3dd44ae5f726b427898e1676b3023 100644 (file)
@@ -508,7 +508,6 @@ int register_sst_card(struct intel_sst_card_ops *card)
                        sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
                        sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
                        card->pcm_control = sst_pmic_ops.pcm_control;
-                       sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
                        return 0;
                } else {
                        pr_err("strcmp fail %s\n", card->module_name);
index d207636a7b6d9ffb28dfb22f5745df8ee4235bb5..ebb6d03552c4b5282cb748d6ce429fd5c1f9bf3c 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/firmware.h>
 #include <sound/control.h>
 #include <asm/mrst.h>
 #include <sound/pcm.h>
@@ -40,6 +41,8 @@
 #include <sound/initval.h>
 #include "intel_sst.h"
 #include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
 #include "intelmid_snd_control.h"
 #include "intelmid.h"
 
@@ -802,6 +805,7 @@ static int __devinit snd_intelmad_sst_register(
                pr_err("sst card registration failed\n");
                return ret_val;
        }
+       sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
 
        sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
        intelmaddata->pmic_status = PMIC_UNINIT;
index 9cc15c1c18d48277f95d8debb8065e46ec541f59..1ea81421805940acca598367a5fe6d3bba43d945 100644 (file)
@@ -28,6 +28,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <linux/file.h>
 #include <asm/mrst.h>
 #include <sound/pcm.h>
index 26d815a67eb836906cd72b3c7553b07fc85ab77b..3c6b3abff3c3e3757fadc8b9a0f43b2895ff8bb6 100644 (file)
@@ -29,6 +29,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <linux/file.h>
 #include "intel_sst.h"
 #include "intelmid_snd_control.h"
index b5d21f6497f9ef14aa4176550615a6203c6a11c8..22c04eabed4116768959b10681c4c880c0940c7c 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/cs5535.h>
 #include <linux/gpio.h>
+#include <linux/delay.h>
 #include <asm/olpc.h>
 
 #include "olpc_dcon.h"
index bef0bbd8cef75f17027768416388be2424d93233..f01a51c381f1d9e218b65ff79724bfb966250050 100644 (file)
@@ -444,7 +444,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd,
                        return (NDIS_STATUS_FAILURE);
                }
        }
-       /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */
+       /* Drop not U2M frames, can't drop here because we will drop beacon in this case */
        /* I am kind of doubting the U2M bit operation */
        /* if (pRxD->U2M == 0) */
        /*      return(NDIS_STATUS_FAILURE); */
index 5637857ae9eb7c7ab9b304857291e1ea6e1785da..83a62faa7e5731255f793bbe873b52f2f95d54fc 100644 (file)
@@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd,
                DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n"));
                return NDIS_STATUS_FAILURE;
        }
-       /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */
+       /* Drop not U2M frames, can't drop here because we will drop beacon in this case */
        /* I am kind of doubting the U2M bit operation */
        /* if (pRxD->U2M == 0) */
        /*      return(NDIS_STATUS_FAILURE); */
index e1408b0e7ae4e33a90a49af8d202d51683f81cca..ab305be96fb5d34e78117b5f4ecddab263adc2a4 100644 (file)
@@ -28,7 +28,7 @@
 
 #define RTSX_STOR "rts_pstor: "
 
-#if CONFIG_RTS_PSTOR_DEBUG
+#ifdef CONFIG_RTS_PSTOR_DEBUG
 #define RTSX_DEBUGP(x...) printk(KERN_DEBUG RTSX_STOR x)
 #define RTSX_DEBUGPN(x...) printk(KERN_DEBUG x)
 #define RTSX_DEBUGPX(x...) printk(x)
index 810e170894f58c3d3180047084dacc31014ec6cd..d89795c6a3ac2545be028198604443b3f37debe0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/blkdev.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
 #include "rtsx.h"
 #include "rtsx_transport.h"
index d2f1c715a684201eae59e646ead22096bb154033..4e60780ea80412b7992e1a46b37da22b284ea214 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kthread.h>
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/vmalloc.h>
 
 #include "rtsx.h"
 #include "rtsx_transport.h"
@@ -1311,11 +1312,11 @@ void rtsx_polling_func(struct rtsx_chip *chip)
 
 #ifdef SUPPORT_OCP
        if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
-               #if CONFIG_RTS_PSTOR_DEBUG
+#ifdef CONFIG_RTS_PSTOR_DEBUG
                if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) {
                        RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat);
                }
-               #endif
+#endif
 
                if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
                        if (chip->card_exist & SD_CARD) {
index 20c2464a20f9cf7f421d600d7326f5ccb802b5b7..7de1fae443fce559780a97af49cf32352dc3205e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/blkdev.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
 #include "rtsx.h"
 #include "rtsx_transport.h"
index 8d066bd428c4ad94e4785a974c2b98c2acceddb0..b1277a6c7a8b857dd602ee610a764ab7810ec099 100644 (file)
@@ -909,7 +909,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir)
                RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
                RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0);
        } else {
-#if CONFIG_RTS_PSTOR_DEBUG
+#ifdef CONFIG_RTS_PSTOR_DEBUG
                rtsx_read_register(chip, SD_VP_CTL, &val);
                RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val);
                rtsx_read_register(chip, SD_DCMPS_CTL, &val);
@@ -958,7 +958,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir)
        return STATUS_SUCCESS;
 
 Fail:
-#if CONFIG_RTS_PSTOR_DEBUG
+#ifdef CONFIG_RTS_PSTOR_DEBUG
        rtsx_read_register(chip, SD_VP_CTL, &val);
        RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val);
        rtsx_read_register(chip, SD_DCMPS_CTL, &val);
index 2c668bae6ff47ea66afc3d74f7897ba06b4aafa6..bc83b49a4eb4a975cdc286c484b08e4d4698a39e 100644 (file)
@@ -82,7 +82,7 @@ do {                                                                                                  \
 #define TRACE_GOTO(chip, label)        goto label
 #endif
 
-#if CONFIG_RTS_PSTOR_DEBUG
+#ifdef CONFIG_RTS_PSTOR_DEBUG
 static inline void rtsx_dump(u8 *buf, int buf_len)
 {
        int i;
index 7bcd468b8f2c2f15fff7e53cae3ce63b322c0bf6..9f3add1e8f59d885564703688df6d76554d228c6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/blkdev.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
 #include "rtsx.h"
 #include "rtsx_transport.h"
diff --git a/drivers/staging/samsung-laptop/Kconfig b/drivers/staging/samsung-laptop/Kconfig
deleted file mode 100644 (file)
index f27c608..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config SAMSUNG_LAPTOP
-       tristate "Samsung Laptop driver"
-       default n
-       depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
-       help
-         This module implements a driver for the N128 Samsung Laptop
-         providing control over the Wireless LED and the LCD backlight
-
-         To compile this driver as a module, choose
-         M here: the module will be called samsung-laptop.
diff --git a/drivers/staging/samsung-laptop/Makefile b/drivers/staging/samsung-laptop/Makefile
deleted file mode 100644 (file)
index 3c6f420..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SAMSUNG_LAPTOP)   += samsung-laptop.o
diff --git a/drivers/staging/samsung-laptop/TODO b/drivers/staging/samsung-laptop/TODO
deleted file mode 100644 (file)
index f7a6d58..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-TODO:
-       - review from other developers
-       - figure out ACPI video issues
-
-Please send patches to Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
deleted file mode 100644 (file)
index 2529446..0000000
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Samsung Laptop driver
- *
- * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
- * Copyright (C) 2009,2011 Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <linux/dmi.h>
-#include <linux/platform_device.h>
-#include <linux/rfkill.h>
-
-/*
- * This driver is needed because a number of Samsung laptops do not hook
- * their control settings through ACPI.  So we have to poke around in the
- * BIOS to do things like brightness values, and "special" key controls.
- */
-
-/*
- * We have 0 - 8 as valid brightness levels.  The specs say that level 0 should
- * be reserved by the BIOS (which really doesn't make much sense), we tell
- * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
- */
-#define MAX_BRIGHT     0x07
-
-
-#define SABI_IFACE_MAIN                        0x00
-#define SABI_IFACE_SUB                 0x02
-#define SABI_IFACE_COMPLETE            0x04
-#define SABI_IFACE_DATA                        0x05
-
-/* Structure to get data back to the calling function */
-struct sabi_retval {
-       u8 retval[20];
-};
-
-struct sabi_header_offsets {
-       u8 port;
-       u8 re_mem;
-       u8 iface_func;
-       u8 en_mem;
-       u8 data_offset;
-       u8 data_segment;
-};
-
-struct sabi_commands {
-       /*
-        * Brightness is 0 - 8, as described above.
-        * Value 0 is for the BIOS to use
-        */
-       u8 get_brightness;
-       u8 set_brightness;
-
-       /*
-        * first byte:
-        * 0x00 - wireless is off
-        * 0x01 - wireless is on
-        * second byte:
-        * 0x02 - 3G is off
-        * 0x03 - 3G is on
-        * TODO, verify 3G is correct, that doesn't seem right...
-        */
-       u8 get_wireless_button;
-       u8 set_wireless_button;
-
-       /* 0 is off, 1 is on */
-       u8 get_backlight;
-       u8 set_backlight;
-
-       /*
-        * 0x80 or 0x00 - no action
-        * 0x81 - recovery key pressed
-        */
-       u8 get_recovery_mode;
-       u8 set_recovery_mode;
-
-       /*
-        * on seclinux: 0 is low, 1 is high,
-        * on swsmi: 0 is normal, 1 is silent, 2 is turbo
-        */
-       u8 get_performance_level;
-       u8 set_performance_level;
-
-       /*
-        * Tell the BIOS that Linux is running on this machine.
-        * 81 is on, 80 is off
-        */
-       u8 set_linux;
-};
-
-struct sabi_performance_level {
-       const char *name;
-       u8 value;
-};
-
-struct sabi_config {
-       const char *test_string;
-       u16 main_function;
-       const struct sabi_header_offsets header_offsets;
-       const struct sabi_commands commands;
-       const struct sabi_performance_level performance_levels[4];
-       u8 min_brightness;
-       u8 max_brightness;
-};
-
-static const struct sabi_config sabi_configs[] = {
-       {
-               .test_string = "SECLINUX",
-
-               .main_function = 0x4c49,
-
-               .header_offsets = {
-                       .port = 0x00,
-                       .re_mem = 0x02,
-                       .iface_func = 0x03,
-                       .en_mem = 0x04,
-                       .data_offset = 0x05,
-                       .data_segment = 0x07,
-               },
-
-               .commands = {
-                       .get_brightness = 0x00,
-                       .set_brightness = 0x01,
-
-                       .get_wireless_button = 0x02,
-                       .set_wireless_button = 0x03,
-
-                       .get_backlight = 0x04,
-                       .set_backlight = 0x05,
-
-                       .get_recovery_mode = 0x06,
-                       .set_recovery_mode = 0x07,
-
-                       .get_performance_level = 0x08,
-                       .set_performance_level = 0x09,
-
-                       .set_linux = 0x0a,
-               },
-
-               .performance_levels = {
-                       {
-                               .name = "silent",
-                               .value = 0,
-                       },
-                       {
-                               .name = "normal",
-                               .value = 1,
-                       },
-                       { },
-               },
-               .min_brightness = 1,
-               .max_brightness = 8,
-       },
-       {
-               .test_string = "SwSmi@",
-
-               .main_function = 0x5843,
-
-               .header_offsets = {
-                       .port = 0x00,
-                       .re_mem = 0x04,
-                       .iface_func = 0x02,
-                       .en_mem = 0x03,
-                       .data_offset = 0x05,
-                       .data_segment = 0x07,
-               },
-
-               .commands = {
-                       .get_brightness = 0x10,
-                       .set_brightness = 0x11,
-
-                       .get_wireless_button = 0x12,
-                       .set_wireless_button = 0x13,
-
-                       .get_backlight = 0x2d,
-                       .set_backlight = 0x2e,
-
-                       .get_recovery_mode = 0xff,
-                       .set_recovery_mode = 0xff,
-
-                       .get_performance_level = 0x31,
-                       .set_performance_level = 0x32,
-
-                       .set_linux = 0xff,
-               },
-
-               .performance_levels = {
-                       {
-                               .name = "normal",
-                               .value = 0,
-                       },
-                       {
-                               .name = "silent",
-                               .value = 1,
-                       },
-                       {
-                               .name = "overclock",
-                               .value = 2,
-                       },
-                       { },
-               },
-               .min_brightness = 0,
-               .max_brightness = 8,
-       },
-       { },
-};
-
-static const struct sabi_config *sabi_config;
-
-static void __iomem *sabi;
-static void __iomem *sabi_iface;
-static void __iomem *f0000_segment;
-static struct backlight_device *backlight_device;
-static struct mutex sabi_mutex;
-static struct platform_device *sdev;
-static struct rfkill *rfk;
-
-static int force;
-module_param(force, bool, 0);
-MODULE_PARM_DESC(force,
-               "Disable the DMI check and forces the driver to be loaded");
-
-static int debug;
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-static int sabi_get_command(u8 command, struct sabi_retval *sretval)
-{
-       int retval = 0;
-       u16 port = readw(sabi + sabi_config->header_offsets.port);
-       u8 complete, iface_data;
-
-       mutex_lock(&sabi_mutex);
-
-       /* enable memory to be able to write to it */
-       outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
-
-       /* write out the command */
-       writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-       writew(command, sabi_iface + SABI_IFACE_SUB);
-       writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-       outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
-
-       /* write protect memory to make it safe */
-       outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
-
-       /* see if the command actually succeeded */
-       complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-       iface_data = readb(sabi_iface + SABI_IFACE_DATA);
-       if (complete != 0xaa || iface_data == 0xff) {
-               pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-                       command, complete, iface_data);
-               retval = -EINVAL;
-               goto exit;
-       }
-       /*
-        * Save off the data into a structure so the caller use it.
-        * Right now we only want the first 4 bytes,
-        * There are commands that need more, but not for the ones we
-        * currently care about.
-        */
-       sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
-       sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
-       sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
-       sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
-
-exit:
-       mutex_unlock(&sabi_mutex);
-       return retval;
-
-}
-
-static int sabi_set_command(u8 command, u8 data)
-{
-       int retval = 0;
-       u16 port = readw(sabi + sabi_config->header_offsets.port);
-       u8 complete, iface_data;
-
-       mutex_lock(&sabi_mutex);
-
-       /* enable memory to be able to write to it */
-       outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
-
-       /* write out the command */
-       writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-       writew(command, sabi_iface + SABI_IFACE_SUB);
-       writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-       writeb(data, sabi_iface + SABI_IFACE_DATA);
-       outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
-
-       /* write protect memory to make it safe */
-       outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
-
-       /* see if the command actually succeeded */
-       complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-       iface_data = readb(sabi_iface + SABI_IFACE_DATA);
-       if (complete != 0xaa || iface_data == 0xff) {
-               pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-                      command, complete, iface_data);
-               retval = -EINVAL;
-       }
-
-       mutex_unlock(&sabi_mutex);
-       return retval;
-}
-
-static void test_backlight(void)
-{
-       struct sabi_retval sretval;
-
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-       sabi_set_command(sabi_config->commands.set_backlight, 0);
-       printk(KERN_DEBUG "backlight should be off\n");
-
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-       msleep(1000);
-
-       sabi_set_command(sabi_config->commands.set_backlight, 1);
-       printk(KERN_DEBUG "backlight should be on\n");
-
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-}
-
-static void test_wireless(void)
-{
-       struct sabi_retval sretval;
-
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-       sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-       printk(KERN_DEBUG "wireless led should be off\n");
-
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-       msleep(1000);
-
-       sabi_set_command(sabi_config->commands.set_wireless_button, 1);
-       printk(KERN_DEBUG "wireless led should be on\n");
-
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-}
-
-static u8 read_brightness(void)
-{
-       struct sabi_retval sretval;
-       int user_brightness = 0;
-       int retval;
-
-       retval = sabi_get_command(sabi_config->commands.get_brightness,
-                                 &sretval);
-       if (!retval) {
-               user_brightness = sretval.retval[0];
-               if (user_brightness != 0)
-                       user_brightness -= sabi_config->min_brightness;
-       }
-       return user_brightness;
-}
-
-static void set_brightness(u8 user_brightness)
-{
-       u8 user_level = user_brightness - sabi_config->min_brightness;
-
-       sabi_set_command(sabi_config->commands.set_brightness, user_level);
-}
-
-static int get_brightness(struct backlight_device *bd)
-{
-       return (int)read_brightness();
-}
-
-static int update_status(struct backlight_device *bd)
-{
-       set_brightness(bd->props.brightness);
-
-       if (bd->props.power == FB_BLANK_UNBLANK)
-               sabi_set_command(sabi_config->commands.set_backlight, 1);
-       else
-               sabi_set_command(sabi_config->commands.set_backlight, 0);
-       return 0;
-}
-
-static const struct backlight_ops backlight_ops = {
-       .get_brightness = get_brightness,
-       .update_status  = update_status,
-};
-
-static int rfkill_set(void *data, bool blocked)
-{
-       /* Do something with blocked...*/
-       /*
-        * blocked == false is on
-        * blocked == true is off
-        */
-       if (blocked)
-               sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-       else
-               sabi_set_command(sabi_config->commands.set_wireless_button, 1);
-
-       return 0;
-}
-
-static struct rfkill_ops rfkill_ops = {
-       .set_block = rfkill_set,
-};
-
-static int init_wireless(struct platform_device *sdev)
-{
-       int retval;
-
-       rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
-                          &rfkill_ops, NULL);
-       if (!rfk)
-               return -ENOMEM;
-
-       retval = rfkill_register(rfk);
-       if (retval) {
-               rfkill_destroy(rfk);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void destroy_wireless(void)
-{
-       rfkill_unregister(rfk);
-       rfkill_destroy(rfk);
-}
-
-static ssize_t get_performance_level(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
-{
-       struct sabi_retval sretval;
-       int retval;
-       int i;
-
-       /* Read the state */
-       retval = sabi_get_command(sabi_config->commands.get_performance_level,
-                                 &sretval);
-       if (retval)
-               return retval;
-
-       /* The logic is backwards, yeah, lots of fun... */
-       for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-               if (sretval.retval[0] == sabi_config->performance_levels[i].value)
-                       return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
-       }
-       return sprintf(buf, "%s\n", "unknown");
-}
-
-static ssize_t set_performance_level(struct device *dev,
-                               struct device_attribute *attr, const char *buf,
-                               size_t count)
-{
-       if (count >= 1) {
-               int i;
-               for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-                       const struct sabi_performance_level *level =
-                               &sabi_config->performance_levels[i];
-                       if (!strncasecmp(level->name, buf, strlen(level->name))) {
-                               sabi_set_command(sabi_config->commands.set_performance_level,
-                                                level->value);
-                               break;
-                       }
-               }
-               if (!sabi_config->performance_levels[i].name)
-                       return -EINVAL;
-       }
-       return count;
-}
-static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
-                  get_performance_level, set_performance_level);
-
-
-static int __init dmi_check_cb(const struct dmi_system_id *id)
-{
-       pr_info("found laptop model '%s'\n",
-               id->ident);
-       return 0;
-}
-
-static struct dmi_system_id __initdata samsung_dmi_table[] = {
-       {
-               .ident = "N128",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N128"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N130",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N130"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "X125",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X125"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "X120/X170",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "NC10",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
-                       DMI_MATCH(DMI_BOARD_NAME, "NC10"),
-               },
-               .callback = dmi_check_cb,
-       },
-               {
-               .ident = "NP-Q45",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
-                       DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
-               },
-               .callback = dmi_check_cb,
-               },
-       {
-               .ident = "X360",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X360"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R410 Plus",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R460"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R518",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R518"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R519/R719",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N150/N210/N220/N230",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N150P/N210P/N220P",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R530/R730",
-               .matches = {
-                     DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                     DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
-                     DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "NF110/NF210/NF310",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
-                       DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N145P/N250P/N260P",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R70/R71",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "P460",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
-                       DMI_MATCH(DMI_BOARD_NAME, "P460"),
-               },
-               .callback = dmi_check_cb,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
-
-static int find_signature(void __iomem *memcheck, const char *testStr)
-{
-       int i = 0;
-       int loca;
-
-       for (loca = 0; loca < 0xffff; loca++) {
-               char temp = readb(memcheck + loca);
-
-               if (temp == testStr[i]) {
-                       if (i == strlen(testStr)-1)
-                               break;
-                       ++i;
-               } else {
-                       i = 0;
-               }
-       }
-       return loca;
-}
-
-static int __init samsung_init(void)
-{
-       struct backlight_properties props;
-       struct sabi_retval sretval;
-       unsigned int ifaceP;
-       int i;
-       int loca;
-       int retval;
-
-       mutex_init(&sabi_mutex);
-
-       if (!force && !dmi_check_system(samsung_dmi_table))
-               return -ENODEV;
-
-       f0000_segment = ioremap_nocache(0xf0000, 0xffff);
-       if (!f0000_segment) {
-               pr_err("Can't map the segment at 0xf0000\n");
-               return -EINVAL;
-       }
-
-       /* Try to find one of the signatures in memory to find the header */
-       for (i = 0; sabi_configs[i].test_string != 0; ++i) {
-               sabi_config = &sabi_configs[i];
-               loca = find_signature(f0000_segment, sabi_config->test_string);
-               if (loca != 0xffff)
-                       break;
-       }
-
-       if (loca == 0xffff) {
-               pr_err("This computer does not support SABI\n");
-               goto error_no_signature;
-       }
-
-       /* point to the SMI port Number */
-       loca += 1;
-       sabi = (f0000_segment + loca);
-
-       if (debug) {
-               printk(KERN_DEBUG "This computer supports SABI==%x\n",
-                       loca + 0xf0000 - 6);
-               printk(KERN_DEBUG "SABI header:\n");
-               printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.port));
-               printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.iface_func));
-               printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.en_mem));
-               printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.re_mem));
-               printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.data_offset));
-               printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.data_segment));
-       }
-
-       /* Get a pointer to the SABI Interface */
-       ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
-       ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
-       sabi_iface = ioremap_nocache(ifaceP, 16);
-       if (!sabi_iface) {
-               pr_err("Can't remap %x\n", ifaceP);
-               goto exit;
-       }
-       if (debug) {
-               printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
-               printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
-
-               test_backlight();
-               test_wireless();
-
-               retval = sabi_get_command(sabi_config->commands.get_brightness,
-                                         &sretval);
-               printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
-       }
-
-       /* Turn on "Linux" mode in the BIOS */
-       if (sabi_config->commands.set_linux != 0xff) {
-               retval = sabi_set_command(sabi_config->commands.set_linux,
-                                         0x81);
-               if (retval) {
-                       pr_warn("Linux mode was not set!\n");
-                       goto error_no_platform;
-               }
-       }
-
-       /* knock up a platform device to hang stuff off of */
-       sdev = platform_device_register_simple("samsung", -1, NULL, 0);
-       if (IS_ERR(sdev))
-               goto error_no_platform;
-
-       /* create a backlight device to talk to this one */
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.type = BACKLIGHT_PLATFORM;
-       props.max_brightness = sabi_config->max_brightness;
-       backlight_device = backlight_device_register("samsung", &sdev->dev,
-                                                    NULL, &backlight_ops,
-                                                    &props);
-       if (IS_ERR(backlight_device))
-               goto error_no_backlight;
-
-       backlight_device->props.brightness = read_brightness();
-       backlight_device->props.power = FB_BLANK_UNBLANK;
-       backlight_update_status(backlight_device);
-
-       retval = init_wireless(sdev);
-       if (retval)
-               goto error_no_rfk;
-
-       retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
-       if (retval)
-               goto error_file_create;
-
-exit:
-       return 0;
-
-error_file_create:
-       destroy_wireless();
-
-error_no_rfk:
-       backlight_device_unregister(backlight_device);
-
-error_no_backlight:
-       platform_device_unregister(sdev);
-
-error_no_platform:
-       iounmap(sabi_iface);
-
-error_no_signature:
-       iounmap(f0000_segment);
-       return -EINVAL;
-}
-
-static void __exit samsung_exit(void)
-{
-       /* Turn off "Linux" mode in the BIOS */
-       if (sabi_config->commands.set_linux != 0xff)
-               sabi_set_command(sabi_config->commands.set_linux, 0x80);
-
-       device_remove_file(&sdev->dev, &dev_attr_performance_level);
-       backlight_device_unregister(backlight_device);
-       destroy_wireless();
-       iounmap(sabi_iface);
-       iounmap(f0000_segment);
-       platform_device_unregister(sdev);
-}
-
-module_init(samsung_init);
-module_exit(samsung_exit);
-
-MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
-MODULE_DESCRIPTION("Samsung Backlight driver");
-MODULE_LICENSE("GPL");
index 2cf77c9408602964a2c5dfe527bc7dc0d316da4f..03dcac4ea4d064a291d28476de2eb8c71b2d8cdb 100644 (file)
@@ -2,6 +2,7 @@ config SOLO6X10
        tristate "Softlogic 6x10 MPEG codec cards"
        depends on PCI && VIDEO_DEV && SND && I2C
        select VIDEOBUF_DMA_SG
+       select SND_PCM
        ---help---
          This driver supports the Softlogic based MPEG-4 and h.264 codec
          codec cards.
index 20dae73d3b78347064608e1ebdb4c7cd639f68f5..506547b603e1fb0724e703a943193bfb559b9a8c 100644 (file)
@@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which)
        }
        dev->queue->queuedata = dev;
 
-       /* As Linux block layer does't support >4KB hardware sector,  */
+       /* As Linux block layer doesn't support >4KB hardware sector,  */
        /* Here we force report 512 byte hardware sector size to Kernel */
        blk_queue_logical_block_size(dev->queue, 512);
 
index 5cecd237e3f68cae3a1f5cc52ff63b85bb80b285..fe1ef0addb09e4da2cf73f7fe36fac818b2bb436 100644 (file)
@@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis)
         * as a temporary for .dllview record construction.
         * Allocate storage for the whole table.  Add 1 to the section count
         * in case a trampoline section is auto-generated as well as the
-        * size of the trampoline section name so DLLView does't get lost.
+        * size of the trampoline section name so DLLView doesn't get lost.
         */
 
        siz = sym_count * sizeof(struct local_symbol);
index cb24c6d999db0b4fc76160c48cf6952921a56c87..5c3598ec74560c56ce1a33115b1e95e14220a81b 100644 (file)
@@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp,
        spin_lock_irqsave(&bp->lock, flags);
        sx_out(bp, CD186x_CAR, port_No(port));
 
-       /* The Specialix board does't implement the RTS lines.
+       /* The Specialix board doesn't implement the RTS lines.
           They are used to set the IRQ level. Don't touch them. */
        if (sx_crtscts(tty))
                port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
index 0f02a4b12ae4a29b05b68710d178686251acd713..4f4f13321f403866c579dfda8a10451b443ea73c 100644 (file)
@@ -876,8 +876,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
        }
 
        /* kill threads related to this sdev, if v.c. exists */
-       kthread_stop(vdev->ud.tcp_rx);
-       kthread_stop(vdev->ud.tcp_tx);
+       if (vdev->ud.tcp_rx)
+               kthread_stop(vdev->ud.tcp_rx);
+       if (vdev->ud.tcp_tx)
+               kthread_stop(vdev->ud.tcp_tx);
 
        usbip_uinfo("stop threads\n");
 
@@ -949,9 +951,6 @@ static void vhci_device_init(struct vhci_device *vdev)
 {
        memset(vdev, 0, sizeof(*vdev));
 
-       vdev->ud.tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
-       vdev->ud.tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
-
        vdev->ud.side   = USBIP_VHCI;
        vdev->ud.status = VDEV_ST_NULL;
        /* vdev->ud.lock   = SPIN_LOCK_UNLOCKED; */
@@ -1139,7 +1138,7 @@ static int vhci_hcd_probe(struct platform_device *pdev)
                usbip_uerr("create hcd failed\n");
                return -ENOMEM;
        }
-
+       hcd->has_tt = 1;
 
        /* this is private data for vhci_hcd */
        the_controller = hcd_to_vhci(hcd);
index 3f2459f30415ef5ec03e84eedf0417bb712d93e1..e2dadbd5ef1e2707956faa774f3c42ec44c039d4 100644 (file)
@@ -21,6 +21,7 @@
 #include "vhci.h"
 
 #include <linux/in.h>
+#include <linux/kthread.h>
 
 /* TODO: refine locking ?*/
 
@@ -220,13 +221,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
        vdev->ud.tcp_socket = socket;
        vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
-       wake_up_process(vdev->ud.tcp_rx);
-       wake_up_process(vdev->ud.tcp_tx);
-
        spin_unlock(&vdev->ud.lock);
        spin_unlock(&the_controller->lock);
        /* end the lock */
 
+       vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+       vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+
        rh_port_connect(rhport, speed);
 
        return count;
index 6a71f52c59b1f0a575b8ba69aeac20a9fd2c733a..76378397b763355c059ace7b5fe6bdd09abaf80c 100644 (file)
@@ -273,7 +273,7 @@ exit:
 }
 
 int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
-                          u8 key_index)
+                          u8 key_index, bool unicast, bool multicast)
 {
        wlandevice_t *wlandev = dev->ml_priv;
 
index 47f8cdb207f14089fcb2eaa3f284cdb11f58228c..74273e638c0dfce1d0350a14d57502a5692ee7d9 100644 (file)
@@ -1658,8 +1658,12 @@ static void gsm_queue(struct gsm_mux *gsm)
 
        if ((gsm->control & ~PF) == UI)
                gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-       /* generate final CRC with received FCS */
-       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
+       if (gsm->encoding == 0){
+               /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only.
+                           In this case it contain the last piece of data
+                           required to generate final CRC */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
+       }
        if (gsm->fcs != GOOD_FCS) {
                gsm->bad_fcs++;
                if (debug & 4)
index cb36b0d4ef3c8305aa7b4aaa0abb543b0b752dd8..62df72d9f0aa32bef8a58a19f447dea922bdd18a 100644 (file)
@@ -382,12 +382,13 @@ static void imx_start_tx(struct uart_port *port)
 static irqreturn_t imx_rtsint(int irq, void *dev_id)
 {
        struct imx_port *sport = dev_id;
-       unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
+       unsigned int val;
        unsigned long flags;
 
        spin_lock_irqsave(&sport->port.lock, flags);
 
        writel(USR1_RTSD, sport->port.membase + USR1);
+       val = readl(sport->port.membase + USR1) & USR1_RTSS;
        uart_handle_cts_change(&sport->port, !!val);
        wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
 
index 41b6e51188e44e4ac66590231c4a884b96a8b8f3..006489d82dc3dbc41b3f1d96fbea3511cb3e6d25 100644 (file)
@@ -66,6 +66,7 @@ config USB_ARCH_HAS_EHCI
        default y if ARCH_VT8500
        default y if PLAT_SPEAR
        default y if ARCH_MSM
+       default y if MICROBLAZE
        default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
index a3d2e2399655b84a348561e8aa27521212f21831..96fdfb815f895969e2d4c76750b8e0a5f7844c47 100644 (file)
@@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
                break;
        case USB_ENDPOINT_XFER_INT:
                type = "Int.";
-               if (speed == USB_SPEED_HIGH)
+               if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
                        interval = 1 << (desc->bInterval - 1);
                else
                        interval = desc->bInterval;
@@ -229,7 +229,8 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
        default:        /* "can't happen" */
                return start;
        }
-       interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
+       interval *= (speed == USB_SPEED_HIGH ||
+                    speed == USB_SPEED_SUPER) ? 125 : 1000;
        if (interval % 1000)
                unit = 'u';
        else {
@@ -542,8 +543,9 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
        if (level == 0) {
                int     max;
 
-               /* high speed reserves 80%, full/low reserves 90% */
-               if (usbdev->speed == USB_SPEED_HIGH)
+               /* super/high speed reserves 80%, full/low reserves 90% */
+               if (usbdev->speed == USB_SPEED_HIGH ||
+                   usbdev->speed == USB_SPEED_SUPER)
                        max = 800;
                else
                        max = FRAME_TIME_MAX_USECS_ALLOC;
index 8eed05d23838932aa0c412aed83c47d46a138e93..77a7faec8d78a0e7efa8c15f2d96a0b40a538130 100644 (file)
@@ -1908,7 +1908,7 @@ void usb_free_streams(struct usb_interface *interface,
 
        /* Streams only apply to bulk endpoints. */
        for (i = 0; i < num_eps; i++)
-               if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
+               if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc))
                        return;
 
        hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
index 8fb754916c67e02d0e1b16625b7948c36b84dad1..93720bdc9efd4a9ff2e4f0d01023f2432edd1f51 100644 (file)
@@ -2285,7 +2285,17 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
        }
 
        /* see 7.1.7.6 */
-       status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
+       /* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0
+        * external hub.
+        * FIXME: this is a temporary workaround to make the system able
+        * to suspend/resume.
+        */
+       if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev))
+               status = clear_port_feature(hub->hdev, port1,
+                                               USB_PORT_FEAT_POWER);
+       else
+               status = set_port_feature(hub->hdev, port1,
+                                               USB_PORT_FEAT_SUSPEND);
        if (status) {
                dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
                                port1, status);
index 9abecfddb27d1c489a59edfe29512adb93990a67..0111f8a9cf7fcc3f6345a9e6d612ea5683474530 100644 (file)
@@ -706,6 +706,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
        struct f_audio          *audio = func_to_audio(f);
 
        usb_free_descriptors(f->descriptors);
+       usb_free_descriptors(f->hs_descriptors);
        kfree(audio);
 }
 
index 95dd4662d6a83acb3153433713c3e48889500f69..b3c304290150028cfafca5e9f192862617971ea8 100644 (file)
@@ -314,6 +314,9 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
 
 static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
 {
+       struct sk_buff *skb = (struct sk_buff *)req->context;
+
+       dev_kfree_skb_any(skb);
 }
 
 /*
@@ -428,10 +431,11 @@ static int eem_unwrap(struct gether *port,
                                skb_trim(skb2, len);
                                put_unaligned_le16(BIT(15) | BIT(11) | len,
                                                        skb_push(skb2, 2));
-                               skb_copy_bits(skb, 0, req->buf, skb->len);
-                               req->length = skb->len;
+                               skb_copy_bits(skb2, 0, req->buf, skb2->len);
+                               req->length = skb2->len;
                                req->complete = eem_cmd_complete;
                                req->zero = 1;
+                               req->context = skb2;
                                if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
                                        DBG(cdev, "echo response queue fail\n");
                                break;
index aee7e3c53c380bf625763ed2af17296591b02a7a..36613b37c50442c96a3bad47449365aaf31b1e89 100644 (file)
@@ -1148,6 +1148,12 @@ static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame)
 static int txcomplete(struct qe_ep *ep, unsigned char restart)
 {
        if (ep->tx_req != NULL) {
+               struct qe_req *req = ep->tx_req;
+               unsigned zlp = 0, last_len = 0;
+
+               last_len = min_t(unsigned, req->req.length - ep->sent,
+                               ep->ep.maxpacket);
+
                if (!restart) {
                        int asent = ep->last;
                        ep->sent += asent;
@@ -1156,9 +1162,18 @@ static int txcomplete(struct qe_ep *ep, unsigned char restart)
                        ep->last = 0;
                }
 
+               /* zlp needed when req->re.zero is set */
+               if (req->req.zero) {
+                       if (last_len == 0 ||
+                               (req->req.length % ep->ep.maxpacket) != 0)
+                               zlp = 0;
+                       else
+                               zlp = 1;
+               } else
+                       zlp = 0;
+
                /* a request already were transmitted completely */
-               if ((ep->tx_req->req.length - ep->sent) <= 0) {
-                       ep->tx_req->req.actual = (unsigned int)ep->sent;
+               if (((ep->tx_req->req.length - ep->sent) <= 0) && !zlp) {
                        done(ep, ep->tx_req, 0);
                        ep->tx_req = NULL;
                        ep->last = 0;
@@ -1191,6 +1206,7 @@ static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame)
        buf = (u8 *)ep->tx_req->req.buf + ep->sent;
        if (buf && size) {
                ep->last = size;
+               ep->tx_req->req.actual += size;
                frame_set_data(frame, buf);
                frame_set_length(frame, size);
                frame_set_status(frame, FRAME_OK);
index 3ed73f49cf188cd98b92cc3e847a6e40f0062efb..a01383f71f38639c5539f5b82431ef1186ee6b60 100644 (file)
@@ -386,8 +386,10 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 
        /* halt any endpoint by doing a "wrong direction" i/o call */
        if (usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc))
+               if (usb_endpoint_xfer_isoc(&data->desc)) {
+                       mutex_unlock(&data->lock);
                        return -EINVAL;
+               }
                DBG (data->dev, "%s halt\n", data->name);
                spin_lock_irq (&data->dev->lock);
                if (likely (data->ep != NULL))
index 3e4b35e50c2446b8926a687b1cb39e61d473cdff..68dbcc3e4cc2cb005bd2606a8bb64a4c35a12d81 100644 (file)
@@ -1608,7 +1608,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                return -EINVAL;
        if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
                return -ESHUTDOWN;
-       spin_lock_irqsave(&ep->dev->lock, iflags);
+       spin_lock_irqsave(&dev->lock, iflags);
        /* map the buffer for dma */
        if (usbreq->length &&
            ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
@@ -1625,8 +1625,10 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                                                             DMA_FROM_DEVICE);
                } else {
                        req->buf = kzalloc(usbreq->length, GFP_ATOMIC);
-                       if (!req->buf)
-                               return -ENOMEM;
+                       if (!req->buf) {
+                               retval = -ENOMEM;
+                               goto probe_end;
+                       }
                        if (ep->in) {
                                memcpy(req->buf, usbreq->buf, usbreq->length);
                                req->dma = dma_map_single(&dev->pdev->dev,
index 015118535f77db3e8418909b850dfb0ed576fd00..6dcc1f68fa6041531e73eed8104d5c1acff1338b 100644 (file)
@@ -1083,7 +1083,9 @@ static void irq_device_state(struct r8a66597 *r8a66597)
 
        if (dvsq == DS_DFLT) {
                /* bus reset */
+               spin_unlock(&r8a66597->lock);
                r8a66597->driver->disconnect(&r8a66597->gadget);
+               spin_lock(&r8a66597->lock);
                r8a66597_update_usb_speed(r8a66597);
        }
        if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG)
index 7e41a95c5ceb6a9aa70ed437b737eabebf379a4a..627f3a678759a1e007a70a520262a41b48327339 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/usb/ulpi.h>
 #include <plat/usb.h>
+#include <linux/regulator/consumer.h>
 
 /* EHCI Register Set */
 #define EHCI_INSNREG04                                 (0xA0)
@@ -118,6 +119,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        struct ehci_hcd                         *omap_ehci;
        int                                     ret = -ENODEV;
        int                                     irq;
+       int                                     i;
+       char                                    supply[7];
 
        if (usb_disabled())
                return -ENODEV;
@@ -158,6 +161,23 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        hcd->rsrc_len = resource_size(res);
        hcd->regs = regs;
 
+       /* get ehci regulator and enable */
+       for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+               if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
+                       pdata->regulator[i] = NULL;
+                       continue;
+               }
+               snprintf(supply, sizeof(supply), "hsusb%d", i);
+               pdata->regulator[i] = regulator_get(dev, supply);
+               if (IS_ERR(pdata->regulator[i])) {
+                       pdata->regulator[i] = NULL;
+                       dev_dbg(dev,
+                       "failed to get ehci port%d regulator\n", i);
+               } else {
+                       regulator_enable(pdata->regulator[i]);
+               }
+       }
+
        ret = omap_usbhs_enable(dev);
        if (ret) {
                dev_err(dev, "failed to start usbhs with err %d\n", ret);
index 98ded66e8d3fc5ccfbe4bfd9170c51e99cf3b752..42abd0f603bfbcd4291c78b0768b2d552b029500 100644 (file)
@@ -1247,24 +1247,27 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 static void scan_async (struct ehci_hcd *ehci)
 {
+       bool                    stopped;
        struct ehci_qh          *qh;
        enum ehci_timer_action  action = TIMER_IO_WATCHDOG;
 
        ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
        timer_action_done (ehci, TIMER_ASYNC_SHRINK);
 rescan:
+       stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
        qh = ehci->async->qh_next.qh;
        if (likely (qh != NULL)) {
                do {
                        /* clean any finished work for this qh */
-                       if (!list_empty (&qh->qtd_list)
-                                       && qh->stamp != ehci->stamp) {
+                       if (!list_empty(&qh->qtd_list) && (stopped ||
+                                       qh->stamp != ehci->stamp)) {
                                int temp;
 
                                /* unlinks could happen here; completion
                                 * reporting drops the lock.  rescan using
                                 * the latest schedule, but don't rescan
-                                * qhs we already finished (no looping).
+                                * qhs we already finished (no looping)
+                                * unless the controller is stopped.
                                 */
                                qh = qh_get (qh);
                                qh->stamp = ehci->stamp;
@@ -1285,9 +1288,9 @@ rescan:
                         */
                        if (list_empty(&qh->qtd_list)
                                        && qh->qh_state == QH_STATE_LINKED) {
-                               if (!ehci->reclaim
-                                       && ((ehci->stamp - qh->stamp) & 0x1fff)
-                                               >= (EHCI_SHRINK_FRAMES * 8))
+                               if (!ehci->reclaim && (stopped ||
+                                       ((ehci->stamp - qh->stamp) & 0x1fff)
+                                               >= EHCI_SHRINK_FRAMES * 8))
                                        start_unlink_async(ehci, qh);
                                else
                                        action = TIMER_ASYNC_SHRINK;
index f50e84ac570aa9eced485e6372db76287fa9df76..7b2e69aa2e98fdf2e803bb9d1c26d25ba74cb63e 100644 (file)
@@ -295,7 +295,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
        }
 
        dev_err(hcd->self.controller,
-                               "%s: Can not allocate %lu bytes of memory\n"
+                               "%s: Cannot allocate %zu bytes of memory\n"
                                "Current memory map:\n",
                                __func__, qtd->length);
        for (i = 0; i < BLOCKS; i++) {
@@ -1633,6 +1633,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                        ints[i].qh = NULL;
                        ints[i].qtd = NULL;
 
+                       urb->status = status;
                        isp1760_urb_done(hcd, urb);
                        if (qtd)
                                pe(hcd, qh, qtd);
index 17a6043c1fa072cba3d84c01fe8f6ba83005fff3..958d985f29513f36b2840b77a532c09a7bafa45e 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifdef __LITTLE_ENDIAN
 #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
-#elif __BIG_ENDIAN
+#elif defined(__BIG_ENDIAN)
 #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \
                          USBH_ENABLE_BE)
 #else
index 1d586d4f7b56d5e3a0c38cf793dfec8dbf2554af..9b166d70ae91f8508642fee95097e958e21d2165 100644 (file)
@@ -84,65 +84,92 @@ int usb_amd_find_chipset_info(void)
 {
        u8 rev = 0;
        unsigned long flags;
+       struct amd_chipset_info info;
+       int ret;
 
        spin_lock_irqsave(&amd_lock, flags);
 
-       amd_chipset.probe_count++;
        /* probe only once */
-       if (amd_chipset.probe_count > 1) {
+       if (amd_chipset.probe_count > 0) {
+               amd_chipset.probe_count++;
                spin_unlock_irqrestore(&amd_lock, flags);
                return amd_chipset.probe_result;
        }
+       memset(&info, 0, sizeof(info));
+       spin_unlock_irqrestore(&amd_lock, flags);
 
-       amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
-       if (amd_chipset.smbus_dev) {
-               rev = amd_chipset.smbus_dev->revision;
+       info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
+       if (info.smbus_dev) {
+               rev = info.smbus_dev->revision;
                if (rev >= 0x40)
-                       amd_chipset.sb_type = 1;
+                       info.sb_type = 1;
                else if (rev >= 0x30 && rev <= 0x3b)
-                       amd_chipset.sb_type = 3;
+                       info.sb_type = 3;
        } else {
-               amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-                                                       0x780b, NULL);
-               if (!amd_chipset.smbus_dev) {
-                       spin_unlock_irqrestore(&amd_lock, flags);
-                       return 0;
+               info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                               0x780b, NULL);
+               if (!info.smbus_dev) {
+                       ret = 0;
+                       goto commit;
                }
-               rev = amd_chipset.smbus_dev->revision;
+
+               rev = info.smbus_dev->revision;
                if (rev >= 0x11 && rev <= 0x18)
-                       amd_chipset.sb_type = 2;
+                       info.sb_type = 2;
        }
 
-       if (amd_chipset.sb_type == 0) {
-               if (amd_chipset.smbus_dev) {
-                       pci_dev_put(amd_chipset.smbus_dev);
-                       amd_chipset.smbus_dev = NULL;
+       if (info.sb_type == 0) {
+               if (info.smbus_dev) {
+                       pci_dev_put(info.smbus_dev);
+                       info.smbus_dev = NULL;
                }
-               spin_unlock_irqrestore(&amd_lock, flags);
-               return 0;
+               ret = 0;
+               goto commit;
        }
 
-       amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
-       if (amd_chipset.nb_dev) {
-               amd_chipset.nb_type = 1;
+       info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
+       if (info.nb_dev) {
+               info.nb_type = 1;
        } else {
-               amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-                                                       0x1510, NULL);
-               if (amd_chipset.nb_dev) {
-                       amd_chipset.nb_type = 2;
-               } else  {
-                       amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-                                                               0x9600, NULL);
-                       if (amd_chipset.nb_dev)
-                               amd_chipset.nb_type = 3;
+               info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
+               if (info.nb_dev) {
+                       info.nb_type = 2;
+               } else {
+                       info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                                    0x9600, NULL);
+                       if (info.nb_dev)
+                               info.nb_type = 3;
                }
        }
 
-       amd_chipset.probe_result = 1;
+       ret = info.probe_result = 1;
        printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
 
-       spin_unlock_irqrestore(&amd_lock, flags);
-       return amd_chipset.probe_result;
+commit:
+
+       spin_lock_irqsave(&amd_lock, flags);
+       if (amd_chipset.probe_count > 0) {
+               /* race - someone else was faster - drop devices */
+
+               /* Mark that we where here */
+               amd_chipset.probe_count++;
+               ret = amd_chipset.probe_result;
+
+               spin_unlock_irqrestore(&amd_lock, flags);
+
+               if (info.nb_dev)
+                       pci_dev_put(info.nb_dev);
+               if (info.smbus_dev)
+                       pci_dev_put(info.smbus_dev);
+
+       } else {
+               /* no race - commit the result */
+               info.probe_count++;
+               amd_chipset = info;
+               spin_unlock_irqrestore(&amd_lock, flags);
+       }
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
 
@@ -284,6 +311,7 @@ EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
 
 void usb_amd_dev_put(void)
 {
+       struct pci_dev *nb, *smbus;
        unsigned long flags;
 
        spin_lock_irqsave(&amd_lock, flags);
@@ -294,20 +322,23 @@ void usb_amd_dev_put(void)
                return;
        }
 
-       if (amd_chipset.nb_dev) {
-               pci_dev_put(amd_chipset.nb_dev);
-               amd_chipset.nb_dev = NULL;
-       }
-       if (amd_chipset.smbus_dev) {
-               pci_dev_put(amd_chipset.smbus_dev);
-               amd_chipset.smbus_dev = NULL;
-       }
+       /* save them to pci_dev_put outside of spinlock */
+       nb    = amd_chipset.nb_dev;
+       smbus = amd_chipset.smbus_dev;
+
+       amd_chipset.nb_dev = NULL;
+       amd_chipset.smbus_dev = NULL;
        amd_chipset.nb_type = 0;
        amd_chipset.sb_type = 0;
        amd_chipset.isoc_reqs = 0;
        amd_chipset.probe_result = 0;
 
        spin_unlock_irqrestore(&amd_lock, flags);
+
+       if (nb)
+               pci_dev_put(nb);
+       if (smbus)
+               pci_dev_put(smbus);
 }
 EXPORT_SYMBOL_GPL(usb_amd_dev_put);
 
index a78f2ebd11b785aabf235bf6dd4e76a529506319..73f75d26436c48635bca66c68a777891287b36c9 100644 (file)
@@ -777,7 +777,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                if (t1 != t2)
                        xhci_writel(xhci, t2, port_array[port_index]);
 
-               if (DEV_HIGHSPEED(t1)) {
+               if (hcd->speed != HCD_USB3) {
                        /* enable remote wake up for USB 2.0 */
                        u32 __iomem *addr;
                        u32 tmp;
@@ -866,6 +866,21 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                                temp |= PORT_LINK_STROBE | XDEV_U0;
                                xhci_writel(xhci, temp, port_array[port_index]);
                        }
+                       /* wait for the port to enter U0 and report port link
+                        * state change.
+                        */
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       msleep(20);
+                       spin_lock_irqsave(&xhci->lock, flags);
+
+                       /* Clear PLC */
+                       temp = xhci_readl(xhci, port_array[port_index]);
+                       if (temp & PORT_PLC) {
+                               temp = xhci_port_state_to_neutral(temp);
+                               temp |= PORT_PLC;
+                               xhci_writel(xhci, temp, port_array[port_index]);
+                       }
+
                        slot_id = xhci_find_slot_id_by_port(hcd,
                                        xhci, port_index + 1);
                        if (slot_id)
@@ -873,7 +888,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                } else
                        xhci_writel(xhci, temp, port_array[port_index]);
 
-               if (DEV_HIGHSPEED(temp)) {
+               if (hcd->speed != HCD_USB3) {
                        /* disable remote wake up for USB 2.0 */
                        u32 __iomem *addr;
                        u32 tmp;
index a003e79aacdc0e06efe85cfa3dc53a2579c850b2..627f3438028ce3a54d49fd7d691143b58f6fac18 100644 (file)
@@ -846,7 +846,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
                 * Skip ports that don't have known speeds, or have duplicate
                 * Extended Capabilities port speed entries.
                 */
-               if (port_speed == 0 || port_speed == -1)
+               if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
                        continue;
 
                /*
@@ -974,6 +974,47 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        return 0;
 }
 
+/*
+ * Convert interval expressed as 2^(bInterval - 1) == interval into
+ * straight exponent value 2^n == interval.
+ *
+ */
+static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       unsigned int interval;
+
+       interval = clamp_val(ep->desc.bInterval, 1, 16) - 1;
+       if (interval != ep->desc.bInterval - 1)
+               dev_warn(&udev->dev,
+                        "ep %#x - rounding interval to %d microframes\n",
+                        ep->desc.bEndpointAddress,
+                        1 << interval);
+
+       return interval;
+}
+
+/*
+ * Convert bInterval expressed in frames (in 1-255 range) to exponent of
+ * microframes, rounded down to nearest power of 2.
+ */
+static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       unsigned int interval;
+
+       interval = fls(8 * ep->desc.bInterval) - 1;
+       interval = clamp_val(interval, 3, 10);
+       if ((1 << interval) != 8 * ep->desc.bInterval)
+               dev_warn(&udev->dev,
+                        "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
+                        ep->desc.bEndpointAddress,
+                        1 << interval,
+                        8 * ep->desc.bInterval);
+
+       return interval;
+}
+
 /* Return the polling or NAK interval.
  *
  * The polling interval is expressed in "microframes".  If xHCI's Interval field
@@ -982,7 +1023,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
  * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
  * is set to 0.
  */
-static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
+static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        unsigned int interval = 0;
@@ -991,45 +1032,38 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
        case USB_SPEED_HIGH:
                /* Max NAK rate */
                if (usb_endpoint_xfer_control(&ep->desc) ||
-                               usb_endpoint_xfer_bulk(&ep->desc))
+                   usb_endpoint_xfer_bulk(&ep->desc)) {
                        interval = ep->desc.bInterval;
+                       break;
+               }
                /* Fall through - SS and HS isoc/int have same decoding */
+
        case USB_SPEED_SUPER:
                if (usb_endpoint_xfer_int(&ep->desc) ||
-                               usb_endpoint_xfer_isoc(&ep->desc)) {
-                       if (ep->desc.bInterval == 0)
-                               interval = 0;
-                       else
-                               interval = ep->desc.bInterval - 1;
-                       if (interval > 15)
-                               interval = 15;
-                       if (interval != ep->desc.bInterval + 1)
-                               dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
-                                               ep->desc.bEndpointAddress, 1 << interval);
+                   usb_endpoint_xfer_isoc(&ep->desc)) {
+                       interval = xhci_parse_exponent_interval(udev, ep);
                }
                break;
-       /* Convert bInterval (in 1-255 frames) to microframes and round down to
-        * nearest power of 2.
-        */
+
        case USB_SPEED_FULL:
+               if (usb_endpoint_xfer_int(&ep->desc)) {
+                       interval = xhci_parse_exponent_interval(udev, ep);
+                       break;
+               }
+               /*
+                * Fall through for isochronous endpoint interval decoding
+                * since it uses the same rules as low speed interrupt
+                * endpoints.
+                */
+
        case USB_SPEED_LOW:
                if (usb_endpoint_xfer_int(&ep->desc) ||
-                               usb_endpoint_xfer_isoc(&ep->desc)) {
-                       interval = fls(8*ep->desc.bInterval) - 1;
-                       if (interval > 10)
-                               interval = 10;
-                       if (interval < 3)
-                               interval = 3;
-                       if ((1 << interval) != 8*ep->desc.bInterval)
-                               dev_warn(&udev->dev,
-                                               "ep %#x - rounding interval"
-                                               " to %d microframes, "
-                                               "ep desc says %d microframes\n",
-                                               ep->desc.bEndpointAddress,
-                                               1 << interval,
-                                               8*ep->desc.bInterval);
+                   usb_endpoint_xfer_isoc(&ep->desc)) {
+
+                       interval = xhci_parse_frame_interval(udev, ep);
                }
                break;
+
        default:
                BUG();
        }
@@ -1041,7 +1075,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
  * transaction opportunities per microframe", but that goes in the Max Burst
  * endpoint context field.
  */
-static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
+static u32 xhci_get_endpoint_mult(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        if (udev->speed != USB_SPEED_SUPER ||
@@ -1050,7 +1084,7 @@ static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
        return ep->ss_ep_comp.bmAttributes;
 }
 
-static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
+static u32 xhci_get_endpoint_type(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        int in;
@@ -1084,7 +1118,7 @@ static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
  * Basically, this is the maxpacket size, multiplied by the burst size
  * and mult size.
  */
-static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
+static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
                struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
@@ -1727,12 +1761,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                         * found a similar duplicate.
                         */
                        if (xhci->port_array[i] != major_revision &&
-                               xhci->port_array[i] != (u8) -1) {
+                               xhci->port_array[i] != DUPLICATE_ENTRY) {
                                if (xhci->port_array[i] == 0x03)
                                        xhci->num_usb3_ports--;
                                else
                                        xhci->num_usb2_ports--;
-                               xhci->port_array[i] = (u8) -1;
+                               xhci->port_array[i] = DUPLICATE_ENTRY;
                        }
                        /* FIXME: Should we disable the port? */
                        continue;
@@ -1831,7 +1865,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                for (i = 0; i < num_ports; i++) {
                        if (xhci->port_array[i] == 0x03 ||
                                        xhci->port_array[i] == 0 ||
-                                       xhci->port_array[i] == -1)
+                                       xhci->port_array[i] == DUPLICATE_ENTRY)
                                continue;
 
                        xhci->usb2_ports[port_index] =
index ceea9f33491c0d1dd379bc48db4fc9fd486a518b..a10494c2f3c7749a83fe52b2479c469da47e9d0e 100644 (file)
@@ -114,6 +114,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
        if (pdev->vendor == PCI_VENDOR_ID_NEC)
                xhci->quirks |= XHCI_NEC_HOST;
 
+       /* AMD PLL quirk */
+       if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
+               xhci->quirks |= XHCI_AMD_PLL_FIX;
+
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
        if (retval)
index cfc1ad92473f5f5ae77403a07e55ae03c2f71690..7437386a9a50afeea3ad87bfd5b2f66f0a861947 100644 (file)
@@ -93,7 +93,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
 /* Does this link TRB point to the first segment in a ring,
  * or was the previous TRB the last TRB on the last segment in the ERST?
  */
-static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
+static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
                struct xhci_segment *seg, union xhci_trb *trb)
 {
        if (ring == xhci->event_ring)
@@ -107,7 +107,7 @@ static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring
  * segment?  I.e. would the updated event TRB pointer step off the end of the
  * event seg?
  */
-static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
+static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
                struct xhci_segment *seg, union xhci_trb *trb)
 {
        if (ring == xhci->event_ring)
@@ -116,7 +116,7 @@ static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
                return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
 }
 
-static inline int enqueue_is_link_trb(struct xhci_ring *ring)
+static int enqueue_is_link_trb(struct xhci_ring *ring)
 {
        struct xhci_link_trb *link = &ring->enqueue->link;
        return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
@@ -592,7 +592,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
        ep->ep_state |= SET_DEQ_PENDING;
 }
 
-static inline void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,
+static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,
                struct xhci_virt_ep *ep)
 {
        ep->ep_state &= ~EP_HALT_PENDING;
@@ -619,6 +619,13 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
 
        /* Only giveback urb when this is the last td in urb */
        if (urb_priv->td_cnt == urb_priv->length) {
+               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                       xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
+                       if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
+                               if (xhci->quirks & XHCI_AMD_PLL_FIX)
+                                       usb_amd_quirk_pll_enable();
+                       }
+               }
                usb_hcd_unlink_urb_from_ep(hcd, urb);
                xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb);
 
@@ -1209,7 +1216,7 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
                 * Skip ports that don't have known speeds, or have duplicate
                 * Extended Capabilities port speed entries.
                 */
-               if (port_speed == 0 || port_speed == -1)
+               if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
                        continue;
 
                /*
@@ -1235,6 +1242,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
        u8 major_revision;
        struct xhci_bus_state *bus_state;
        u32 __iomem **port_array;
+       bool bogus_port_status = false;
 
        /* Port status change events always have a successful completion code */
        if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
@@ -1247,6 +1255,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
        max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
        if ((port_id <= 0) || (port_id > max_ports)) {
                xhci_warn(xhci, "Invalid port id %d\n", port_id);
+               bogus_port_status = true;
                goto cleanup;
        }
 
@@ -1258,12 +1267,14 @@ static void handle_port_status(struct xhci_hcd *xhci,
                xhci_warn(xhci, "Event for port %u not in "
                                "Extended Capabilities, ignoring.\n",
                                port_id);
+               bogus_port_status = true;
                goto cleanup;
        }
-       if (major_revision == (u8) -1) {
+       if (major_revision == DUPLICATE_ENTRY) {
                xhci_warn(xhci, "Event for port %u duplicated in"
                                "Extended Capabilities, ignoring.\n",
                                port_id);
+               bogus_port_status = true;
                goto cleanup;
        }
 
@@ -1335,6 +1346,13 @@ cleanup:
        /* Update event ring dequeue pointer before dropping the lock */
        inc_deq(xhci, xhci->event_ring, true);
 
+       /* Don't make the USB core poll the roothub if we got a bad port status
+        * change event.  Besides, at that point we can't tell which roothub
+        * (USB 2.0 or USB 3.0) to kick.
+        */
+       if (bogus_port_status)
+               return;
+
        spin_unlock(&xhci->lock);
        /* Pass this up to the core */
        usb_hcd_poll_rh_status(hcd);
@@ -1554,8 +1572,17 @@ td_cleanup:
 
                urb_priv->td_cnt++;
                /* Giveback the urb when all the tds are completed */
-               if (urb_priv->td_cnt == urb_priv->length)
+               if (urb_priv->td_cnt == urb_priv->length) {
                        ret = 1;
+                       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                               xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
+                               if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs
+                                       == 0) {
+                                       if (xhci->quirks & XHCI_AMD_PLL_FIX)
+                                               usb_amd_quirk_pll_enable();
+                               }
+                       }
+               }
        }
 
        return ret;
@@ -1675,71 +1702,52 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        struct urb_priv *urb_priv;
        int idx;
        int len = 0;
-       int skip_td = 0;
        union xhci_trb *cur_trb;
        struct xhci_segment *cur_seg;
+       struct usb_iso_packet_descriptor *frame;
        u32 trb_comp_code;
+       bool skip_td = false;
 
        ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
        trb_comp_code = GET_COMP_CODE(event->transfer_len);
        urb_priv = td->urb->hcpriv;
        idx = urb_priv->td_cnt;
+       frame = &td->urb->iso_frame_desc[idx];
 
-       if (ep->skip) {
-               /* The transfer is partly done */
-               *status = -EXDEV;
-               td->urb->iso_frame_desc[idx].status = -EXDEV;
-       } else {
-               /* handle completion code */
-               switch (trb_comp_code) {
-               case COMP_SUCCESS:
-                       td->urb->iso_frame_desc[idx].status = 0;
-                       xhci_dbg(xhci, "Successful isoc transfer!\n");
-                       break;
-               case COMP_SHORT_TX:
-                       if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
-                               td->urb->iso_frame_desc[idx].status =
-                                        -EREMOTEIO;
-                       else
-                               td->urb->iso_frame_desc[idx].status = 0;
-                       break;
-               case COMP_BW_OVER:
-                       td->urb->iso_frame_desc[idx].status = -ECOMM;
-                       skip_td = 1;
-                       break;
-               case COMP_BUFF_OVER:
-               case COMP_BABBLE:
-                       td->urb->iso_frame_desc[idx].status = -EOVERFLOW;
-                       skip_td = 1;
-                       break;
-               case COMP_STALL:
-                       td->urb->iso_frame_desc[idx].status = -EPROTO;
-                       skip_td = 1;
-                       break;
-               case COMP_STOP:
-               case COMP_STOP_INVAL:
-                       break;
-               default:
-                       td->urb->iso_frame_desc[idx].status = -1;
-                       break;
-               }
-       }
-
-       /* calc actual length */
-       if (ep->skip) {
-               td->urb->iso_frame_desc[idx].actual_length = 0;
-               /* Update ring dequeue pointer */
-               while (ep_ring->dequeue != td->last_trb)
-                       inc_deq(xhci, ep_ring, false);
-               inc_deq(xhci, ep_ring, false);
-               return finish_td(xhci, td, event_trb, event, ep, status, true);
+       /* handle completion code */
+       switch (trb_comp_code) {
+       case COMP_SUCCESS:
+               frame->status = 0;
+               xhci_dbg(xhci, "Successful isoc transfer!\n");
+               break;
+       case COMP_SHORT_TX:
+               frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
+                               -EREMOTEIO : 0;
+               break;
+       case COMP_BW_OVER:
+               frame->status = -ECOMM;
+               skip_td = true;
+               break;
+       case COMP_BUFF_OVER:
+       case COMP_BABBLE:
+               frame->status = -EOVERFLOW;
+               skip_td = true;
+               break;
+       case COMP_STALL:
+               frame->status = -EPROTO;
+               skip_td = true;
+               break;
+       case COMP_STOP:
+       case COMP_STOP_INVAL:
+               break;
+       default:
+               frame->status = -1;
+               break;
        }
 
-       if (trb_comp_code == COMP_SUCCESS || skip_td == 1) {
-               td->urb->iso_frame_desc[idx].actual_length =
-                       td->urb->iso_frame_desc[idx].length;
-               td->urb->actual_length +=
-                       td->urb->iso_frame_desc[idx].length;
+       if (trb_comp_code == COMP_SUCCESS || skip_td) {
+               frame->actual_length = frame->length;
+               td->urb->actual_length += frame->length;
        } else {
                for (cur_trb = ep_ring->dequeue,
                     cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
@@ -1755,7 +1763,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
                        TRB_LEN(event->transfer_len);
 
                if (trb_comp_code != COMP_STOP_INVAL) {
-                       td->urb->iso_frame_desc[idx].actual_length = len;
+                       frame->actual_length = len;
                        td->urb->actual_length += len;
                }
        }
@@ -1766,6 +1774,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        return finish_td(xhci, td, event_trb, event, ep, status, false);
 }
 
+static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
+                       struct xhci_transfer_event *event,
+                       struct xhci_virt_ep *ep, int *status)
+{
+       struct xhci_ring *ep_ring;
+       struct urb_priv *urb_priv;
+       struct usb_iso_packet_descriptor *frame;
+       int idx;
+
+       ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+       urb_priv = td->urb->hcpriv;
+       idx = urb_priv->td_cnt;
+       frame = &td->urb->iso_frame_desc[idx];
+
+       /* The transfer is partly done */
+       *status = -EXDEV;
+       frame->status = -EXDEV;
+
+       /* calc actual length */
+       frame->actual_length = 0;
+
+       /* Update ring dequeue pointer */
+       while (ep_ring->dequeue != td->last_trb)
+               inc_deq(xhci, ep_ring, false);
+       inc_deq(xhci, ep_ring, false);
+
+       return finish_td(xhci, td, NULL, event, ep, status, true);
+}
+
 /*
  * Process bulk and interrupt tds, update urb status and actual_length.
  */
@@ -2024,36 +2061,42 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                }
 
                td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+
                /* Is this a TRB in the currently executing TD? */
                event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
                                td->last_trb, event_dma);
-               if (event_seg && ep->skip) {
+               if (!event_seg) {
+                       if (!ep->skip ||
+                           !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
+                               /* HC is busted, give up! */
+                               xhci_err(xhci,
+                                       "ERROR Transfer event TRB DMA ptr not "
+                                       "part of current TD\n");
+                               return -ESHUTDOWN;
+                       }
+
+                       ret = skip_isoc_td(xhci, td, event, ep, &status);
+                       goto cleanup;
+               }
+
+               if (ep->skip) {
                        xhci_dbg(xhci, "Found td. Clear skip flag.\n");
                        ep->skip = false;
                }
-               if (!event_seg &&
-                  (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc))) {
-                       /* HC is busted, give up! */
-                       xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not "
-                                       "part of current TD\n");
-                       return -ESHUTDOWN;
-               }
 
-               if (event_seg) {
-                       event_trb = &event_seg->trbs[(event_dma -
-                                        event_seg->dma) / sizeof(*event_trb)];
-                       /*
-                        * No-op TRB should not trigger interrupts.
-                        * If event_trb is a no-op TRB, it means the
-                        * corresponding TD has been cancelled. Just ignore
-                        * the TD.
-                        */
-                       if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
-                                        == TRB_TYPE(TRB_TR_NOOP)) {
-                               xhci_dbg(xhci, "event_trb is a no-op TRB. "
-                                               "Skip it\n");
-                               goto cleanup;
-                       }
+               event_trb = &event_seg->trbs[(event_dma - event_seg->dma) /
+                                               sizeof(*event_trb)];
+               /*
+                * No-op TRB should not trigger interrupts.
+                * If event_trb is a no-op TRB, it means the
+                * corresponding TD has been cancelled. Just ignore
+                * the TD.
+                */
+               if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
+                                == TRB_TYPE(TRB_TR_NOOP)) {
+                       xhci_dbg(xhci,
+                                "event_trb is a no-op TRB. Skip it\n");
+                       goto cleanup;
                }
 
                /* Now update the urb's actual_length and give back to
@@ -3126,6 +3169,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                }
        }
 
+       if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
+               if (xhci->quirks & XHCI_AMD_PLL_FIX)
+                       usb_amd_quirk_pll_disable();
+       }
+       xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs++;
+
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
                        start_cycle, start_trb);
        return 0;
index 196e0181b2ed6e5f56c0a8ea2330a3399c8f739b..81b976e45880900065b505611c0fb762d5852015 100644 (file)
@@ -550,6 +550,9 @@ void xhci_stop(struct usb_hcd *hcd)
        del_timer_sync(&xhci->event_ring_timer);
 #endif
 
+       if (xhci->quirks & XHCI_AMD_PLL_FIX)
+               usb_amd_dev_put();
+
        xhci_dbg(xhci, "// Disabling event ring interrupts\n");
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
@@ -771,7 +774,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 
        /* If restore operation fails, re-initialize the HC during resume */
        if ((temp & STS_SRE) || hibernated) {
-               usb_root_hub_lost_power(hcd->self.root_hub);
+               /* Let the USB core know _both_ roothubs lost power. */
+               usb_root_hub_lost_power(xhci->main_hcd->self.root_hub);
+               usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);
 
                xhci_dbg(xhci, "Stop HCD\n");
                xhci_halt(xhci);
@@ -2386,10 +2391,18 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
        /* Everything but endpoint 0 is disabled, so free or cache the rings. */
        last_freed_endpoint = 1;
        for (i = 1; i < 31; ++i) {
-               if (!virt_dev->eps[i].ring)
-                       continue;
-               xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
-               last_freed_endpoint = i;
+               struct xhci_virt_ep *ep = &virt_dev->eps[i];
+
+               if (ep->ep_state & EP_HAS_STREAMS) {
+                       xhci_free_stream_info(xhci, ep->stream_info);
+                       ep->stream_info = NULL;
+                       ep->ep_state &= ~EP_HAS_STREAMS;
+               }
+
+               if (ep->ring) {
+                       xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+                       last_freed_endpoint = i;
+               }
        }
        xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
        xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
index 07e263063e373ad9fc45e7832f6700fb0b56b2e6..ba1be6b7cc6d91774323e9dd0848e759fe338c9f 100644 (file)
@@ -30,6 +30,7 @@
 
 /* Code sharing between pci-quirks and xhci hcd */
 #include       "xhci-ext-caps.h"
+#include "pci-quirks.h"
 
 /* xHCI PCI Configuration Registers */
 #define XHCI_SBRN_OFFSET       (0x60)
@@ -232,7 +233,7 @@ struct xhci_op_regs {
  * notification type that matches a bit set in this bit field.
  */
 #define        DEV_NOTE_MASK           (0xffff)
-#define ENABLE_DEV_NOTE(x)     (1 << x)
+#define ENABLE_DEV_NOTE(x)     (1 << (x))
 /* Most of the device notification types should only be used for debug.
  * SW does need to pay attention to function wake notifications.
  */
@@ -348,6 +349,9 @@ struct xhci_op_regs {
 /* Initiate a warm port reset - complete when PORT_WRC is '1' */
 #define PORT_WR                (1 << 31)
 
+/* We mark duplicate entries with -1 */
+#define DUPLICATE_ENTRY ((u8)(-1))
+
 /* Port Power Management Status and Control - port_power_base bitmasks */
 /* Inactivity timer value for transitions into U1, in microseconds.
  * Timeout can be up to 127us.  0xFF means an infinite timeout.
@@ -601,11 +605,11 @@ struct xhci_ep_ctx {
 #define EP_STATE_STOPPED       3
 #define EP_STATE_ERROR         4
 /* Mult - Max number of burtst within an interval, in EP companion desc. */
-#define EP_MULT(p)             ((p & 0x3) << 8)
+#define EP_MULT(p)             (((p) & 0x3) << 8)
 /* bits 10:14 are Max Primary Streams */
 /* bit 15 is Linear Stream Array */
 /* Interval - period between requests to an endpoint - 125u increments. */
-#define EP_INTERVAL(p)         ((p & 0xff) << 16)
+#define EP_INTERVAL(p)         (((p) & 0xff) << 16)
 #define EP_INTERVAL_TO_UFRAMES(p)              (1 << (((p) >> 16) & 0xff))
 #define EP_MAXPSTREAMS_MASK    (0x1f << 10)
 #define EP_MAXPSTREAMS(p)      (((p) << 10) & EP_MAXPSTREAMS_MASK)
@@ -1276,6 +1280,7 @@ struct xhci_hcd {
 #define        XHCI_LINK_TRB_QUIRK     (1 << 0)
 #define XHCI_RESET_EP_QUIRK    (1 << 1)
 #define XHCI_NEC_HOST          (1 << 2)
+#define XHCI_AMD_PLL_FIX       (1 << 3)
        /* There are two roothubs to keep track of bus suspend info for */
        struct xhci_bus_state   bus_state[2];
        /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
index 4cbb7e4b368d24d3461b02c28804bcf5badf76ba..74073b363c30f86536daa948a43961654e23bbb7 100644 (file)
@@ -14,7 +14,7 @@ config USB_MUSB_HDRC
        select TWL4030_USB if MACH_OMAP_3430SDP
        select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
        select USB_OTG_UTILS
-       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+       bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        help
          Say Y here if your system has a dual role high speed USB
          controller based on the Mentor Graphics silicon IP.  Then
@@ -30,8 +30,8 @@ config USB_MUSB_HDRC
 
          If you do not know what this is, please say N.
 
-         To compile this driver as a module, choose M here; the
-         module will be called "musb-hdrc".
+#        To compile this driver as a module, choose M here; the
+#        module will be called "musb-hdrc".
 
 choice
        prompt "Platform Glue Layer"
index 52312e8af213a4d0d6cdd515aa50757fd06bfa56..8e2a1ff8a35a8b71cbe6296bf5d546b0d46035c6 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/cacheflush.h>
 
 #include "musb_core.h"
+#include "musbhsdma.h"
 #include "blackfin.h"
 
 struct bfin_glue {
@@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
        return -EIO;
 }
 
+static int bfin_musb_adjust_channel_params(struct dma_channel *channel,
+                               u16 packet_sz, u8 *mode,
+                               dma_addr_t *dma_addr, u32 *len)
+{
+       struct musb_dma_channel *musb_channel = channel->private_data;
+
+       /*
+        * Anomaly 05000450 might cause data corruption when using DMA
+        * MODE 1 transmits with short packet.  So to work around this,
+        * we truncate all MODE 1 transfers down to a multiple of the
+        * max packet size, and then do the last short packet transfer
+        * (if there is any) using MODE 0.
+        */
+       if (ANOMALY_05000450) {
+               if (musb_channel->transmit && *mode == 1)
+                       *len = *len - (*len % packet_sz);
+       }
+
+       return 0;
+}
+
 static void bfin_musb_reg_init(struct musb *musb)
 {
        if (ANOMALY_05000346) {
@@ -430,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = {
 
        .vbus_status    = bfin_musb_vbus_status,
        .set_vbus       = bfin_musb_set_vbus,
+
+       .adjust_channel_params = bfin_musb_adjust_channel_params,
 };
 
 static u64 bfin_dmamask = DMA_BIT_MASK(32);
index de55a3c3259ac1a403e3c4d730781eeb63fda77c..ab434fbd8c35446863052fb7df19607c295b8228 100644 (file)
@@ -597,12 +597,12 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
                length = min(n_bds * maxpacket, length);
        }
 
-       DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
+       DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
                        tx->index,
                        maxpacket,
                        rndis ? "rndis" : "transparent",
                        n_bds,
-                       addr, length);
+                       (unsigned long long)addr, length);
 
        cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
 
@@ -820,7 +820,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
        length = min(n_bds * maxpacket, length);
 
        DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
-                       "dma 0x%x len %u %u/%u\n",
+                       "dma 0x%llx len %u %u/%u\n",
                        rx->index, maxpacket,
                        onepacket
                                ? (is_rndis ? "rndis" : "onepacket")
@@ -829,7 +829,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
                        musb_readl(tibase,
                                DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
                                        & 0xffff,
-                       addr, length, rx->channel.actual_len, rx->buf_len);
+                       (unsigned long long)addr, length,
+                       rx->channel.actual_len, rx->buf_len);
 
        /* only queue one segment at a time, since the hardware prevents
         * correct queue shutdown after unexpected short packets
@@ -1039,9 +1040,9 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
                if (!completed && (bd->hw_options & CPPI_OWN_SET))
                        break;
 
-               DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
+               DBG(5, "C/RXBD %llx: nxt %08x buf %08x "
                        "off.len %08x opt.len %08x (%d)\n",
-                       bd->dma, bd->hw_next, bd->hw_bufp,
+                       (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
                        bd->hw_off_len, bd->hw_options,
                        rx->channel.actual_len);
 
@@ -1111,11 +1112,12 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
                musb_ep_select(cppi->mregs, rx->index + 1);
                csr = musb_readw(regs, MUSB_RXCSR);
                if (csr & MUSB_RXCSR_DMAENAB) {
-                       DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
+                       DBG(4, "list%d %p/%p, last %llx%s, csr %04x\n",
                                rx->index,
                                rx->head, rx->tail,
                                rx->last_processed
-                                       ? rx->last_processed->dma
+                                       ? (unsigned long long)
+                                               rx->last_processed->dma
                                        : 0,
                                completed ? ", completed" : "",
                                csr);
@@ -1167,8 +1169,11 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
        tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
        rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
 
-       if (!tx && !rx)
+       if (!tx && !rx) {
+               if (cppi->irq)
+                       spin_unlock_irqrestore(&musb->lock, flags);
                return IRQ_NONE;
+       }
 
        DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
 
@@ -1199,7 +1204,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
                 */
                if (NULL == bd) {
                        DBG(1, "null BD\n");
-                       tx_ram->tx_complete = 0;
+                       musb_writel(&tx_ram->tx_complete, 0, 0);
                        continue;
                }
 
@@ -1452,7 +1457,7 @@ static int cppi_channel_abort(struct dma_channel *channel)
                 *    compare mode by writing 1 to the tx_complete register.
                 */
                cppi_reset_tx(tx_ram, 1);
-               cppi_ch->head = 0;
+               cppi_ch->head = NULL;
                musb_writel(&tx_ram->tx_complete, 0, 1);
                cppi_dump_tx(5, cppi_ch, " (done teardown)");
 
index 630ae7f3cd4cf1ff9288f38cbca245b504d38629..f10ff00ca09ea377bbd7dd6167e3723260bd78f9 100644 (file)
@@ -1030,6 +1030,7 @@ static void musb_shutdown(struct platform_device *pdev)
        struct musb     *musb = dev_to_musb(&pdev->dev);
        unsigned long   flags;
 
+       pm_runtime_get_sync(musb->controller);
        spin_lock_irqsave(&musb->lock, flags);
        musb_platform_disable(musb);
        musb_generic_disable(musb);
@@ -1040,6 +1041,7 @@ static void musb_shutdown(struct platform_device *pdev)
        musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
        musb_platform_exit(musb);
 
+       pm_runtime_put(musb->controller);
        /* FIXME power down */
 }
 
index 4bd9e2145ee416dec1cf516538b0597cf94fa08f..0e053b5879601fa93a77a8caede70773b1360f27 100644 (file)
@@ -261,6 +261,7 @@ enum musb_g_ep0_state {
  * @try_ilde:  tries to idle the IP
  * @vbus_status: returns vbus status if possible
  * @set_vbus:  forces vbus status
+ * @channel_program: pre check for standard dma channel_program func
  */
 struct musb_platform_ops {
        int     (*init)(struct musb *musb);
@@ -274,6 +275,10 @@ struct musb_platform_ops {
 
        int     (*vbus_status)(struct musb *musb);
        void    (*set_vbus)(struct musb *musb, int on);
+
+       int     (*adjust_channel_params)(struct dma_channel *channel,
+                               u16 packet_sz, u8 *mode,
+                               dma_addr_t *dma_addr, u32 *len);
 };
 
 /*
index 98519c5d8b5cc23e5407dac87a521004d8885f59..f47c20197c61aa3c8882f25a064c83e6890ff9cb 100644 (file)
@@ -535,7 +535,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
                        is_dma = 1;
                        csr |= MUSB_TXCSR_P_WZC_BITS;
                        csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
-                                MUSB_TXCSR_TXPKTRDY);
+                                MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);
                        musb_writew(epio, MUSB_TXCSR, csr);
                        /* Ensure writebuffer is empty. */
                        csr = musb_readw(epio, MUSB_TXCSR);
@@ -1296,7 +1296,7 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
        }
 
        /* if the hardware doesn't have the request, easy ... */
-       if (musb_ep->req_list.next != &request->list || musb_ep->busy)
+       if (musb_ep->req_list.next != &req->list || musb_ep->busy)
                musb_g_giveback(musb_ep, request, -ECONNRESET);
 
        /* ... else abort the dma transfer ... */
@@ -1887,11 +1887,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                        otg_set_vbus(musb->xceiv, 1);
 
                hcd->self.uses_pio_for_control = 1;
-
-               if (musb->xceiv->last_event == USB_EVENT_NONE)
-                       pm_runtime_put(musb->controller);
-
        }
+       if (musb->xceiv->last_event == USB_EVENT_NONE)
+               pm_runtime_put(musb->controller);
 
        return 0;
 
index 0144a2d481fd8daf8b8c3ab30102e57154096c5e..d281792db05c414cc0a6f2c30a62967dd8a458e9 100644 (file)
@@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel,
        BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
                channel->status == MUSB_DMA_STATUS_BUSY);
 
+       /* Let targets check/tweak the arguments */
+       if (musb->ops->adjust_channel_params) {
+               int ret = musb->ops->adjust_channel_params(channel,
+                       packet_sz, &mode, &dma_addr, &len);
+               if (ret)
+                       return ret;
+       }
+
        /*
         * The DMA engine in RTL1.8 and above cannot handle
         * DMA addresses that are not aligned to a 4 byte boundary.
index 25cb8b0003b152c751087251a593c39e482c326e..e9e60b6e058394c3bdcdad9af873e6f25e9c21d8 100644 (file)
@@ -259,9 +259,10 @@ static int musb_otg_notifications(struct notifier_block *nb,
        case USB_EVENT_VBUS:
                DBG(4, "VBUS Connect\n");
 
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
                if (musb->gadget_driver)
                        pm_runtime_get_sync(musb->controller);
-
+#endif
                otg_init(musb->xceiv);
                break;
 
@@ -269,7 +270,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
                DBG(4, "VBUS Disconnect\n");
 
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
-               if (is_otg_enabled(musb))
+               if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
                        if (musb->gadget_driver)
 #endif
                        {
index d6384e4aeef96ba77448fa048cbc6560a4d2353d..f7e04bf34a13a86f7439b2033b255137f10d039b 100644 (file)
@@ -93,6 +93,8 @@ static int __init ux500_probe(struct platform_device *pdev)
        }
 
        musb->dev.parent                = &pdev->dev;
+       musb->dev.dma_mask              = pdev->dev.dma_mask;
+       musb->dev.coherent_dma_mask     = pdev->dev.coherent_dma_mask;
 
        glue->dev                       = &pdev->dev;
        glue->musb                      = musb;
index a973c7a29d6ef1458baf0c76044d5ecbd83bc134..4de6ef0ae52af2b541890a920641e1e792f8c3d7 100644 (file)
@@ -151,6 +151,8 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
  * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
  */
 static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
@@ -525,6 +527,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
        { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
        { USB_DEVICE(OCT_VID, OCT_US101_PID) },
+       { USB_DEVICE(OCT_VID, OCT_DK201_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
                .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
@@ -787,6 +790,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
+       { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
+       { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
        { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
        { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
        { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
index c543e55bafbaff09fbc3c1d31b3726c58532486c..efffc23723bdf94aae454a025b9b419453f54b3f 100644 (file)
  * Hameg HO820 and HO870 interface (using VID 0x0403)
  */
 #define HAMEG_HO820_PID                        0xed74
+#define HAMEG_HO730_PID                        0xed73
+#define HAMEG_HO720_PID                        0xed72
 #define HAMEG_HO870_PID                        0xed71
 
 /*
 /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
 /* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
 /* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
+#define OCT_DK201_PID          0x0103  /* OCT DK201 USB docking station */
 #define OCT_US101_PID          0x0421  /* OCT US101 USB to RS-232 */
 
 /*
 #define QIHARDWARE_VID                 0x20B7
 #define MILKYMISTONE_JTAGSERIAL_PID    0x0713
 
+/*
+ * CTI GmbH RS485 Converter http://www.cti-lean.com/
+ */
+/* USB-485-Mini*/
+#define FTDI_CTI_MINI_PID      0xF608
+/* USB-Nano-485*/
+#define FTDI_CTI_NANO_PID      0xF60B
+
+
index 75c7f456eed52880bb181e8dd3d53d5aca01a3c3..d77ff0435896bf098c39fda885d2370de685cc0c 100644 (file)
@@ -407,6 +407,10 @@ static void option_instat_callback(struct urb *urb);
 /* ONDA MT825UP HSDPA 14.2 modem */
 #define ONDA_MT825UP         0x000b
 
+/* Samsung products */
+#define SAMSUNG_VENDOR_ID                       0x04e8
+#define SAMSUNG_PRODUCT_GT_B3730                0x6889
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -968,6 +972,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
        { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
+       { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730/GT-B3710 LTE USB modem.*/
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 8858201eb1d39cddb1150d2077f954226a4b833e..54a9dab1f33b4e4d335201d04572499ab701c424 100644 (file)
@@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
        ifnum = intf->desc.bInterfaceNumber;
        dbg("This Interface = %d", ifnum);
 
-       data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+       data = kzalloc(sizeof(struct usb_wwan_intf_private),
                                         GFP_KERNEL);
        if (!data)
                return -ENOMEM;
@@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
                        dbg("QDL port found");
 
-                       if (serial->interface->num_altsetting == 1)
-                               return 0;
+                       if (serial->interface->num_altsetting == 1) {
+                               retval = 0; /* Success */
+                               break;
+                       }
 
                        retval = usb_set_interface(serial->dev, ifnum, 1);
                        if (retval < 0) {
@@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                                retval = -ENODEV;
                                kfree(data);
                        }
-                       return retval;
                }
                break;
 
@@ -166,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                                        "Could not set interface, error %d\n",
                                        retval);
                                retval = -ENODEV;
+                               kfree(data);
                        }
                } else if (ifnum == 2) {
                        dbg("Modem port found");
@@ -177,7 +179,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                                retval = -ENODEV;
                                kfree(data);
                        }
-                       return retval;
                } else if (ifnum==3) {
                        /*
                         * NMEA (serial line 9600 8N1)
@@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                                        "Could not set interface, error %d\n",
                                        retval);
                                retval = -ENODEV;
+                               kfree(data);
                        }
                }
                break;
@@ -199,12 +201,27 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
                dev_err(&serial->dev->dev,
                        "unknown number of interfaces: %d\n", nintf);
                kfree(data);
-               return -ENODEV;
+               retval = -ENODEV;
        }
 
+       /* Set serial->private if not returning -ENODEV */
+       if (retval != -ENODEV)
+               usb_set_serial_data(serial, data);
        return retval;
 }
 
+static void qc_release(struct usb_serial *serial)
+{
+       struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+
+       dbg("%s", __func__);
+
+       /* Call usb_wwan release & free the private data allocated in qcprobe */
+       usb_wwan_release(serial);
+       usb_set_serial_data(serial, NULL);
+       kfree(priv);
+}
+
 static struct usb_serial_driver qcdevice = {
        .driver = {
                .owner     = THIS_MODULE,
@@ -222,7 +239,7 @@ static struct usb_serial_driver qcdevice = {
        .chars_in_buffer     = usb_wwan_chars_in_buffer,
        .attach              = usb_wwan_startup,
        .disconnect          = usb_wwan_disconnect,
-       .release             = usb_wwan_release,
+       .release             = qc_release,
 #ifdef CONFIG_PM
        .suspend             = usb_wwan_suspend,
        .resume              = usb_wwan_resume,
index a2e5b5100ab4edd8a8756905a0fbeefdd4091c4f..0f4e8c942f9e082e7410de7983ac28f81576c5f3 100644 (file)
@@ -1648,7 +1648,9 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
 
        switch (val) {
        case CPUFREQ_PRECHANGE:
-               if (!fbi->overlay[0].usage && !fbi->overlay[1].usage)
+#ifdef CONFIG_FB_PXA_OVERLAY
+               if (!(fbi->overlay[0].usage || fbi->overlay[1].usage))
+#endif
                        set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
                break;
 
index 4fb5b2bf23486c0bee03f0dd3de196aff7f40549..4bcc8b82640be13af193478aaa2c4699bc609d2b 100644 (file)
@@ -590,15 +590,10 @@ static struct virtio_config_ops virtio_pci_config_ops = {
 
 static void virtio_pci_release_dev(struct device *_d)
 {
-       struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
+       struct virtio_device *dev = container_of(_d, struct virtio_device,
+                                                dev);
        struct virtio_pci_device *vp_dev = to_vp_device(dev);
-       struct pci_dev *pci_dev = vp_dev->pci_dev;
 
-       vp_del_vqs(dev);
-       pci_set_drvdata(pci_dev, NULL);
-       pci_iounmap(pci_dev, vp_dev->ioaddr);
-       pci_release_regions(pci_dev);
-       pci_disable_device(pci_dev);
        kfree(vp_dev);
 }
 
@@ -681,6 +676,12 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
        struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
 
        unregister_virtio_device(&vp_dev->vdev);
+
+       vp_del_vqs(&vp_dev->vdev);
+       pci_set_drvdata(pci_dev, NULL);
+       pci_iounmap(pci_dev, vp_dev->ioaddr);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
 }
 
 #ifdef CONFIG_PM
index cc2f73e03475b620053765b373c8b1a39fc08762..b0043fb26a4d5dd8fcc9a2b7b66a18b3b44053b0 100644 (file)
@@ -371,6 +371,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
                /* detach_buf clears data, so grab it now. */
                buf = vq->data[i];
                detach_buf(vq, i);
+               vq->vring.avail->idx--;
                END_USE(vq);
                return buf;
        }
index 35a0d12dad7351340fdd1cfc8b84cb221556e059..5fd020da7c5534f32f7823d966ee49610ac9d31a 100644 (file)
@@ -35,6 +35,7 @@
  *     document number 324645-001, 324646-001: Cougar Point (CPT)
  *     document number TBD                   : Patsburg (PBG)
  *     document number TBD                   : DH89xxCC
+ *     document number TBD                   : Panther Point
  */
 
 /*
@@ -153,6 +154,38 @@ enum iTCO_chipsets {
        TCO_PBG1,       /* Patsburg */
        TCO_PBG2,       /* Patsburg */
        TCO_DH89XXCC,   /* DH89xxCC */
+       TCO_PPT0,       /* Panther Point */
+       TCO_PPT1,       /* Panther Point */
+       TCO_PPT2,       /* Panther Point */
+       TCO_PPT3,       /* Panther Point */
+       TCO_PPT4,       /* Panther Point */
+       TCO_PPT5,       /* Panther Point */
+       TCO_PPT6,       /* Panther Point */
+       TCO_PPT7,       /* Panther Point */
+       TCO_PPT8,       /* Panther Point */
+       TCO_PPT9,       /* Panther Point */
+       TCO_PPT10,      /* Panther Point */
+       TCO_PPT11,      /* Panther Point */
+       TCO_PPT12,      /* Panther Point */
+       TCO_PPT13,      /* Panther Point */
+       TCO_PPT14,      /* Panther Point */
+       TCO_PPT15,      /* Panther Point */
+       TCO_PPT16,      /* Panther Point */
+       TCO_PPT17,      /* Panther Point */
+       TCO_PPT18,      /* Panther Point */
+       TCO_PPT19,      /* Panther Point */
+       TCO_PPT20,      /* Panther Point */
+       TCO_PPT21,      /* Panther Point */
+       TCO_PPT22,      /* Panther Point */
+       TCO_PPT23,      /* Panther Point */
+       TCO_PPT24,      /* Panther Point */
+       TCO_PPT25,      /* Panther Point */
+       TCO_PPT26,      /* Panther Point */
+       TCO_PPT27,      /* Panther Point */
+       TCO_PPT28,      /* Panther Point */
+       TCO_PPT29,      /* Panther Point */
+       TCO_PPT30,      /* Panther Point */
+       TCO_PPT31,      /* Panther Point */
 };
 
 static struct {
@@ -244,6 +277,38 @@ static struct {
        {"Patsburg", 2},
        {"Patsburg", 2},
        {"DH89xxCC", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
+       {"Panther Point", 2},
        {NULL, 0}
 };
 
@@ -363,6 +428,38 @@ static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
        { ITCO_PCI_DEVICE(0x1d40,                               TCO_PBG1)},
        { ITCO_PCI_DEVICE(0x1d41,                               TCO_PBG2)},
        { ITCO_PCI_DEVICE(0x2310,                               TCO_DH89XXCC)},
+       { ITCO_PCI_DEVICE(0x1e40,                               TCO_PPT0)},
+       { ITCO_PCI_DEVICE(0x1e41,                               TCO_PPT1)},
+       { ITCO_PCI_DEVICE(0x1e42,                               TCO_PPT2)},
+       { ITCO_PCI_DEVICE(0x1e43,                               TCO_PPT3)},
+       { ITCO_PCI_DEVICE(0x1e44,                               TCO_PPT4)},
+       { ITCO_PCI_DEVICE(0x1e45,                               TCO_PPT5)},
+       { ITCO_PCI_DEVICE(0x1e46,                               TCO_PPT6)},
+       { ITCO_PCI_DEVICE(0x1e47,                               TCO_PPT7)},
+       { ITCO_PCI_DEVICE(0x1e48,                               TCO_PPT8)},
+       { ITCO_PCI_DEVICE(0x1e49,                               TCO_PPT9)},
+       { ITCO_PCI_DEVICE(0x1e4a,                               TCO_PPT10)},
+       { ITCO_PCI_DEVICE(0x1e4b,                               TCO_PPT11)},
+       { ITCO_PCI_DEVICE(0x1e4c,                               TCO_PPT12)},
+       { ITCO_PCI_DEVICE(0x1e4d,                               TCO_PPT13)},
+       { ITCO_PCI_DEVICE(0x1e4e,                               TCO_PPT14)},
+       { ITCO_PCI_DEVICE(0x1e4f,                               TCO_PPT15)},
+       { ITCO_PCI_DEVICE(0x1e50,                               TCO_PPT16)},
+       { ITCO_PCI_DEVICE(0x1e51,                               TCO_PPT17)},
+       { ITCO_PCI_DEVICE(0x1e52,                               TCO_PPT18)},
+       { ITCO_PCI_DEVICE(0x1e53,                               TCO_PPT19)},
+       { ITCO_PCI_DEVICE(0x1e54,                               TCO_PPT20)},
+       { ITCO_PCI_DEVICE(0x1e55,                               TCO_PPT21)},
+       { ITCO_PCI_DEVICE(0x1e56,                               TCO_PPT22)},
+       { ITCO_PCI_DEVICE(0x1e57,                               TCO_PPT23)},
+       { ITCO_PCI_DEVICE(0x1e58,                               TCO_PPT24)},
+       { ITCO_PCI_DEVICE(0x1e59,                               TCO_PPT25)},
+       { ITCO_PCI_DEVICE(0x1e5a,                               TCO_PPT26)},
+       { ITCO_PCI_DEVICE(0x1e5b,                               TCO_PPT27)},
+       { ITCO_PCI_DEVICE(0x1e5c,                               TCO_PPT28)},
+       { ITCO_PCI_DEVICE(0x1e5d,                               TCO_PPT29)},
+       { ITCO_PCI_DEVICE(0x1e5e,                               TCO_PPT30)},
+       { ITCO_PCI_DEVICE(0x1e5f,                               TCO_PPT31)},
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
index 42d6c930cc87c3dab4ec512c6948ceb4a913e43f..33167b43ac7e4ad9ae981b53ad6ee9069d453296 100644 (file)
@@ -912,8 +912,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
                              unsigned long irqflags,
                              const char *devname, void *dev_id)
 {
-       unsigned int irq;
-       int retval;
+       int irq, retval;
 
        irq = bind_evtchn_to_irq(evtchn);
        if (irq < 0)
@@ -955,8 +954,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
                            irq_handler_t handler,
                            unsigned long irqflags, const char *devname, void *dev_id)
 {
-       unsigned int irq;
-       int retval;
+       int irq, retval;
 
        irq = bind_virq_to_irq(virq, cpu);
        if (irq < 0)
index 95143dd6904daf459286079e769532f666014603..a2eee574784e801aec6463a8317267c24f928201 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/sysrq.h>
 #include <linux/stop_machine.h>
 #include <linux/freezer.h>
+#include <linux/syscore_ops.h>
 
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -61,7 +62,7 @@ static void xen_post_suspend(int cancelled)
        xen_mm_unpin_all();
 }
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 static int xen_suspend(void *data)
 {
        struct suspend_info *si = data;
@@ -70,8 +71,13 @@ static int xen_suspend(void *data)
        BUG_ON(!irqs_disabled());
 
        err = sysdev_suspend(PMSG_FREEZE);
+       if (!err) {
+               err = syscore_suspend();
+               if (err)
+                       sysdev_resume();
+       }
        if (err) {
-               printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
+               printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
                        err);
                return err;
        }
@@ -95,6 +101,7 @@ static int xen_suspend(void *data)
                xen_timer_resume();
        }
 
+       syscore_resume();
        sysdev_resume();
 
        return 0;
@@ -173,7 +180,7 @@ out:
 #endif
        shutting_down = SHUTDOWN_INVALID;
 }
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
 
 struct shutdown_handler {
        const char *command;
@@ -202,7 +209,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
                { "poweroff",   do_poweroff },
                { "halt",       do_poweroff },
                { "reboot",     do_reboot   },
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
                { "suspend",    do_suspend  },
 #endif
                {NULL, NULL},
index 0ee594569dcceb60f4ff795f48fe83c87003fd47..85b67ffa2a43eb184250b1a167eae215deaa0399 100644 (file)
@@ -286,11 +286,9 @@ static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid)
 
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
 {
-       int err, flags;
+       int err;
        struct p9_fid *fid;
-       struct v9fs_session_info *v9ses;
 
-       v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_clone_with_uid(dentry, 0);
        if (IS_ERR(fid))
                goto error_out;
@@ -299,17 +297,8 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
         * dirty pages. We always request for the open fid in read-write
         * mode so that a partial page write which result in page
         * read can work.
-        *
-        * we don't have a tsyncfs operation for older version
-        * of protocol. So make sure the write back fid is
-        * opened in O_SYNC mode.
         */
-       if (!v9fs_proto_dotl(v9ses))
-               flags = O_RDWR | O_SYNC;
-       else
-               flags = O_RDWR;
-
-       err = p9_client_open(fid, flags);
+       err = p9_client_open(fid, O_RDWR);
        if (err < 0) {
                p9_client_clunk(fid);
                fid = ERR_PTR(err);
index 9665c2b840e6442a11b550f59da6ddf0ed73f256..e5ebedfc5ed8d345e366cd1482978a2ff2f2e4ae 100644 (file)
@@ -116,7 +116,6 @@ struct v9fs_session_info {
        struct list_head slist; /* list of sessions registered with v9fs */
        struct backing_dev_info bdi;
        struct rw_semaphore rename_sem;
-       struct p9_fid *root_fid; /* Used for file system sync */
 };
 
 /* cache_validity flags */
index b6a3b9f7fe4d85c428ce6ccacf3d84826075d24c..e022890c6f403283b4da166b7c56e4a27e14b975 100644 (file)
@@ -126,7 +126,9 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
                        retval = v9fs_refresh_inode_dotl(fid, inode);
                else
                        retval = v9fs_refresh_inode(fid, inode);
-               if (retval <= 0)
+               if (retval == -ENOENT)
+                       return 0;
+               if (retval < 0)
                        return retval;
        }
 out_valid:
index ffbb113d5f33537892fd001dd0d75af9e6d1fd69..82a7c38ddad0dec0c9ecded6fcc4d3eb93a50350 100644 (file)
@@ -811,7 +811,7 @@ v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid)) {
                __putname(link);
-               link = ERR_PTR(PTR_ERR(fid));
+               link = ERR_CAST(fid);
                goto ndset;
        }
        retval = p9_client_readlink(fid, &target);
index f3eed3383e4fdeb87dddc890ad732925f0245319..feef6cdc1fd22d23ba45a8f98f2f21ec0a0dc95a 100644 (file)
@@ -154,6 +154,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                retval = PTR_ERR(inode);
                goto release_sb;
        }
+
        root = d_alloc_root(inode);
        if (!root) {
                iput(inode);
@@ -185,21 +186,10 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                p9stat_free(st);
                kfree(st);
        }
-       v9fs_fid_add(root, fid);
        retval = v9fs_get_acl(inode, fid);
        if (retval)
                goto release_sb;
-       /*
-        * Add the root fid to session info. This is used
-        * for file system sync. We want a cloned fid here
-        * so that we can do a sync_filesystem after a
-        * shrink_dcache_for_umount
-        */
-       v9ses->root_fid = v9fs_fid_clone(root);
-       if (IS_ERR(v9ses->root_fid)) {
-               retval = PTR_ERR(v9ses->root_fid);
-               goto release_sb;
-       }
+       v9fs_fid_add(root, fid);
 
        P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
        return dget(sb->s_root);
@@ -210,11 +200,15 @@ close_session:
        v9fs_session_close(v9ses);
        kfree(v9ses);
        return ERR_PTR(retval);
+
 release_sb:
        /*
-        * we will do the session_close and root dentry
-        * release in the below call.
+        * we will do the session_close and root dentry release
+        * in the below call. But we need to clunk fid, because we haven't
+        * attached the fid to dentry so it won't get clunked
+        * automatically.
         */
+       p9_client_clunk(fid);
        deactivate_locked_super(sb);
        return ERR_PTR(retval);
 }
@@ -232,7 +226,7 @@ static void v9fs_kill_super(struct super_block *s)
        P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
 
        kill_anon_super(s);
-       p9_client_clunk(v9ses->root_fid);
+
        v9fs_session_cancel(v9ses);
        v9fs_session_close(v9ses);
        kfree(v9ses);
@@ -285,14 +279,6 @@ done:
        return res;
 }
 
-static int v9fs_sync_fs(struct super_block *sb, int wait)
-{
-       struct v9fs_session_info *v9ses = sb->s_fs_info;
-
-       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_sync_fs: super_block %p\n", sb);
-       return p9_client_sync_fs(v9ses->root_fid);
-}
-
 static int v9fs_drop_inode(struct inode *inode)
 {
        struct v9fs_session_info *v9ses;
@@ -307,6 +293,51 @@ static int v9fs_drop_inode(struct inode *inode)
        return 1;
 }
 
+static int v9fs_write_inode(struct inode *inode,
+                           struct writeback_control *wbc)
+{
+       int ret;
+       struct p9_wstat wstat;
+       struct v9fs_inode *v9inode;
+       /*
+        * send an fsync request to server irrespective of
+        * wbc->sync_mode.
+        */
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
+       v9inode = V9FS_I(inode);
+       if (!v9inode->writeback_fid)
+               return 0;
+       v9fs_blank_wstat(&wstat);
+
+       ret = p9_client_wstat(v9inode->writeback_fid, &wstat);
+       if (ret < 0) {
+               __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+               return ret;
+       }
+       return 0;
+}
+
+static int v9fs_write_inode_dotl(struct inode *inode,
+                                struct writeback_control *wbc)
+{
+       int ret;
+       struct v9fs_inode *v9inode;
+       /*
+        * send an fsync request to server irrespective of
+        * wbc->sync_mode.
+        */
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
+       v9inode = V9FS_I(inode);
+       if (!v9inode->writeback_fid)
+               return 0;
+       ret = p9_client_fsync(v9inode->writeback_fid, 0);
+       if (ret < 0) {
+               __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+               return ret;
+       }
+       return 0;
+}
+
 static const struct super_operations v9fs_super_ops = {
        .alloc_inode = v9fs_alloc_inode,
        .destroy_inode = v9fs_destroy_inode,
@@ -314,17 +345,18 @@ static const struct super_operations v9fs_super_ops = {
        .evict_inode = v9fs_evict_inode,
        .show_options = generic_show_options,
        .umount_begin = v9fs_umount_begin,
+       .write_inode = v9fs_write_inode,
 };
 
 static const struct super_operations v9fs_super_ops_dotl = {
        .alloc_inode = v9fs_alloc_inode,
        .destroy_inode = v9fs_destroy_inode,
-       .sync_fs = v9fs_sync_fs,
        .statfs = v9fs_statfs,
        .drop_inode = v9fs_drop_inode,
        .evict_inode = v9fs_evict_inode,
        .show_options = generic_show_options,
        .umount_begin = v9fs_umount_begin,
+       .write_inode = v9fs_write_inode_dotl,
 };
 
 struct file_system_type v9fs_fs_type = {
index f34078d702d3bdbe1ee69bc1122b63d3facf5009..303983fabfd63391f3961a58be352303b7af0064 100644 (file)
@@ -941,9 +941,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        current->mm->start_stack = bprm->p;
 
 #ifdef arch_randomize_brk
-       if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
+       if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
                current->mm->brk = current->mm->start_brk =
                        arch_randomize_brk(current->mm);
+#ifdef CONFIG_COMPAT_BRK
+               current->brk_randomized = 1;
+#endif
+       }
 #endif
 
        if (current->personality & MMAP_PAGE_ZERO) {
index de34bfad9ec3cab33f35ead4f31d9605f48af66c..5d505aaa72fb8326eb451687590b336c2e04052a 100644 (file)
@@ -178,16 +178,17 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
 
        if (value) {
                acl = posix_acl_from_xattr(value, size);
-               if (acl == NULL) {
-                       value = NULL;
-                       size = 0;
+               if (acl) {
+                       ret = posix_acl_valid(acl);
+                       if (ret)
+                               goto out;
                } else if (IS_ERR(acl)) {
                        return PTR_ERR(acl);
                }
        }
 
        ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
-
+out:
        posix_acl_release(acl);
 
        return ret;
index 3458b5725540c511103421bf8f1749833c2998f7..8f4b81de3ae2a0ffb21b57080de5649d9a3785ff 100644 (file)
@@ -718,7 +718,7 @@ struct btrfs_space_info {
        u64 total_bytes;        /* total bytes in the space,
                                   this doesn't take mirrors into account */
        u64 bytes_used;         /* total bytes used,
-                                  this does't take mirrors into account */
+                                  this doesn't take mirrors into account */
        u64 bytes_pinned;       /* total bytes pinned, will be freed when the
                                   transaction finishes */
        u64 bytes_reserved;     /* total bytes the allocator has reserved for
@@ -740,8 +740,10 @@ struct btrfs_space_info {
         */
        unsigned long reservation_progress;
 
-       int full;               /* indicates that we cannot allocate any more
+       int full:1;             /* indicates that we cannot allocate any more
                                   chunks for this space */
+       int chunk_alloc:1;      /* set if we are allocating a chunk */
+
        int force_alloc;        /* set if we need to force a chunk alloc for
                                   this space */
 
@@ -2576,6 +2578,11 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
 int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
                              struct inode *inode, u64 start, u64 end);
 int btrfs_release_file(struct inode *inode, struct file *file);
+void btrfs_drop_pages(struct page **pages, size_t num_pages);
+int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
+                     struct page **pages, size_t num_pages,
+                     loff_t pos, size_t write_bytes,
+                     struct extent_state **cached);
 
 /* tree-defrag.c */
 int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
index 8f1d44ba332f487aa42e3291daa63e45b04d44e0..228cf36ece8351475d5075f74e15624e4276e112 100644 (file)
@@ -2824,6 +2824,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 
        spin_lock(&delayed_refs->lock);
        if (delayed_refs->num_entries == 0) {
+               spin_unlock(&delayed_refs->lock);
                printk(KERN_INFO "delayed_refs has NO entry\n");
                return ret;
        }
@@ -3057,7 +3058,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
                btrfs_destroy_pinned_extent(root,
                                            root->fs_info->pinned_extents);
 
-               t->use_count = 0;
+               atomic_set(&t->use_count, 0);
                list_del_init(&t->list);
                memset(t, 0, sizeof(*t));
                kmem_cache_free(btrfs_transaction_cachep, t);
index f619c3cb13b7006cc7f95e273996917bbcebcf67..cd52f7f556efb753bc05138cb3e62e1f72a30354 100644 (file)
 #include "locking.h"
 #include "free-space-cache.h"
 
+/* control flags for do_chunk_alloc's force field
+ * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk
+ * if we really need one.
+ *
+ * CHUNK_ALLOC_FORCE means it must try to allocate one
+ *
+ * CHUNK_ALLOC_LIMITED means to only try and allocate one
+ * if we have very few chunks already allocated.  This is
+ * used as part of the clustering code to help make sure
+ * we have a good pool of storage to cluster in, without
+ * filling the FS with empty chunks
+ *
+ */
+enum {
+       CHUNK_ALLOC_NO_FORCE = 0,
+       CHUNK_ALLOC_FORCE = 1,
+       CHUNK_ALLOC_LIMITED = 2,
+};
+
 static int update_block_group(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              u64 bytenr, u64 num_bytes, int alloc);
@@ -3019,7 +3038,8 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->bytes_readonly = 0;
        found->bytes_may_use = 0;
        found->full = 0;
-       found->force_alloc = 0;
+       found->force_alloc = CHUNK_ALLOC_NO_FORCE;
+       found->chunk_alloc = 0;
        *space_info = found;
        list_add_rcu(&found->list, &info->space_info);
        atomic_set(&found->caching_threads, 0);
@@ -3150,7 +3170,7 @@ again:
                if (!data_sinfo->full && alloc_chunk) {
                        u64 alloc_target;
 
-                       data_sinfo->force_alloc = 1;
+                       data_sinfo->force_alloc = CHUNK_ALLOC_FORCE;
                        spin_unlock(&data_sinfo->lock);
 alloc:
                        alloc_target = btrfs_get_alloc_profile(root, 1);
@@ -3160,7 +3180,8 @@ alloc:
 
                        ret = do_chunk_alloc(trans, root->fs_info->extent_root,
                                             bytes + 2 * 1024 * 1024,
-                                            alloc_target, 0);
+                                            alloc_target,
+                                            CHUNK_ALLOC_NO_FORCE);
                        btrfs_end_transaction(trans, root);
                        if (ret < 0) {
                                if (ret != -ENOSPC)
@@ -3239,31 +3260,56 @@ static void force_metadata_allocation(struct btrfs_fs_info *info)
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
                if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
-                       found->force_alloc = 1;
+                       found->force_alloc = CHUNK_ALLOC_FORCE;
        }
        rcu_read_unlock();
 }
 
 static int should_alloc_chunk(struct btrfs_root *root,
-                             struct btrfs_space_info *sinfo, u64 alloc_bytes)
+                             struct btrfs_space_info *sinfo, u64 alloc_bytes,
+                             int force)
 {
        u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly;
+       u64 num_allocated = sinfo->bytes_used + sinfo->bytes_reserved;
        u64 thresh;
 
-       if (sinfo->bytes_used + sinfo->bytes_reserved +
-           alloc_bytes + 256 * 1024 * 1024 < num_bytes)
+       if (force == CHUNK_ALLOC_FORCE)
+               return 1;
+
+       /*
+        * in limited mode, we want to have some free space up to
+        * about 1% of the FS size.
+        */
+       if (force == CHUNK_ALLOC_LIMITED) {
+               thresh = btrfs_super_total_bytes(&root->fs_info->super_copy);
+               thresh = max_t(u64, 64 * 1024 * 1024,
+                              div_factor_fine(thresh, 1));
+
+               if (num_bytes - num_allocated < thresh)
+                       return 1;
+       }
+
+       /*
+        * we have two similar checks here, one based on percentage
+        * and once based on a hard number of 256MB.  The idea
+        * is that if we have a good amount of free
+        * room, don't allocate a chunk.  A good mount is
+        * less than 80% utilized of the chunks we have allocated,
+        * or more than 256MB free
+        */
+       if (num_allocated + alloc_bytes + 256 * 1024 * 1024 < num_bytes)
                return 0;
 
-       if (sinfo->bytes_used + sinfo->bytes_reserved +
-           alloc_bytes < div_factor(num_bytes, 8))
+       if (num_allocated + alloc_bytes < div_factor(num_bytes, 8))
                return 0;
 
        thresh = btrfs_super_total_bytes(&root->fs_info->super_copy);
+
+       /* 256MB or 5% of the FS */
        thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5));
 
        if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 3))
                return 0;
-
        return 1;
 }
 
@@ -3273,10 +3319,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
 {
        struct btrfs_space_info *space_info;
        struct btrfs_fs_info *fs_info = extent_root->fs_info;
+       int wait_for_alloc = 0;
        int ret = 0;
 
-       mutex_lock(&fs_info->chunk_mutex);
-
        flags = btrfs_reduce_alloc_profile(extent_root, flags);
 
        space_info = __find_space_info(extent_root->fs_info, flags);
@@ -3287,21 +3332,40 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
        }
        BUG_ON(!space_info);
 
+again:
        spin_lock(&space_info->lock);
        if (space_info->force_alloc)
-               force = 1;
+               force = space_info->force_alloc;
        if (space_info->full) {
                spin_unlock(&space_info->lock);
-               goto out;
+               return 0;
        }
 
-       if (!force && !should_alloc_chunk(extent_root, space_info,
-                                         alloc_bytes)) {
+       if (!should_alloc_chunk(extent_root, space_info, alloc_bytes, force)) {
                spin_unlock(&space_info->lock);
-               goto out;
+               return 0;
+       } else if (space_info->chunk_alloc) {
+               wait_for_alloc = 1;
+       } else {
+               space_info->chunk_alloc = 1;
        }
+
        spin_unlock(&space_info->lock);
 
+       mutex_lock(&fs_info->chunk_mutex);
+
+       /*
+        * The chunk_mutex is held throughout the entirety of a chunk
+        * allocation, so once we've acquired the chunk_mutex we know that the
+        * other guy is done and we need to recheck and see if we should
+        * allocate.
+        */
+       if (wait_for_alloc) {
+               mutex_unlock(&fs_info->chunk_mutex);
+               wait_for_alloc = 0;
+               goto again;
+       }
+
        /*
         * If we have mixed data/metadata chunks we want to make sure we keep
         * allocating mixed chunks instead of individual chunks.
@@ -3327,9 +3391,10 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                space_info->full = 1;
        else
                ret = 1;
-       space_info->force_alloc = 0;
+
+       space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
+       space_info->chunk_alloc = 0;
        spin_unlock(&space_info->lock);
-out:
        mutex_unlock(&extent_root->fs_info->chunk_mutex);
        return ret;
 }
@@ -5303,11 +5368,13 @@ loop:
 
                if (allowed_chunk_alloc) {
                        ret = do_chunk_alloc(trans, root, num_bytes +
-                                            2 * 1024 * 1024, data, 1);
+                                            2 * 1024 * 1024, data,
+                                            CHUNK_ALLOC_LIMITED);
                        allowed_chunk_alloc = 0;
                        done_chunk_alloc = 1;
-               } else if (!done_chunk_alloc) {
-                       space_info->force_alloc = 1;
+               } else if (!done_chunk_alloc &&
+                          space_info->force_alloc == CHUNK_ALLOC_NO_FORCE) {
+                       space_info->force_alloc = CHUNK_ALLOC_LIMITED;
                }
 
                if (loop < LOOP_NO_EMPTY_SIZE) {
@@ -5393,7 +5460,8 @@ again:
         */
        if (empty_size || root->ref_cows)
                ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                    num_bytes + 2 * 1024 * 1024, data, 0);
+                                    num_bytes + 2 * 1024 * 1024, data,
+                                    CHUNK_ALLOC_NO_FORCE);
 
        WARN_ON(num_bytes < root->sectorsize);
        ret = find_free_extent(trans, root, num_bytes, empty_size,
@@ -5405,7 +5473,7 @@ again:
                num_bytes = num_bytes & ~(root->sectorsize - 1);
                num_bytes = max(num_bytes, min_alloc_size);
                do_chunk_alloc(trans, root->fs_info->extent_root,
-                              num_bytes, data, 1);
+                              num_bytes, data, CHUNK_ALLOC_FORCE);
                goto again;
        }
        if (ret == -ENOSPC && btrfs_test_opt(root, ENOSPC_DEBUG)) {
@@ -7991,6 +8059,10 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root,
                                u64 group_start = group->key.objectid;
                                new_extents = kmalloc(sizeof(*new_extents),
                                                      GFP_NOFS);
+                               if (!new_extents) {
+                                       ret = -ENOMEM;
+                                       goto out;
+                               }
                                nr_extents = 1;
                                ret = get_new_locations(reloc_inode,
                                                        extent_key,
@@ -8109,13 +8181,15 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
 
        alloc_flags = update_block_group_flags(root, cache->flags);
        if (alloc_flags != cache->flags)
-               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                              CHUNK_ALLOC_FORCE);
 
        ret = set_block_group_ro(cache);
        if (!ret)
                goto out;
        alloc_flags = get_alloc_profile(root, cache->space_info->flags);
-       ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+       ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                            CHUNK_ALLOC_FORCE);
        if (ret < 0)
                goto out;
        ret = set_block_group_ro(cache);
@@ -8128,7 +8202,8 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root, u64 type)
 {
        u64 alloc_flags = get_alloc_profile(root, type);
-       return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+       return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                             CHUNK_ALLOC_FORCE);
 }
 
 /*
index 20ddb28602a8fa0c0eb4c082966741f2f7fd15c8..ba41da59e31b1d93348622d7b47655234f5ff930 100644 (file)
@@ -690,6 +690,15 @@ static void cache_state(struct extent_state *state,
        }
 }
 
+static void uncache_state(struct extent_state **cached_ptr)
+{
+       if (cached_ptr && (*cached_ptr)) {
+               struct extent_state *state = *cached_ptr;
+               *cached_ptr = NULL;
+               free_extent_state(state);
+       }
+}
+
 /*
  * set some bits on a range in the tree.  This may require allocations or
  * sleeping, so the gfp mask is used to indicate what is allowed.
@@ -940,10 +949,10 @@ static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
 }
 
 int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
-                       gfp_t mask)
+                       struct extent_state **cached_state, gfp_t mask)
 {
-       return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, NULL,
-                             NULL, mask);
+       return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0,
+                             NULL, cached_state, mask);
 }
 
 static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
@@ -1012,8 +1021,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
                                mask);
 }
 
-int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
-                 gfp_t mask)
+int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
 {
        return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL,
                                mask);
@@ -1735,6 +1743,9 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
 
        do {
                struct page *page = bvec->bv_page;
+               struct extent_state *cached = NULL;
+               struct extent_state *state;
+
                tree = &BTRFS_I(page->mapping->host)->io_tree;
 
                start = ((u64)page->index << PAGE_CACHE_SHIFT) +
@@ -1749,9 +1760,20 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                if (++bvec <= bvec_end)
                        prefetchw(&bvec->bv_page->flags);
 
+               spin_lock(&tree->lock);
+               state = find_first_extent_bit_state(tree, start, EXTENT_LOCKED);
+               if (state && state->start == start) {
+                       /*
+                        * take a reference on the state, unlock will drop
+                        * the ref
+                        */
+                       cache_state(state, &cached);
+               }
+               spin_unlock(&tree->lock);
+
                if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
                        ret = tree->ops->readpage_end_io_hook(page, start, end,
-                                                             NULL);
+                                                             state);
                        if (ret)
                                uptodate = 0;
                }
@@ -1764,15 +1786,16 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                                        test_bit(BIO_UPTODATE, &bio->bi_flags);
                                if (err)
                                        uptodate = 0;
+                               uncache_state(&cached);
                                continue;
                        }
                }
 
                if (uptodate) {
-                       set_extent_uptodate(tree, start, end,
+                       set_extent_uptodate(tree, start, end, &cached,
                                            GFP_ATOMIC);
                }
-               unlock_extent(tree, start, end, GFP_ATOMIC);
+               unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC);
 
                if (whole_page) {
                        if (uptodate) {
@@ -1811,6 +1834,7 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err)
 
        do {
                struct page *page = bvec->bv_page;
+               struct extent_state *cached = NULL;
                tree = &BTRFS_I(page->mapping->host)->io_tree;
 
                start = ((u64)page->index << PAGE_CACHE_SHIFT) +
@@ -1821,13 +1845,14 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err)
                        prefetchw(&bvec->bv_page->flags);
 
                if (uptodate) {
-                       set_extent_uptodate(tree, start, end, GFP_ATOMIC);
+                       set_extent_uptodate(tree, start, end, &cached,
+                                           GFP_ATOMIC);
                } else {
                        ClearPageUptodate(page);
                        SetPageError(page);
                }
 
-               unlock_extent(tree, start, end, GFP_ATOMIC);
+               unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC);
 
        } while (bvec >= bio->bi_io_vec);
 
@@ -2016,14 +2041,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
        while (cur <= end) {
                if (cur >= last_byte) {
                        char *userpage;
+                       struct extent_state *cached = NULL;
+
                        iosize = PAGE_CACHE_SIZE - page_offset;
                        userpage = kmap_atomic(page, KM_USER0);
                        memset(userpage + page_offset, 0, iosize);
                        flush_dcache_page(page);
                        kunmap_atomic(userpage, KM_USER0);
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
-                                           GFP_NOFS);
-                       unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
+                                           &cached, GFP_NOFS);
+                       unlock_extent_cached(tree, cur, cur + iosize - 1,
+                                            &cached, GFP_NOFS);
                        break;
                }
                em = get_extent(inode, page, page_offset, cur,
@@ -2063,14 +2091,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                /* we've found a hole, just zero and go on */
                if (block_start == EXTENT_MAP_HOLE) {
                        char *userpage;
+                       struct extent_state *cached = NULL;
+
                        userpage = kmap_atomic(page, KM_USER0);
                        memset(userpage + page_offset, 0, iosize);
                        flush_dcache_page(page);
                        kunmap_atomic(userpage, KM_USER0);
 
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
-                                           GFP_NOFS);
-                       unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
+                                           &cached, GFP_NOFS);
+                       unlock_extent_cached(tree, cur, cur + iosize - 1,
+                                            &cached, GFP_NOFS);
                        cur = cur + iosize;
                        page_offset += iosize;
                        continue;
@@ -2650,7 +2681,7 @@ int extent_readpages(struct extent_io_tree *tree,
                prefetchw(&page->flags);
                list_del(&page->lru);
                if (!add_to_page_cache_lru(page, mapping,
-                                       page->index, GFP_KERNEL)) {
+                                       page->index, GFP_NOFS)) {
                        __extent_read_full_page(tree, page, get_extent,
                                                &bio, 0, &bio_flags);
                }
@@ -2789,9 +2820,12 @@ int extent_prepare_write(struct extent_io_tree *tree,
                        iocount++;
                        block_start = block_start + iosize;
                } else {
-                       set_extent_uptodate(tree, block_start, cur_end,
+                       struct extent_state *cached = NULL;
+
+                       set_extent_uptodate(tree, block_start, cur_end, &cached,
                                            GFP_NOFS);
-                       unlock_extent(tree, block_start, cur_end, GFP_NOFS);
+                       unlock_extent_cached(tree, block_start, cur_end,
+                                            &cached, GFP_NOFS);
                        block_start = cur_end + 1;
                }
                page_offset = block_start & (PAGE_CACHE_SIZE - 1);
@@ -3457,7 +3491,7 @@ int set_extent_buffer_uptodate(struct extent_io_tree *tree,
        num_pages = num_extent_pages(eb->start, eb->len);
 
        set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-                           GFP_NOFS);
+                           NULL, GFP_NOFS);
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) ||
@@ -3885,6 +3919,12 @@ static void move_pages(struct page *dst_page, struct page *src_page,
        kunmap_atomic(dst_kaddr, KM_USER0);
 }
 
+static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
+{
+       unsigned long distance = (src > dst) ? src - dst : dst - src;
+       return distance < len;
+}
+
 static void copy_pages(struct page *dst_page, struct page *src_page,
                       unsigned long dst_off, unsigned long src_off,
                       unsigned long len)
@@ -3892,10 +3932,12 @@ static void copy_pages(struct page *dst_page, struct page *src_page,
        char *dst_kaddr = kmap_atomic(dst_page, KM_USER0);
        char *src_kaddr;
 
-       if (dst_page != src_page)
+       if (dst_page != src_page) {
                src_kaddr = kmap_atomic(src_page, KM_USER1);
-       else
+       } else {
                src_kaddr = dst_kaddr;
+               BUG_ON(areas_overlap(src_off, dst_off, len));
+       }
 
        memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len);
        kunmap_atomic(dst_kaddr, KM_USER0);
@@ -3970,7 +4012,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                       "len %lu len %lu\n", dst_offset, len, dst->len);
                BUG_ON(1);
        }
-       if (dst_offset < src_offset) {
+       if (!areas_overlap(src_offset, dst_offset, len)) {
                memcpy_extent_buffer(dst, dst_offset, src_offset, len);
                return;
        }
index f62c5442835d1ab70da88d510ef6e073d050c794..af2d7179c37288f50371bfd2ffa5dd307b16af00 100644 (file)
@@ -208,7 +208,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                   int bits, int exclusive_bits, u64 *failed_start,
                   struct extent_state **cached_state, gfp_t mask);
 int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
-                       gfp_t mask);
+                       struct extent_state **cached_state, gfp_t mask);
 int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
                   gfp_t mask);
 int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
index e621ea54a3fd64bcf3dae29e4f96e887b6eff95c..75899a01dded75042b4c99f15a44cc83882730a4 100644 (file)
@@ -104,7 +104,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
 /*
  * unlocks pages after btrfs_file_write is done with them
  */
-static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
+void btrfs_drop_pages(struct page **pages, size_t num_pages)
 {
        size_t i;
        for (i = 0; i < num_pages; i++) {
@@ -127,16 +127,13 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
  * this also makes the decision about creating an inline extent vs
  * doing real data extents, marking pages dirty and delalloc as required.
  */
-static noinline int dirty_and_release_pages(struct btrfs_root *root,
-                                           struct file *file,
-                                           struct page **pages,
-                                           size_t num_pages,
-                                           loff_t pos,
-                                           size_t write_bytes)
+int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
+                     struct page **pages, size_t num_pages,
+                     loff_t pos, size_t write_bytes,
+                     struct extent_state **cached)
 {
        int err = 0;
        int i;
-       struct inode *inode = fdentry(file)->d_inode;
        u64 num_bytes;
        u64 start_pos;
        u64 end_of_last_block;
@@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root,
 
        end_of_last_block = start_pos + num_bytes - 1;
        err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
-                                       NULL);
+                                       cached);
        if (err)
                return err;
 
@@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                }
 
                if (copied > 0) {
-                       ret = dirty_and_release_pages(root, file, pages,
-                                                     dirty_pages, pos,
-                                                     copied);
+                       ret = btrfs_dirty_pages(root, inode, pages,
+                                               dirty_pages, pos, copied,
+                                               NULL);
                        if (ret) {
                                btrfs_delalloc_release_space(inode,
                                        dirty_pages << PAGE_CACHE_SHIFT);
index f561c953205bfb5dca0c53608c1770388a9db875..63731a1fb0a1f9004e892a31e121ae977a9eff3a 100644 (file)
@@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
        struct inode *inode;
        struct rb_node *node;
        struct list_head *pos, *n;
+       struct page **pages;
        struct page *page;
        struct extent_state *cached_state = NULL;
        struct btrfs_free_cluster *cluster = NULL;
@@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root,
        u64 start, end, len;
        u64 bytes = 0;
        u32 *crc, *checksums;
-       pgoff_t index = 0, last_index = 0;
        unsigned long first_page_offset;
-       int num_checksums;
+       int index = 0, num_pages = 0;
        int entries = 0;
        int bitmaps = 0;
        int ret = 0;
        bool next_page = false;
+       bool out_of_space = false;
 
        root = root->fs_info->tree_root;
 
@@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                return 0;
        }
 
-       last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
+       num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+               PAGE_CACHE_SHIFT;
        filemap_write_and_wait(inode->i_mapping);
        btrfs_wait_ordered_range(inode, inode->i_size &
                                 ~(root->sectorsize - 1), (u64)-1);
 
        /* We need a checksum per page. */
-       num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE;
-       crc = checksums  = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS);
+       crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS);
        if (!crc) {
                iput(inode);
                return 0;
        }
 
+       pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
+       if (!pages) {
+               kfree(crc);
+               iput(inode);
+               return 0;
+       }
+
        /* Since the first page has all of our checksums and our generation we
         * need to calculate the offset into the page that we can start writing
         * our entries.
         */
-       first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
+       first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);
 
        /* Get the cluster for this block_group if it exists */
        if (!list_empty(&block_group->cluster_list))
@@ -590,20 +598,18 @@ int btrfs_write_out_cache(struct btrfs_root *root,
         * after find_get_page at this point.  Just putting this here so people
         * know and don't freak out.
         */
-       while (index <= last_index) {
+       while (index < num_pages) {
                page = grab_cache_page(inode->i_mapping, index);
                if (!page) {
-                       pgoff_t i = 0;
+                       int i;
 
-                       while (i < index) {
-                               page = find_get_page(inode->i_mapping, i);
-                               unlock_page(page);
-                               page_cache_release(page);
-                               page_cache_release(page);
-                               i++;
+                       for (i = 0; i < num_pages; i++) {
+                               unlock_page(pages[i]);
+                               page_cache_release(pages[i]);
                        }
                        goto out_free;
                }
+               pages[index] = page;
                index++;
        }
 
@@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                        offset = start_offset;
                }
 
-               page = find_get_page(inode->i_mapping, index);
+               if (index >= num_pages) {
+                       out_of_space = true;
+                       break;
+               }
+
+               page = pages[index];
 
                addr = kmap(page);
                entry = addr + start_offset;
@@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root,
 
                bytes += PAGE_CACHE_SIZE;
 
-               ClearPageChecked(page);
-               set_page_extent_mapped(page);
-               SetPageUptodate(page);
-               set_page_dirty(page);
-
-               /*
-                * We need to release our reference we got for grab_cache_page,
-                * except for the first page which will hold our checksums, we
-                * do that below.
-                */
-               if (index != 0) {
-                       unlock_page(page);
-                       page_cache_release(page);
-               }
-
-               page_cache_release(page);
-
                index++;
        } while (node || next_page);
 
@@ -734,7 +728,11 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                struct btrfs_free_space *entry =
                        list_entry(pos, struct btrfs_free_space, list);
 
-               page = find_get_page(inode->i_mapping, index);
+               if (index >= num_pages) {
+                       out_of_space = true;
+                       break;
+               }
+               page = pages[index];
 
                addr = kmap(page);
                memcpy(addr, entry->bitmap, PAGE_CACHE_SIZE);
@@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                crc++;
                bytes += PAGE_CACHE_SIZE;
 
-               ClearPageChecked(page);
-               set_page_extent_mapped(page);
-               SetPageUptodate(page);
-               set_page_dirty(page);
-               unlock_page(page);
-               page_cache_release(page);
-               page_cache_release(page);
                list_del_init(&entry->list);
                index++;
        }
 
+       if (out_of_space) {
+               btrfs_drop_pages(pages, num_pages);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
+                                    i_size_read(inode) - 1, &cached_state,
+                                    GFP_NOFS);
+               ret = 0;
+               goto out_free;
+       }
+
        /* Zero out the rest of the pages just to make sure */
-       while (index <= last_index) {
+       while (index < num_pages) {
                void *addr;
 
-               page = find_get_page(inode->i_mapping, index);
-
+               page = pages[index];
                addr = kmap(page);
                memset(addr, 0, PAGE_CACHE_SIZE);
                kunmap(page);
-               ClearPageChecked(page);
-               set_page_extent_mapped(page);
-               SetPageUptodate(page);
-               set_page_dirty(page);
-               unlock_page(page);
-               page_cache_release(page);
-               page_cache_release(page);
                bytes += PAGE_CACHE_SIZE;
                index++;
        }
 
-       btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state);
-
        /* Write the checksums and trans id to the first page */
        {
                void *addr;
                u64 *gen;
 
-               page = find_get_page(inode->i_mapping, 0);
+               page = pages[0];
 
                addr = kmap(page);
-               memcpy(addr, checksums, sizeof(u32) * num_checksums);
-               gen = addr + (sizeof(u32) * num_checksums);
+               memcpy(addr, checksums, sizeof(u32) * num_pages);
+               gen = addr + (sizeof(u32) * num_pages);
                *gen = trans->transid;
                kunmap(page);
-               ClearPageChecked(page);
-               set_page_extent_mapped(page);
-               SetPageUptodate(page);
-               set_page_dirty(page);
-               unlock_page(page);
-               page_cache_release(page);
-               page_cache_release(page);
        }
-       BTRFS_I(inode)->generation = trans->transid;
 
+       ret = btrfs_dirty_pages(root, inode, pages, num_pages, 0,
+                                           bytes, &cached_state);
+       btrfs_drop_pages(pages, num_pages);
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
                             i_size_read(inode) - 1, &cached_state, GFP_NOFS);
 
+       if (ret) {
+               ret = 0;
+               goto out_free;
+       }
+
+       BTRFS_I(inode)->generation = trans->transid;
+
        filemap_write_and_wait(inode->i_mapping);
 
        key.objectid = BTRFS_FREE_SPACE_OBJECTID;
@@ -853,6 +845,7 @@ out_free:
                BTRFS_I(inode)->generation = 0;
        }
        kfree(checksums);
+       kfree(pages);
        btrfs_update_inode(trans, root, inode);
        iput(inode);
        return ret;
@@ -1775,10 +1768,13 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
 
        while ((node = rb_last(&block_group->free_space_offset)) != NULL) {
                info = rb_entry(node, struct btrfs_free_space, offset_index);
-               unlink_free_space(block_group, info);
-               if (info->bitmap)
-                       kfree(info->bitmap);
-               kmem_cache_free(btrfs_free_space_cachep, info);
+               if (!info->bitmap) {
+                       unlink_free_space(block_group, info);
+                       kmem_cache_free(btrfs_free_space_cachep, info);
+               } else {
+                       free_bitmap(block_group, info);
+               }
+
                if (need_resched()) {
                        spin_unlock(&block_group->tree_lock);
                        cond_resched();
@@ -2308,7 +2304,7 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
                        start = entry->offset;
                        bytes = min(entry->bytes, end - start);
                        unlink_free_space(block_group, entry);
-                       kfree(entry);
+                       kmem_cache_free(btrfs_free_space_cachep, entry);
                }
 
                spin_unlock(&block_group->tree_lock);
index 5cc64ab9c4851c5b1fe9adbebabcf083c4581b14..7cd8ab0ef04d5b3e95ccd572f96ca858457e8c18 100644 (file)
@@ -954,6 +954,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
                         1, 0, NULL, GFP_NOFS);
        while (start < end) {
                async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
+               BUG_ON(!async_cow);
                async_cow->inode = inode;
                async_cow->root = root;
                async_cow->locked_page = locked_page;
@@ -1770,9 +1771,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
 
-       btrfs_ordered_update_i_size(inode, 0, ordered_extent);
-       ret = btrfs_update_inode(trans, root, inode);
-       BUG_ON(ret);
+       ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
+       if (!ret) {
+               ret = btrfs_update_inode(trans, root, inode);
+               BUG_ON(ret);
+       }
+       ret = 0;
 out:
        if (nolock) {
                if (trans)
@@ -2590,6 +2594,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
                            struct btrfs_inode_item *item,
                            struct inode *inode)
 {
+       if (!leaf->map_token)
+               map_private_extent_buffer(leaf, (unsigned long)item,
+                                         sizeof(struct btrfs_inode_item),
+                                         &leaf->map_token, &leaf->kaddr,
+                                         &leaf->map_start, &leaf->map_len,
+                                         KM_USER1);
+
        btrfs_set_inode_uid(leaf, item, inode->i_uid);
        btrfs_set_inode_gid(leaf, item, inode->i_gid);
        btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size);
@@ -2618,6 +2629,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
        btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
        btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
        btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
+
+       if (leaf->map_token) {
+               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
+               leaf->map_token = NULL;
+       }
 }
 
 /*
@@ -4207,10 +4223,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        struct btrfs_key found_key;
        struct btrfs_path *path;
        int ret;
-       u32 nritems;
        struct extent_buffer *leaf;
        int slot;
-       int advance;
        unsigned char d_type;
        int over = 0;
        u32 di_cur;
@@ -4253,27 +4267,19 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                goto err;
-       advance = 0;
 
        while (1) {
                leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
                slot = path->slots[0];
-               if (advance || slot >= nritems) {
-                       if (slot >= nritems - 1) {
-                               ret = btrfs_next_leaf(root, path);
-                               if (ret)
-                                       break;
-                               leaf = path->nodes[0];
-                               nritems = btrfs_header_nritems(leaf);
-                               slot = path->slots[0];
-                       } else {
-                               slot++;
-                               path->slots[0]++;
-                       }
+               if (slot >= btrfs_header_nritems(leaf)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               goto err;
+                       else if (ret > 0)
+                               break;
+                       continue;
                }
 
-               advance = 1;
                item = btrfs_item_nr(leaf, slot);
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
@@ -4282,7 +4288,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                if (btrfs_key_type(&found_key) != key_type)
                        break;
                if (found_key.offset < filp->f_pos)
-                       continue;
+                       goto next;
 
                filp->f_pos = found_key.offset;
 
@@ -4335,6 +4341,8 @@ skip:
                        di_cur += di_len;
                        di = (struct btrfs_dir_item *)((char *)di + di_len);
                }
+next:
+               path->slots[0]++;
        }
 
        /* Reached end of directory/root. Bump pos past the last item. */
@@ -4527,14 +4535,17 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        BUG_ON(!path);
 
        inode = new_inode(root->fs_info->sb);
-       if (!inode)
+       if (!inode) {
+               btrfs_free_path(path);
                return ERR_PTR(-ENOMEM);
+       }
 
        if (dir) {
                trace_btrfs_inode_request(dir);
 
                ret = btrfs_set_inode_index(dir, index);
                if (ret) {
+                       btrfs_free_path(path);
                        iput(inode);
                        return ERR_PTR(ret);
                }
@@ -4721,9 +4732,10 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, dir->i_ino, objectid,
                                BTRFS_I(dir)->block_group, mode, &index);
-       err = PTR_ERR(inode);
-       if (IS_ERR(inode))
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out_unlock;
+       }
 
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
@@ -4782,9 +4794,10 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, dir->i_ino, objectid,
                                BTRFS_I(dir)->block_group, mode, &index);
-       err = PTR_ERR(inode);
-       if (IS_ERR(inode))
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out_unlock;
+       }
 
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
@@ -4834,9 +4847,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        if (inode->i_nlink == ~0U)
                return -EMLINK;
 
-       btrfs_inc_nlink(inode);
-       inode->i_ctime = CURRENT_TIME;
-
        err = btrfs_set_inode_index(dir, &index);
        if (err)
                goto fail;
@@ -4852,6 +4862,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                goto fail;
        }
 
+       btrfs_inc_nlink(inode);
+       inode->i_ctime = CURRENT_TIME;
+
        btrfs_set_trans_block_group(trans, dir);
        ihold(inode);
 
@@ -4989,6 +5002,8 @@ static noinline int uncompress_inline(struct btrfs_path *path,
        inline_size = btrfs_file_extent_inline_item_len(leaf,
                                        btrfs_item_nr(leaf, path->slots[0]));
        tmp = kmalloc(inline_size, GFP_NOFS);
+       if (!tmp)
+               return -ENOMEM;
        ptr = btrfs_file_extent_inline_start(item);
 
        read_extent_buffer(leaf, tmp, ptr, inline_size);
@@ -5221,7 +5236,7 @@ again:
                        btrfs_mark_buffer_dirty(leaf);
                }
                set_extent_uptodate(io_tree, em->start,
-                                   extent_map_end(em) - 1, GFP_NOFS);
+                                   extent_map_end(em) - 1, NULL, GFP_NOFS);
                goto insert;
        } else {
                printk(KERN_ERR "btrfs unknown found_type %d\n", found_type);
@@ -5428,17 +5443,30 @@ out:
 }
 
 static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
+                                                 struct extent_map *em,
                                                  u64 start, u64 len)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
-       struct extent_map *em;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct btrfs_key ins;
        u64 alloc_hint;
        int ret;
+       bool insert = false;
 
-       btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
+       /*
+        * Ok if the extent map we looked up is a hole and is for the exact
+        * range we want, there is no reason to allocate a new one, however if
+        * it is not right then we need to free this one and drop the cache for
+        * our range.
+        */
+       if (em->block_start != EXTENT_MAP_HOLE || em->start != start ||
+           em->len != len) {
+               free_extent_map(em);
+               em = NULL;
+               insert = true;
+               btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
+       }
 
        trans = btrfs_join_transaction(root, 0);
        if (IS_ERR(trans))
@@ -5454,10 +5482,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                goto out;
        }
 
-       em = alloc_extent_map(GFP_NOFS);
        if (!em) {
-               em = ERR_PTR(-ENOMEM);
-               goto out;
+               em = alloc_extent_map(GFP_NOFS);
+               if (!em) {
+                       em = ERR_PTR(-ENOMEM);
+                       goto out;
+               }
        }
 
        em->start = start;
@@ -5467,9 +5497,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
        em->block_start = ins.objectid;
        em->block_len = ins.offset;
        em->bdev = root->fs_info->fs_devices->latest_bdev;
+
+       /*
+        * We need to do this because if we're using the original em we searched
+        * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that.
+        */
+       em->flags = 0;
        set_bit(EXTENT_FLAG_PINNED, &em->flags);
 
-       while (1) {
+       while (insert) {
                write_lock(&em_tree->lock);
                ret = add_extent_mapping(em_tree, em);
                write_unlock(&em_tree->lock);
@@ -5687,8 +5723,7 @@ must_cow:
         * it above
         */
        len = bh_result->b_size;
-       free_extent_map(em);
-       em = btrfs_new_extent_direct(inode, start, len);
+       em = btrfs_new_extent_direct(inode, em, start, len);
        if (IS_ERR(em))
                return PTR_ERR(em);
        len = min(len, em->len - (start - em->start));
@@ -5851,8 +5886,10 @@ again:
        }
 
        add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
-       btrfs_ordered_update_i_size(inode, 0, ordered);
-       btrfs_update_inode(trans, root, inode);
+       ret = btrfs_ordered_update_i_size(inode, 0, ordered);
+       if (!ret)
+               btrfs_update_inode(trans, root, inode);
+       ret = 0;
 out_unlock:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
                             ordered->file_offset + ordered->len - 1,
@@ -5938,7 +5975,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
 
 static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                                         int rw, u64 file_offset, int skip_sum,
-                                        u32 *csums)
+                                        u32 *csums, int async_submit)
 {
        int write = rw & REQ_WRITE;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -5949,13 +5986,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
        if (ret)
                goto err;
 
-       if (write && !skip_sum) {
+       if (skip_sum)
+               goto map;
+
+       if (write && async_submit) {
                ret = btrfs_wq_submit_bio(root->fs_info,
                                   inode, rw, bio, 0, 0,
                                   file_offset,
                                   __btrfs_submit_bio_start_direct_io,
                                   __btrfs_submit_bio_done);
                goto err;
+       } else if (write) {
+               /*
+                * If we aren't doing async submit, calculate the csum of the
+                * bio now.
+                */
+               ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1);
+               if (ret)
+                       goto err;
        } else if (!skip_sum) {
                ret = btrfs_lookup_bio_sums_dio(root, inode, bio,
                                          file_offset, csums);
@@ -5963,7 +6011,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                        goto err;
        }
 
-       ret = btrfs_map_bio(root, rw, bio, 0, 1);
+map:
+       ret = btrfs_map_bio(root, rw, bio, 0, async_submit);
 err:
        bio_put(bio);
        return ret;
@@ -5985,23 +6034,30 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        int nr_pages = 0;
        u32 *csums = dip->csums;
        int ret = 0;
+       int async_submit = 0;
        int write = rw & REQ_WRITE;
 
-       bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
-       if (!bio)
-               return -ENOMEM;
-       bio->bi_private = dip;
-       bio->bi_end_io = btrfs_end_dio_bio;
-       atomic_inc(&dip->pending_bios);
-
        map_length = orig_bio->bi_size;
        ret = btrfs_map_block(map_tree, READ, start_sector << 9,
                              &map_length, NULL, 0);
        if (ret) {
-               bio_put(bio);
+               bio_put(orig_bio);
                return -EIO;
        }
 
+       if (map_length >= orig_bio->bi_size) {
+               bio = orig_bio;
+               goto submit;
+       }
+
+       async_submit = 1;
+       bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
+       if (!bio)
+               return -ENOMEM;
+       bio->bi_private = dip;
+       bio->bi_end_io = btrfs_end_dio_bio;
+       atomic_inc(&dip->pending_bios);
+
        while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
                if (unlikely(map_length < submit_len + bvec->bv_len ||
                    bio_add_page(bio, bvec->bv_page, bvec->bv_len,
@@ -6015,7 +6071,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                        atomic_inc(&dip->pending_bios);
                        ret = __btrfs_submit_dio_bio(bio, inode, rw,
                                                     file_offset, skip_sum,
-                                                    csums);
+                                                    csums, async_submit);
                        if (ret) {
                                bio_put(bio);
                                atomic_dec(&dip->pending_bios);
@@ -6052,8 +6108,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                }
        }
 
+submit:
        ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
-                                    csums);
+                                    csums, async_submit);
        if (!ret)
                return 0;
 
@@ -6148,6 +6205,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io
                        unsigned long nr_segs)
 {
        int seg;
+       int i;
        size_t size;
        unsigned long addr;
        unsigned blocksize_mask = root->sectorsize - 1;
@@ -6162,8 +6220,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io
                addr = (unsigned long)iov[seg].iov_base;
                size = iov[seg].iov_len;
                end += size;
-               if ((addr & blocksize_mask) || (size & blocksize_mask)) 
+               if ((addr & blocksize_mask) || (size & blocksize_mask))
                        goto out;
+
+               /* If this is a write we don't need to check anymore */
+               if (rw & WRITE)
+                       continue;
+
+               /*
+                * Check to make sure we don't have duplicate iov_base's in this
+                * iovec, if so return EINVAL, otherwise we'll get csum errors
+                * when reading back.
+                */
+               for (i = seg + 1; i < nr_segs; i++) {
+                       if (iov[seg].iov_base == iov[i].iov_base)
+                               goto out;
+               }
        }
        retval = 0;
 out:
@@ -7206,9 +7278,10 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                                dentry->d_name.len, dir->i_ino, objectid,
                                BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
                                &index);
-       err = PTR_ERR(inode);
-       if (IS_ERR(inode))
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
                goto out_unlock;
+       }
 
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
index cfc264fefdb0e61d419673205304bf54ca285179..ffb48d6c54334ab8fe0d29ae4d69cfa1b22d613c 100644 (file)
@@ -2287,7 +2287,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
        struct btrfs_ioctl_space_info space;
        struct btrfs_ioctl_space_info *dest;
        struct btrfs_ioctl_space_info *dest_orig;
-       struct btrfs_ioctl_space_info *user_dest;
+       struct btrfs_ioctl_space_info __user *user_dest;
        struct btrfs_space_info *info;
        u64 types[] = {BTRFS_BLOCK_GROUP_DATA,
                       BTRFS_BLOCK_GROUP_SYSTEM,
index 58e7de9cc90cb47d2c4047acb9a8d14cdc933f40..0ac712efcdf293ac8e858fef443b57316b039037 100644 (file)
@@ -159,7 +159,7 @@ enum {
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
        Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
-       Opt_enospc_debug, Opt_err,
+       Opt_enospc_debug, Opt_subvolrootid, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -189,6 +189,7 @@ static match_table_t tokens = {
        {Opt_clear_cache, "clear_cache"},
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
        {Opt_enospc_debug, "enospc_debug"},
+       {Opt_subvolrootid, "subvolrootid=%d"},
        {Opt_err, NULL},
 };
 
@@ -232,6 +233,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        break;
                case Opt_subvol:
                case Opt_subvolid:
+               case Opt_subvolrootid:
                case Opt_device:
                        /*
                         * These are parsed by btrfs_parse_early_options
@@ -388,7 +390,7 @@ out:
  */
 static int btrfs_parse_early_options(const char *options, fmode_t flags,
                void *holder, char **subvol_name, u64 *subvol_objectid,
-               struct btrfs_fs_devices **fs_devices)
+               u64 *subvol_rootid, struct btrfs_fs_devices **fs_devices)
 {
        substring_t args[MAX_OPT_ARGS];
        char *opts, *orig, *p;
@@ -429,6 +431,18 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                                        *subvol_objectid = intarg;
                        }
                        break;
+               case Opt_subvolrootid:
+                       intarg = 0;
+                       error = match_int(&args[0], &intarg);
+                       if (!error) {
+                               /* we want the original fs_tree */
+                               if (!intarg)
+                                       *subvol_rootid =
+                                               BTRFS_FS_TREE_OBJECTID;
+                               else
+                                       *subvol_rootid = intarg;
+                       }
+                       break;
                case Opt_device:
                        error = btrfs_scan_one_device(match_strdup(&args[0]),
                                        flags, holder, fs_devices);
@@ -736,6 +750,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        fmode_t mode = FMODE_READ;
        char *subvol_name = NULL;
        u64 subvol_objectid = 0;
+       u64 subvol_rootid = 0;
        int error = 0;
 
        if (!(flags & MS_RDONLY))
@@ -743,7 +758,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 
        error = btrfs_parse_early_options(data, mode, fs_type,
                                          &subvol_name, &subvol_objectid,
-                                         &fs_devices);
+                                         &subvol_rootid, &fs_devices);
        if (error)
                return ERR_PTR(error);
 
@@ -807,15 +822,17 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                s->s_flags |= MS_ACTIVE;
        }
 
-       root = get_default_root(s, subvol_objectid);
-       if (IS_ERR(root)) {
-               error = PTR_ERR(root);
-               deactivate_locked_super(s);
-               goto error_free_subvol_name;
-       }
        /* if they gave us a subvolume name bind mount into that */
        if (strcmp(subvol_name, ".")) {
                struct dentry *new_root;
+
+               root = get_default_root(s, subvol_rootid);
+               if (IS_ERR(root)) {
+                       error = PTR_ERR(root);
+                       deactivate_locked_super(s);
+                       goto error_free_subvol_name;
+               }
+
                mutex_lock(&root->d_inode->i_mutex);
                new_root = lookup_one_len(subvol_name, root,
                                      strlen(subvol_name));
@@ -836,6 +853,13 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                }
                dput(root);
                root = new_root;
+       } else {
+               root = get_default_root(s, subvol_objectid);
+               if (IS_ERR(root)) {
+                       error = PTR_ERR(root);
+                       deactivate_locked_super(s);
+                       goto error_free_subvol_name;
+               }
        }
 
        kfree(subvol_name);
index 5b158da7e0bb7816710859ee47f7fad4007fb4a2..c571734d5e5a802ea73a0c6458dd41c0b2e56659 100644 (file)
 
 static noinline void put_transaction(struct btrfs_transaction *transaction)
 {
-       WARN_ON(transaction->use_count == 0);
-       transaction->use_count--;
-       if (transaction->use_count == 0) {
-               list_del_init(&transaction->list);
+       WARN_ON(atomic_read(&transaction->use_count) == 0);
+       if (atomic_dec_and_test(&transaction->use_count)) {
                memset(transaction, 0, sizeof(*transaction));
                kmem_cache_free(btrfs_transaction_cachep, transaction);
        }
@@ -60,14 +58,14 @@ static noinline int join_transaction(struct btrfs_root *root)
                if (!cur_trans)
                        return -ENOMEM;
                root->fs_info->generation++;
-               cur_trans->num_writers = 1;
+               atomic_set(&cur_trans->num_writers, 1);
                cur_trans->num_joined = 0;
                cur_trans->transid = root->fs_info->generation;
                init_waitqueue_head(&cur_trans->writer_wait);
                init_waitqueue_head(&cur_trans->commit_wait);
                cur_trans->in_commit = 0;
                cur_trans->blocked = 0;
-               cur_trans->use_count = 1;
+               atomic_set(&cur_trans->use_count, 1);
                cur_trans->commit_done = 0;
                cur_trans->start_time = get_seconds();
 
@@ -88,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root)
                root->fs_info->running_transaction = cur_trans;
                spin_unlock(&root->fs_info->new_trans_lock);
        } else {
-               cur_trans->num_writers++;
+               atomic_inc(&cur_trans->num_writers);
                cur_trans->num_joined++;
        }
 
@@ -145,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root)
        cur_trans = root->fs_info->running_transaction;
        if (cur_trans && cur_trans->blocked) {
                DEFINE_WAIT(wait);
-               cur_trans->use_count++;
+               atomic_inc(&cur_trans->use_count);
                while (1) {
                        prepare_to_wait(&root->fs_info->transaction_wait, &wait,
                                        TASK_UNINTERRUPTIBLE);
@@ -181,6 +179,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 {
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
+       int retries = 0;
        int ret;
 
        if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
@@ -204,7 +203,7 @@ again:
        }
 
        cur_trans = root->fs_info->running_transaction;
-       cur_trans->use_count++;
+       atomic_inc(&cur_trans->use_count);
        if (type != TRANS_JOIN_NOLOCK)
                mutex_unlock(&root->fs_info->trans_mutex);
 
@@ -224,10 +223,18 @@ again:
 
        if (num_items > 0) {
                ret = btrfs_trans_reserve_metadata(h, root, num_items);
-               if (ret == -EAGAIN) {
+               if (ret == -EAGAIN && !retries) {
+                       retries++;
                        btrfs_commit_transaction(h, root);
                        goto again;
+               } else if (ret == -EAGAIN) {
+                       /*
+                        * We have already retried and got EAGAIN, so really we
+                        * don't have space, so set ret to -ENOSPC.
+                        */
+                       ret = -ENOSPC;
                }
+
                if (ret < 0) {
                        btrfs_end_transaction(h, root);
                        return ERR_PTR(ret);
@@ -327,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
                        goto out_unlock;  /* nothing committing|committed */
        }
 
-       cur_trans->use_count++;
+       atomic_inc(&cur_trans->use_count);
        mutex_unlock(&root->fs_info->trans_mutex);
 
        wait_for_commit(root, cur_trans);
@@ -457,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                        wake_up_process(info->transaction_kthread);
        }
 
-       if (lock)
-               mutex_lock(&info->trans_mutex);
        WARN_ON(cur_trans != info->running_transaction);
-       WARN_ON(cur_trans->num_writers < 1);
-       cur_trans->num_writers--;
+       WARN_ON(atomic_read(&cur_trans->num_writers) < 1);
+       atomic_dec(&cur_trans->num_writers);
 
        smp_mb();
        if (waitqueue_active(&cur_trans->writer_wait))
                wake_up(&cur_trans->writer_wait);
        put_transaction(cur_trans);
-       if (lock)
-               mutex_unlock(&info->trans_mutex);
 
        if (current->journal_info == trans)
                current->journal_info = NULL;
@@ -1178,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
        /* take transaction reference */
        mutex_lock(&root->fs_info->trans_mutex);
        cur_trans = trans->transaction;
-       cur_trans->use_count++;
+       atomic_inc(&cur_trans->use_count);
        mutex_unlock(&root->fs_info->trans_mutex);
 
        btrfs_end_transaction(trans, root);
@@ -1237,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        mutex_lock(&root->fs_info->trans_mutex);
        if (cur_trans->in_commit) {
-               cur_trans->use_count++;
+               atomic_inc(&cur_trans->use_count);
                mutex_unlock(&root->fs_info->trans_mutex);
                btrfs_end_transaction(trans, root);
 
@@ -1259,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                prev_trans = list_entry(cur_trans->list.prev,
                                        struct btrfs_transaction, list);
                if (!prev_trans->commit_done) {
-                       prev_trans->use_count++;
+                       atomic_inc(&prev_trans->use_count);
                        mutex_unlock(&root->fs_info->trans_mutex);
 
                        wait_for_commit(root, prev_trans);
@@ -1300,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                                TASK_UNINTERRUPTIBLE);
 
                smp_mb();
-               if (cur_trans->num_writers > 1)
+               if (atomic_read(&cur_trans->num_writers) > 1)
                        schedule_timeout(MAX_SCHEDULE_TIMEOUT);
                else if (should_grow)
                        schedule_timeout(1);
 
                mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&cur_trans->writer_wait, &wait);
-       } while (cur_trans->num_writers > 1 ||
+       } while (atomic_read(&cur_trans->num_writers) > 1 ||
                 (should_grow && cur_trans->num_joined != joined));
 
        ret = create_pending_snapshots(trans, root->fs_info);
@@ -1394,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        wake_up(&cur_trans->commit_wait);
 
+       list_del_init(&cur_trans->list);
        put_transaction(cur_trans);
        put_transaction(cur_trans);
 
index 229a594cacd5a15c8bbd71ed1575f57d615945e4..e441acc6c584a7e03859d3e63cd3e455312ff631 100644 (file)
@@ -27,11 +27,11 @@ struct btrfs_transaction {
         * total writers in this transaction, it must be zero before the
         * transaction can end
         */
-       unsigned long num_writers;
+       atomic_t num_writers;
 
        unsigned long num_joined;
        int in_commit;
-       int use_count;
+       atomic_t use_count;
        int commit_done;
        int blocked;
        struct list_head list;
index c50271ad3157675059656d8113e9804cf3872dfb..f997ec0c1ba4b8efb6b46f88160de43cda3da4f2 100644 (file)
@@ -2209,8 +2209,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        log = root->log_root;
        path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       if (!path) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
 
        di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
                                   name, name_len, -1);
@@ -2271,6 +2273,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        }
 fail:
        btrfs_free_path(path);
+out_unlock:
        mutex_unlock(&BTRFS_I(dir)->log_mutex);
        if (ret == -ENOSPC) {
                root->fs_info->last_trans_log_full_commit = trans->transid;
index 309a57b9fc85e3a6f09809da14d0cd9e1df55fb5..c7367ae5a3e6d9427add05ebf8a594ae92e81d5b 100644 (file)
@@ -155,6 +155,15 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        unsigned long limit;
        unsigned long last_waited = 0;
        int force_reg = 0;
+       struct blk_plug plug;
+
+       /*
+        * this function runs all the bios we've collected for
+        * a particular device.  We don't want to wander off to
+        * another device without first sending all of these down.
+        * So, setup a plug here and finish it off before we return
+        */
+       blk_start_plug(&plug);
 
        bdi = blk_get_backing_dev_info(device->bdev);
        fs_info = device->dev_root->fs_info;
@@ -294,6 +303,7 @@ loop_lock:
        spin_unlock(&device->io_lock);
 
 done:
+       blk_finish_plug(&plug);
        return 0;
 }
 
index a5303b871b13874d574edb6dec5642cf2286e7cb..cfd660550ded035fd2fad7aadce102aa23fc27fb 100644 (file)
@@ -180,11 +180,10 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct btrfs_dir_item *di;
-       int ret = 0, slot, advance;
+       int ret = 0, slot;
        size_t total_size = 0, size_left = size;
        unsigned long name_ptr;
        size_t name_len;
-       u32 nritems;
 
        /*
         * ok we want all objects associated with this id.
@@ -204,34 +203,24 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                goto err;
-       advance = 0;
+
        while (1) {
                leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
                slot = path->slots[0];
 
                /* this is where we start walking through the path */
-               if (advance || slot >= nritems) {
+               if (slot >= btrfs_header_nritems(leaf)) {
                        /*
                         * if we've reached the last slot in this leaf we need
                         * to go to the next leaf and reset everything
                         */
-                       if (slot >= nritems-1) {
-                               ret = btrfs_next_leaf(root, path);
-                               if (ret)
-                                       break;
-                               leaf = path->nodes[0];
-                               nritems = btrfs_header_nritems(leaf);
-                               slot = path->slots[0];
-                       } else {
-                               /*
-                                * just walking through the slots on this leaf
-                                */
-                               slot++;
-                               path->slots[0]++;
-                       }
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               goto err;
+                       else if (ret > 0)
+                               break;
+                       continue;
                }
-               advance = 1;
 
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
@@ -250,7 +239,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 
                /* we are just looking for how big our buffer needs to be */
                if (!size)
-                       continue;
+                       goto next;
 
                if (!buffer || (name_len + 1) > size_left) {
                        ret = -ERANGE;
@@ -263,6 +252,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 
                size_left -= name_len + 1;
                buffer += name_len + 1;
+next:
+               path->slots[0]++;
        }
        ret = total_size;
 
index e159c529fd2bbc845bbd893f645ac7633d91b9eb..38b8ab554924cd2d4a9ddf11ce3a79efe3d411cd 100644 (file)
@@ -775,6 +775,13 @@ get_more_pages:
                                            ci->i_truncate_seq,
                                            ci->i_truncate_size,
                                            &inode->i_mtime, true, 1, 0);
+
+                               if (!req) {
+                                       rc = -ENOMEM;
+                                       unlock_page(page);
+                                       break;
+                               }
+
                                max_pages = req->r_num_pages;
 
                                alloc_page_vec(fsc, req);
index 5323c330bbf3d4acad87fe6a48701b9ee7f27589..9fa08662a88df54652895f472369e04ecc0b144d 100644 (file)
@@ -1331,10 +1331,11 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci)
 }
 
 /*
- * Mark caps dirty.  If inode is newly dirty, add to the global dirty
- * list.
+ * Mark caps dirty.  If inode is newly dirty, return the dirty flags.
+ * Caller is then responsible for calling __mark_inode_dirty with the
+ * returned flags value.
  */
-void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
+int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
 {
        struct ceph_mds_client *mdsc =
                ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
@@ -1357,7 +1358,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
                list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
                spin_unlock(&mdsc->cap_dirty_lock);
                if (ci->i_flushing_caps == 0) {
-                       igrab(inode);
+                       ihold(inode);
                        dirty |= I_DIRTY_SYNC;
                }
        }
@@ -1365,9 +1366,8 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
        if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) &&
            (mask & CEPH_CAP_FILE_BUFFER))
                dirty |= I_DIRTY_DATASYNC;
-       if (dirty)
-               __mark_inode_dirty(inode, dirty);
        __cap_delay_requeue(mdsc, ci);
+       return dirty;
 }
 
 /*
@@ -1991,7 +1991,7 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got)
                ci->i_wr_ref++;
        if (got & CEPH_CAP_FILE_BUFFER) {
                if (ci->i_wrbuffer_ref == 0)
-                       igrab(&ci->vfs_inode);
+                       ihold(&ci->vfs_inode);
                ci->i_wrbuffer_ref++;
                dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n",
                     &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref);
index 159b512d5a271379abf0bde217fd46feeb38c79b..203252d88d9fa6509d1dd7bfed3e4198c414d906 100644 (file)
@@ -734,9 +734,12 @@ retry_snap:
                }
        }
        if (ret >= 0) {
+               int dirty;
                spin_lock(&inode->i_lock);
-               __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
                spin_unlock(&inode->i_lock);
+               if (dirty)
+                       __mark_inode_dirty(inode, dirty);
        }
 
 out:
index b54c97da1c43fd8a4d52238d469c0aa6cb904772..03d6dafda61fbf6300902cb0aa9bdd85947c70e3 100644 (file)
@@ -1567,6 +1567,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        int release = 0, dirtied = 0;
        int mask = 0;
        int err = 0;
+       int inode_dirty_flags = 0;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
@@ -1725,13 +1726,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
                dout("setattr %p ATTR_FILE ... hrm!\n", inode);
 
        if (dirtied) {
-               __ceph_mark_dirty_caps(ci, dirtied);
+               inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied);
                inode->i_ctime = CURRENT_TIME;
        }
 
        release &= issued;
        spin_unlock(&inode->i_lock);
 
+       if (inode_dirty_flags)
+               __mark_inode_dirty(inode, inode_dirty_flags);
+
        if (mask) {
                req->r_inode = igrab(inode);
                req->r_inode_drop = release;
index 619fe719968ff124771de1811b80ba165a54c2b3..b1f1b8bb127127c4936305501e688e5285fa4eef 100644 (file)
@@ -506,7 +506,7 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)
 {
        return ci->i_dirty_caps | ci->i_flushing_caps;
 }
-extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
+extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
 
 extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
 extern int __ceph_caps_used(struct ceph_inode_info *ci);
index 8c9eba6ef9df4999ce4894893900984d943695e5..f2b628696180e93d69bae9c72464ed4b795d694e 100644 (file)
@@ -703,6 +703,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        struct ceph_inode_xattr *xattr = NULL;
        int issued;
        int required_blob_size;
+       int dirty;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
@@ -763,11 +764,12 @@ retry:
        dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
        err = __set_xattr(ci, newname, name_len, newval,
                          val_len, 1, 1, 1, &xattr);
-       __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+       dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
        inode->i_ctime = CURRENT_TIME;
        spin_unlock(&inode->i_lock);
-
+       if (dirty)
+               __mark_inode_dirty(inode, dirty);
        return err;
 
 do_sync:
@@ -810,6 +812,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
        int issued;
        int err;
+       int dirty;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
@@ -833,12 +836,13 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
                goto do_sync;
 
        err = __remove_xattr_by_name(ceph_inode(inode), name);
-       __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+       dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
        inode->i_ctime = CURRENT_TIME;
 
        spin_unlock(&inode->i_lock);
-
+       if (dirty)
+               __mark_inode_dirty(inode, dirty);
        return err;
 do_sync:
        spin_unlock(&inode->i_lock);
index fe1683590828a0ed011fa4a2e6ca6cc157292dca..74ab165fc646aea64d873900b64696a2ef35f471 100644 (file)
@@ -685,22 +685,6 @@ LinuxExtensionsEnabled     If set to one then the client will attempt to
                        support and want to map the uid and gid fields 
                        to values supplied at mount (rather than the 
                        actual values, then set this to zero. (default 1)
-Experimental            When set to 1 used to enable certain experimental
-                       features (currently enables multipage writes
-                       when signing is enabled, the multipage write
-                       performance enhancement was disabled when
-                       signing turned on in case buffer was modified
-                       just before it was sent, also this flag will
-                       be used to use the new experimental directory change 
-                       notification code).  When set to 2 enables
-                       an additional experimental feature, "raw ntlmssp"
-                       session establishment support (which allows
-                       specifying "sec=ntlmssp" on mount). The Linux cifs
-                       module will use ntlmv2 authentication encapsulated
-                       in "raw ntlmssp" (not using SPNEGO) when
-                       "sec=ntlmssp" is specified on mount.
-                       This support also requires building cifs with
-                       the CONFIG_CIFS_EXPERIMENTAL configuration flag.
 
 These experimental features and tracing can be enabled by changing flags in 
 /proc/fs/cifs (after the cifs module has been installed or built into the 
index e654dfd092c3a8d0333af9771156898d1c9ed65e..53d57a3fe427c3d94218a7f54b4ab87df3d68031 100644 (file)
@@ -50,7 +50,7 @@ void cifs_fscache_unregister(void)
  */
 struct cifs_server_key {
        uint16_t        family;         /* address family */
-       uint16_t        port;           /* IP port */
+       __be16          port;           /* IP port */
        union {
                struct in_addr  ipv4_addr;
                struct in6_addr ipv6_addr;
index 65829d32128c253a661ecd61dc50f4893bc9f52d..30d01bc9085556bc810ce4d233f358728e6bea44 100644 (file)
@@ -423,7 +423,6 @@ static const struct file_operations cifs_lookup_cache_proc_fops;
 static const struct file_operations traceSMB_proc_fops;
 static const struct file_operations cifs_multiuser_mount_proc_fops;
 static const struct file_operations cifs_security_flags_proc_fops;
-static const struct file_operations cifs_experimental_proc_fops;
 static const struct file_operations cifs_linux_ext_proc_fops;
 
 void
@@ -441,8 +440,6 @@ cifs_proc_init(void)
        proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
        proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
        proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops);
-       proc_create("Experimental", 0, proc_fs_cifs,
-                   &cifs_experimental_proc_fops);
        proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
                    &cifs_linux_ext_proc_fops);
        proc_create("MultiuserMount", 0, proc_fs_cifs,
@@ -469,7 +466,6 @@ cifs_proc_clean(void)
        remove_proc_entry("OplockEnabled", proc_fs_cifs);
        remove_proc_entry("SecurityFlags", proc_fs_cifs);
        remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
-       remove_proc_entry("Experimental", proc_fs_cifs);
        remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
        remove_proc_entry("fs/cifs", NULL);
 }
@@ -550,45 +546,6 @@ static const struct file_operations cifs_oplock_proc_fops = {
        .write          = cifs_oplock_proc_write,
 };
 
-static int cifs_experimental_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", experimEnabled);
-       return 0;
-}
-
-static int cifs_experimental_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, cifs_experimental_proc_show, NULL);
-}
-
-static ssize_t cifs_experimental_proc_write(struct file *file,
-               const char __user *buffer, size_t count, loff_t *ppos)
-{
-       char c;
-       int rc;
-
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-       if (c == '0' || c == 'n' || c == 'N')
-               experimEnabled = 0;
-       else if (c == '1' || c == 'y' || c == 'Y')
-               experimEnabled = 1;
-       else if (c == '2')
-               experimEnabled = 2;
-
-       return count;
-}
-
-static const struct file_operations cifs_experimental_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = cifs_experimental_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = cifs_experimental_proc_write,
-};
-
 static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
 {
        seq_printf(m, "%d\n", linuxExtEnabled);
index 4dfba82831654910b3aab62a9803dc95855a52f1..33d221394acae068807adea4eeca47317a821888 100644 (file)
@@ -113,7 +113,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
                   MAX_MECH_STR_LEN +
                   UID_KEY_LEN + (sizeof(uid_t) * 2) +
                   CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
-                  USER_KEY_LEN + strlen(sesInfo->userName) +
+                  USER_KEY_LEN + strlen(sesInfo->user_name) +
                   PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
 
        spnego_key = ERR_PTR(-ENOMEM);
@@ -153,7 +153,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
 
        dp = description + strlen(description);
-       sprintf(dp, ";user=%s", sesInfo->userName);
+       sprintf(dp, ";user=%s", sesInfo->user_name);
 
        dp = description + strlen(description);
        sprintf(dp, ";pid=0x%x", current->pid);
index fc0fd4fde306b989c1593ef11ce2611fd49dca54..23d43cde4306042407dcd3df76d78ab81b793db7 100644 (file)
@@ -90,7 +90,7 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
        case UNI_COLON:
                *target = ':';
                break;
-       case UNI_ASTERIK:
+       case UNI_ASTERISK:
                *target = '*';
                break;
        case UNI_QUESTION:
@@ -264,40 +264,40 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
  * names are little endian 16 bit Unicode on the wire
  */
 int
-cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+cifsConvertToUCS(__le16 *target, const char *source, int srclen,
                 const struct nls_table *cp, int mapChars)
 {
        int i, j, charlen;
-       int len_remaining = maxlen;
        char src_char;
-       __u16 temp;
+       __le16 dst_char;
+       wchar_t tmp;
 
        if (!mapChars)
                return cifs_strtoUCS(target, source, PATH_MAX, cp);
 
-       for (i = 0, j = 0; i < maxlen; j++) {
+       for (i = 0, j = 0; i < srclen; j++) {
                src_char = source[i];
                switch (src_char) {
                case 0:
-                       put_unaligned_le16(0, &target[j]);
+                       put_unaligned(0, &target[j]);
                        goto ctoUCS_out;
                case ':':
-                       temp = UNI_COLON;
+                       dst_char = cpu_to_le16(UNI_COLON);
                        break;
                case '*':
-                       temp = UNI_ASTERIK;
+                       dst_char = cpu_to_le16(UNI_ASTERISK);
                        break;
                case '?':
-                       temp = UNI_QUESTION;
+                       dst_char = cpu_to_le16(UNI_QUESTION);
                        break;
                case '<':
-                       temp = UNI_LESSTHAN;
+                       dst_char = cpu_to_le16(UNI_LESSTHAN);
                        break;
                case '>':
-                       temp = UNI_GRTRTHAN;
+                       dst_char = cpu_to_le16(UNI_GRTRTHAN);
                        break;
                case '|':
-                       temp = UNI_PIPE;
+                       dst_char = cpu_to_le16(UNI_PIPE);
                        break;
                /*
                 * FIXME: We can not handle remapping backslash (UNI_SLASH)
@@ -305,17 +305,17 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
                 * as they use backslash as separator.
                 */
                default:
-                       charlen = cp->char2uni(source+i, len_remaining,
-                                               &temp);
+                       charlen = cp->char2uni(source + i, srclen - i, &tmp);
+                       dst_char = cpu_to_le16(tmp);
+
                        /*
                         * if no match, use question mark, which at least in
                         * some cases serves as wild card
                         */
                        if (charlen < 1) {
-                               temp = 0x003f;
+                               dst_char = cpu_to_le16(0x003f);
                                charlen = 1;
                        }
-                       len_remaining -= charlen;
                        /*
                         * character may take more than one byte in the source
                         * string, but will take exactly two bytes in the
@@ -324,9 +324,8 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
                        i += charlen;
                        continue;
                }
-               put_unaligned_le16(temp, &target[j]);
+               put_unaligned(dst_char, &target[j]);
                i++; /* move to next char in source string */
-               len_remaining--;
        }
 
 ctoUCS_out:
index 7fe6b52df5076a2eb14a7ec563403795e2e4c041..644dd882a5604c5ed6f900aad2a47478bc31b49a 100644 (file)
@@ -44,7 +44,7 @@
  * reserved symbols (along with \ and /), otherwise illegal to store
  * in filenames in NTFS
  */
-#define UNI_ASTERI    (__u16) ('*' + 0xF000)
+#define UNI_ASTERISK    (__u16) ('*' + 0xF000)
 #define UNI_QUESTION    (__u16) ('?' + 0xF000)
 #define UNI_COLON       (__u16) (':' + 0xF000)
 #define UNI_GRTRTHAN    (__u16) ('>' + 0xF000)
index a51585f9852b4627735e318e83478cbf512c9fbc..d1a016be73ba75c7a70cb099cd5fdb55150926a9 100644 (file)
 #include <linux/ctype.h>
 #include <linux/random.h>
 
-/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
-/* the 16 byte signature must be allocated by the caller  */
-/* Note we only use the 1st eight bytes */
-/* Note that the smb header signature field on input contains the
-       sequence number before this function is called */
-
+/*
+ * Calculate and return the CIFS signature based on the mac key and SMB PDU.
+ * The 16 byte signature must be allocated by the caller. Note we only use the
+ * 1st eight bytes and that the smb header signature field on input contains
+ * the sequence number before this function is called. Also, this function
+ * should be called with the server->srv_mutex held.
+ */
 static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
                                struct TCP_Server_Info *server, char *signature)
 {
@@ -209,8 +210,10 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
                                        cpu_to_le32(expected_sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
 
+       mutex_lock(&server->srv_mutex);
        rc = cifs_calculate_signature(cifs_pdu, server,
                what_we_think_sig_should_be);
+       mutex_unlock(&server->srv_mutex);
 
        if (rc)
                return rc;
@@ -469,15 +472,15 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
                return rc;
        }
 
-       /* convert ses->userName to unicode and uppercase */
-       len = strlen(ses->userName);
+       /* convert ses->user_name to unicode and uppercase */
+       len = strlen(ses->user_name);
        user = kmalloc(2 + (len * 2), GFP_KERNEL);
        if (user == NULL) {
                cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
                rc = -ENOMEM;
                goto calc_exit_2;
        }
-       len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
+       len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp);
        UniStrupr(user);
 
        crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
index f2970136d17d06c27e0654bbf4f13e302b3dc815..5c412b33cd7c3ba11d584befbcffd12c210e760c 100644 (file)
@@ -53,7 +53,6 @@ int cifsFYI = 0;
 int cifsERROR = 1;
 int traceSMB = 0;
 unsigned int oplockEnabled = 1;
-unsigned int experimEnabled = 0;
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
@@ -127,6 +126,7 @@ cifs_read_super(struct super_block *sb, void *data,
                kfree(cifs_sb);
                return rc;
        }
+       cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
        /* copy mount params to sb for use in submounts */
@@ -409,8 +409,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
                seq_printf(s, ",multiuser");
-       else if (tcon->ses->userName)
-               seq_printf(s, ",username=%s", tcon->ses->userName);
+       else if (tcon->ses->user_name)
+               seq_printf(s, ",username=%s", tcon->ses->user_name);
 
        if (tcon->ses->domainName)
                seq_printf(s, ",domain=%s", tcon->ses->domainName);
index 17afb0fbcaed362b85935d43d12702f8e815efb5..a5d1106fcbde82ea8b5ab5f61de9a29dc72148d2 100644 (file)
 
 #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
 #define MAX_SERVER_SIZE 15
-#define MAX_SHARE_SIZE  64     /* used to be 20, this should still be enough */
-#define MAX_USERNAME_SIZE 32   /* 32 is to allow for 15 char names + null
-                                  termination then *2 for unicode versions */
-#define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
+#define MAX_SHARE_SIZE 80
+#define MAX_USERNAME_SIZE 256  /* reasonable maximum for current servers */
+#define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
 
 #define CIFS_MIN_RCV_POOL 4
 
@@ -92,7 +91,8 @@ enum statusEnum {
        CifsNew = 0,
        CifsGood,
        CifsExiting,
-       CifsNeedReconnect
+       CifsNeedReconnect,
+       CifsNeedNegotiate
 };
 
 enum securityEnum {
@@ -274,7 +274,7 @@ struct cifsSesInfo {
        int capabilities;
        char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
                                TCP names - will ipv6 and sctp addresses fit? */
-       char userName[MAX_USERNAME_SIZE + 1];
+       char *user_name;
        char *domainName;
        char *password;
        struct session_key auth_key;
@@ -817,7 +817,6 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
                                have the uid/password or Kerberos credential
                                or equivalent for current user */
 GLOBAL_EXTERN unsigned int oplockEnabled;
-GLOBAL_EXTERN unsigned int experimEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int global_secflags;    /* if on, session setup sent
                                with more secure ntlmssp2 challenge/resp */
index 2644a5d6cc67d91002810da3d7f05c3d4be11b5a..df959bae67281597a2c1b4ce643eb3893b0e6ee2 100644 (file)
@@ -142,9 +142,9 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
         */
        while (server->tcpStatus == CifsNeedReconnect) {
                wait_event_interruptible_timeout(server->response_q,
-                       (server->tcpStatus == CifsGood), 10 * HZ);
+                       (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
 
-               /* is TCP session is reestablished now ?*/
+               /* are we still trying to reconnect? */
                if (server->tcpStatus != CifsNeedReconnect)
                        break;
 
@@ -729,7 +729,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
                return rc;
 
        /* set up echo request */
-       smb->hdr.Tid = cpu_to_le16(0xffff);
+       smb->hdr.Tid = 0xffff;
        smb->hdr.WordCount = 1;
        put_unaligned_le16(1, &smb->EchoCount);
        put_bcc_le(1, &smb->hdr);
@@ -1884,10 +1884,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                                        __constant_cpu_to_le16(CIFS_WRLCK))
                                pLockData->fl_type = F_WRLCK;
 
-                       pLockData->fl_start = parm_data->start;
-                       pLockData->fl_end = parm_data->start +
-                                               parm_data->length - 1;
-                       pLockData->fl_pid = parm_data->pid;
+                       pLockData->fl_start = le64_to_cpu(parm_data->start);
+                       pLockData->fl_end = pLockData->fl_start +
+                                       le64_to_cpu(parm_data->length) - 1;
+                       pLockData->fl_pid = le32_to_cpu(parm_data->pid);
                }
        }
 
index 6e2b2addfc78a184ca6663fcc528c2f242e1056b..05f1dcf7d79ae023e2b1aae9b2c358784025c1ef 100644 (file)
@@ -199,8 +199,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        }
        spin_unlock(&GlobalMid_Lock);
 
-       while ((server->tcpStatus != CifsExiting) &&
-              (server->tcpStatus != CifsGood)) {
+       while (server->tcpStatus == CifsNeedReconnect) {
                try_to_freeze();
 
                /* we should try only the port we connected to before */
@@ -212,7 +211,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        atomic_inc(&tcpSesReconnectCount);
                        spin_lock(&GlobalMid_Lock);
                        if (server->tcpStatus != CifsExiting)
-                               server->tcpStatus = CifsGood;
+                               server->tcpStatus = CifsNeedNegotiate;
                        spin_unlock(&GlobalMid_Lock);
                }
        }
@@ -248,24 +247,24 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
        total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
        data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
 
-       remaining = total_data_size - data_in_this_rsp;
-
-       if (remaining == 0)
+       if (total_data_size == data_in_this_rsp)
                return 0;
-       else if (remaining < 0) {
+       else if (total_data_size < data_in_this_rsp) {
                cFYI(1, "total data %d smaller than data in frame %d",
                        total_data_size, data_in_this_rsp);
                return -EINVAL;
-       } else {
-               cFYI(1, "missing %d bytes from transact2, check next response",
-                       remaining);
-               if (total_data_size > maxBufSize) {
-                       cERROR(1, "TotalDataSize %d is over maximum buffer %d",
-                               total_data_size, maxBufSize);
-                       return -EINVAL;
-               }
-               return remaining;
        }
+
+       remaining = total_data_size - data_in_this_rsp;
+
+       cFYI(1, "missing %d bytes from transact2, check next response",
+               remaining);
+       if (total_data_size > maxBufSize) {
+               cERROR(1, "TotalDataSize %d is over maximum buffer %d",
+                       total_data_size, maxBufSize);
+               return -EINVAL;
+       }
+       return remaining;
 }
 
 static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
@@ -275,7 +274,8 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
        char *data_area_of_target;
        char *data_area_of_buf2;
        int remaining;
-       __u16 byte_count, total_data_size, total_in_buf, total_in_buf2;
+       unsigned int byte_count, total_in_buf;
+       __u16 total_data_size, total_in_buf2;
 
        total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
 
@@ -288,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
        remaining = total_data_size - total_in_buf;
 
        if (remaining < 0)
-               return -EINVAL;
+               return -EPROTO;
 
        if (remaining == 0) /* nothing to do, ignore */
                return 0;
@@ -309,20 +309,29 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
        data_area_of_target += total_in_buf;
 
        /* copy second buffer into end of first buffer */
-       memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
        total_in_buf += total_in_buf2;
+       /* is the result too big for the field? */
+       if (total_in_buf > USHRT_MAX)
+               return -EPROTO;
        put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
+
+       /* fix up the BCC */
        byte_count = get_bcc_le(pTargetSMB);
        byte_count += total_in_buf2;
+       /* is the result too big for the field? */
+       if (byte_count > USHRT_MAX)
+               return -EPROTO;
        put_bcc_le(byte_count, pTargetSMB);
 
        byte_count = pTargetSMB->smb_buf_length;
        byte_count += total_in_buf2;
-
-       /* BB also add check that we are not beyond maximum buffer size */
-
+       /* don't allow buffer to overflow */
+       if (byte_count > CIFSMaxBufSize)
+               return -ENOBUFS;
        pTargetSMB->smb_buf_length = byte_count;
 
+       memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
+
        if (remaining == total_in_buf2) {
                cFYI(1, "found the last secondary response");
                return 0; /* we are done */
@@ -421,7 +430,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                pdu_length = 4; /* enough to get RFC1001 header */
 
 incomplete_rcv:
-               if (echo_retries > 0 &&
+               if (echo_retries > 0 && server->tcpStatus == CifsGood &&
                    time_after(jiffies, server->lstrp +
                                        (echo_retries * SMB_ECHO_INTERVAL))) {
                        cERROR(1, "Server %s has not responded in %d seconds. "
@@ -608,59 +617,63 @@ incomplete_rcv:
                list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 
-                       if ((mid_entry->mid == smb_buffer->Mid) &&
-                           (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
-                           (mid_entry->command == smb_buffer->Command)) {
-                               if (length == 0 &&
-                                  check2ndT2(smb_buffer, server->maxBuf) > 0) {
-                                       /* We have a multipart transact2 resp */
-                                       isMultiRsp = true;
-                                       if (mid_entry->resp_buf) {
-                                               /* merge response - fix up 1st*/
-                                               if (coalesce_t2(smb_buffer,
-                                                       mid_entry->resp_buf)) {
-                                                       mid_entry->multiRsp =
-                                                                true;
-                                                       break;
-                                               } else {
-                                                       /* all parts received */
-                                                       mid_entry->multiEnd =
-                                                                true;
-                                                       goto multi_t2_fnd;
-                                               }
+                       if (mid_entry->mid != smb_buffer->Mid ||
+                           mid_entry->midState != MID_REQUEST_SUBMITTED ||
+                           mid_entry->command != smb_buffer->Command) {
+                               mid_entry = NULL;
+                               continue;
+                       }
+
+                       if (length == 0 &&
+                           check2ndT2(smb_buffer, server->maxBuf) > 0) {
+                               /* We have a multipart transact2 resp */
+                               isMultiRsp = true;
+                               if (mid_entry->resp_buf) {
+                                       /* merge response - fix up 1st*/
+                                       length = coalesce_t2(smb_buffer,
+                                                       mid_entry->resp_buf);
+                                       if (length > 0) {
+                                               length = 0;
+                                               mid_entry->multiRsp = true;
+                                               break;
                                        } else {
-                                               if (!isLargeBuf) {
-                                                       cERROR(1, "1st trans2 resp needs bigbuf");
-                                       /* BB maybe we can fix this up,  switch
-                                          to already allocated large buffer? */
-                                               } else {
-                                                       /* Have first buffer */
-                                                       mid_entry->resp_buf =
-                                                                smb_buffer;
-                                                       mid_entry->largeBuf =
-                                                                true;
-                                                       bigbuf = NULL;
-                                               }
+                                               /* all parts received or
+                                                * packet is malformed
+                                                */
+                                               mid_entry->multiEnd = true;
+                                               goto multi_t2_fnd;
+                                       }
+                               } else {
+                                       if (!isLargeBuf) {
+                                               /*
+                                                * FIXME: switch to already
+                                                *        allocated largebuf?
+                                                */
+                                               cERROR(1, "1st trans2 resp "
+                                                         "needs bigbuf");
+                                       } else {
+                                               /* Have first buffer */
+                                               mid_entry->resp_buf =
+                                                        smb_buffer;
+                                               mid_entry->largeBuf = true;
+                                               bigbuf = NULL;
                                        }
-                                       break;
                                }
-                               mid_entry->resp_buf = smb_buffer;
-                               mid_entry->largeBuf = isLargeBuf;
+                               break;
+                       }
+                       mid_entry->resp_buf = smb_buffer;
+                       mid_entry->largeBuf = isLargeBuf;
 multi_t2_fnd:
-                               if (length == 0)
-                                       mid_entry->midState =
-                                                       MID_RESPONSE_RECEIVED;
-                               else
-                                       mid_entry->midState =
-                                                       MID_RESPONSE_MALFORMED;
+                       if (length == 0)
+                               mid_entry->midState = MID_RESPONSE_RECEIVED;
+                       else
+                               mid_entry->midState = MID_RESPONSE_MALFORMED;
 #ifdef CONFIG_CIFS_STATS2
-                               mid_entry->when_received = jiffies;
+                       mid_entry->when_received = jiffies;
 #endif
-                               list_del_init(&mid_entry->qhead);
-                               mid_entry->callback(mid_entry);
-                               break;
-                       }
-                       mid_entry = NULL;
+                       list_del_init(&mid_entry->qhead);
+                       mid_entry->callback(mid_entry);
+                       break;
                }
                spin_unlock(&GlobalMid_Lock);
 
@@ -808,8 +821,7 @@ static int
 cifs_parse_mount_options(char *options, const char *devname,
                         struct smb_vol *vol)
 {
-       char *value;
-       char *data;
+       char *value, *data, *end;
        unsigned int  temp_len, i, j;
        char separator[2];
        short int override_uid = -1;
@@ -852,6 +864,7 @@ cifs_parse_mount_options(char *options, const char *devname,
        if (!options)
                return 1;
 
+       end = options + strlen(options);
        if (strncmp(options, "sep=", 4) == 0) {
                if (options[4] != 0) {
                        separator[0] = options[4];
@@ -881,7 +894,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                                /* null user, ie anonymous, authentication */
                                vol->nullauth = 1;
                        }
-                       if (strnlen(value, 200) < 200) {
+                       if (strnlen(value, MAX_USERNAME_SIZE) <
+                                               MAX_USERNAME_SIZE) {
                                vol->username = value;
                        } else {
                                printk(KERN_WARNING "CIFS: username too long\n");
@@ -916,6 +930,7 @@ cifs_parse_mount_options(char *options, const char *devname,
                        the only illegal character in a password is null */
 
                        if ((value[temp_len] == 0) &&
+                           (value + temp_len < end) &&
                            (value[temp_len+1] == separator[0])) {
                                /* reinsert comma */
                                value[temp_len] = separator[0];
@@ -1472,7 +1487,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
 static bool
 match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
 {
-       unsigned short int port, *sport;
+       __be16 port, *sport;
 
        switch (addr->sa_family) {
        case AF_INET:
@@ -1765,6 +1780,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                module_put(THIS_MODULE);
                goto out_err_crypto_release;
        }
+       tcp_ses->tcpStatus = CifsNeedNegotiate;
 
        /* thread spawned, put it on the list */
        spin_lock(&cifs_tcp_ses_lock);
@@ -1808,7 +1824,9 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
                        break;
                default:
                        /* anything else takes username/password */
-                       if (strncmp(ses->userName, vol->username,
+                       if (ses->user_name == NULL)
+                               continue;
+                       if (strncmp(ses->user_name, vol->username,
                                    MAX_USERNAME_SIZE))
                                continue;
                        if (strlen(vol->username) != 0 &&
@@ -1851,6 +1869,8 @@ cifs_put_smb_ses(struct cifsSesInfo *ses)
        cifs_put_tcp_session(server);
 }
 
+static bool warned_on_ntlm;  /* globals init to false automatically */
+
 static struct cifsSesInfo *
 cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 {
@@ -1906,9 +1926,11 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
        else
                sprintf(ses->serverName, "%pI4", &addr->sin_addr);
 
-       if (volume_info->username)
-               strncpy(ses->userName, volume_info->username,
-                       MAX_USERNAME_SIZE);
+       if (volume_info->username) {
+               ses->user_name = kstrdup(volume_info->username, GFP_KERNEL);
+               if (!ses->user_name)
+                       goto get_ses_fail;
+       }
 
        /* volume_info->password freed at unmount */
        if (volume_info->password) {
@@ -1923,6 +1945,15 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
        }
        ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
+
+       /* ntlmv2 is much stronger than ntlm security, and has been broadly
+       supported for many years, time to update default security mechanism */
+       if ((volume_info->secFlg == 0) && warned_on_ntlm == false) {
+               warned_on_ntlm = true;
+               cERROR(1, "default security mechanism requested.  The default "
+                       "security mechanism will be upgraded from ntlm to "
+                       "ntlmv2 in kernel release 2.6.41");
+       }
        ses->overrideSecFlg = volume_info->secFlg;
 
        mutex_lock(&ses->session_mutex);
@@ -2276,7 +2307,7 @@ static int
 generic_ip_connect(struct TCP_Server_Info *server)
 {
        int rc = 0;
-       unsigned short int sport;
+       __be16 sport;
        int slen, sfamily;
        struct socket *socket = server->ssocket;
        struct sockaddr *saddr;
@@ -2361,7 +2392,7 @@ generic_ip_connect(struct TCP_Server_Info *server)
 static int
 ip_connect(struct TCP_Server_Info *server)
 {
-       unsigned short int *sport;
+       __be16 *sport;
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
        struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
 
@@ -2826,7 +2857,7 @@ try_mount_again:
 
 remote_path_check:
        /* check if a whole path (including prepath) is not remote */
-       if (!rc && cifs_sb->prepathlen && tcon) {
+       if (!rc && tcon) {
                /* build_path_to_root works only when we have a valid tcon */
                full_path = cifs_build_path_to_root(cifs_sb, tcon);
                if (full_path == NULL) {
index c27d236738fc08ff80d32eceabc8f412140afbb2..faf59529e847a2adceb9728d10e739adc822f1f5 100644 (file)
@@ -575,8 +575,10 @@ reopen_error_exit:
 
 int cifs_close(struct inode *inode, struct file *file)
 {
-       cifsFileInfo_put(file->private_data);
-       file->private_data = NULL;
+       if (file->private_data != NULL) {
+               cifsFileInfo_put(file->private_data);
+               file->private_data = NULL;
+       }
 
        /* return code from the ->release op is always ignored */
        return 0;
@@ -970,6 +972,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
             total_written += bytes_written) {
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
+                       struct kvec iov[2];
+                       unsigned int len;
+
                        if (open_file->invalidHandle) {
                                /* we could deadlock if we called
                                   filemap_fdatawait from here so tell
@@ -979,31 +984,14 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
                                if (rc != 0)
                                        break;
                        }
-                       if (experimEnabled || (pTcon->ses->server &&
-                               ((pTcon->ses->server->secMode &
-                               (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                               == 0))) {
-                               struct kvec iov[2];
-                               unsigned int len;
-
-                               len = min((size_t)cifs_sb->wsize,
-                                         write_size - total_written);
-                               /* iov[0] is reserved for smb header */
-                               iov[1].iov_base = (char *)write_data +
-                                                 total_written;
-                               iov[1].iov_len = len;
-                               rc = CIFSSMBWrite2(xid, pTcon,
-                                               open_file->netfid, len,
-                                               *poffset, &bytes_written,
-                                               iov, 1, 0);
-                       } else
-                               rc = CIFSSMBWrite(xid, pTcon,
-                                        open_file->netfid,
-                                        min_t(const int, cifs_sb->wsize,
-                                              write_size - total_written),
-                                        *poffset, &bytes_written,
-                                        write_data + total_written,
-                                        NULL, 0);
+
+                       len = min((size_t)cifs_sb->wsize,
+                                 write_size - total_written);
+                       /* iov[0] is reserved for smb header */
+                       iov[1].iov_base = (char *)write_data + total_written;
+                       iov[1].iov_len = len;
+                       rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid, len,
+                                          *poffset, &bytes_written, iov, 1, 0);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -1240,12 +1228,6 @@ static int cifs_writepages(struct address_space *mapping,
        }
 
        tcon = tlink_tcon(open_file->tlink);
-       if (!experimEnabled && tcon->ses->server->secMode &
-                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
-               cifsFileInfo_put(open_file);
-               kfree(iov);
-               return generic_writepages(mapping, wbc);
-       }
        cifsFileInfo_put(open_file);
 
        xid = GetXid();
@@ -1980,6 +1962,24 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        return total_read;
 }
 
+/*
+ * If the page is mmap'ed into a process' page tables, then we need to make
+ * sure that it doesn't change while being written back.
+ */
+static int
+cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct page *page = vmf->page;
+
+       lock_page(page);
+       return VM_FAULT_LOCKED;
+}
+
+static struct vm_operations_struct cifs_file_vm_ops = {
+       .fault = filemap_fault,
+       .page_mkwrite = cifs_page_mkwrite,
+};
+
 int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int rc, xid;
@@ -1991,6 +1991,8 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
                cifs_invalidate_mapping(inode);
 
        rc = generic_file_mmap(file, vma);
+       if (rc == 0)
+               vma->vm_ops = &cifs_file_vm_ops;
        FreeXid(xid);
        return rc;
 }
@@ -2007,6 +2009,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
                return rc;
        }
        rc = generic_file_mmap(file, vma);
+       if (rc == 0)
+               vma->vm_ops = &cifs_file_vm_ops;
        FreeXid(xid);
        return rc;
 }
index e8804d3734044f578da6d4427e4961431d61ae5a..ce417a9764a3fe5c3963e1e93fe5e5b17bf7390c 100644 (file)
@@ -239,7 +239,7 @@ CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
        if (rc != 0)
                return rc;
 
-       if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
+       if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
                CIFSSMBClose(xid, tcon, netfid);
                /* it's not a symlink */
                return -EINVAL;
@@ -316,7 +316,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
        if (rc != 0)
                goto out;
 
-       if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
+       if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
                CIFSSMBClose(xid, pTcon, netfid);
                /* it's not a symlink */
                goto out;
index 2a930a752a784faea9ee912211c3f7a88e1ce9d5..0c684ae4c07163140f4d9009b2d2ccd1f0c86dd2 100644 (file)
@@ -100,6 +100,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
                memset(buf_to_free->password, 0, strlen(buf_to_free->password));
                kfree(buf_to_free->password);
        }
+       kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
        kfree(buf_to_free);
 }
@@ -520,7 +521,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                        (struct smb_com_transaction_change_notify_rsp *)buf;
                struct file_notify_information *pnotify;
                __u32 data_offset = 0;
-               if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
+               if (get_bcc_le(buf) > sizeof(struct file_notify_information)) {
                        data_offset = le32_to_cpu(pSMBr->DataOffset);
 
                        pnotify = (struct file_notify_information *)
index 16765703131be6288e41f0d22d6994ffe3d7685f..645114ad0a10031e08ad9beaa815a720b9fe50b0 100644 (file)
@@ -219,12 +219,12 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
                bcc_ptr++;
        } */
        /* copy user */
-       if (ses->userName == NULL) {
+       if (ses->user_name == NULL) {
                /* null user mount */
                *bcc_ptr = 0;
                *(bcc_ptr+1) = 0;
        } else {
-               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->user_name,
                                          MAX_USERNAME_SIZE, nls_cp);
        }
        bcc_ptr += 2 * bytes_ret;
@@ -244,12 +244,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
        /* copy user */
        /* BB what about null user mounts - check that we do this BB */
        /* copy user */
-       if (ses->userName == NULL) {
-               /* BB what about null user mounts - check that we do this BB */
-       } else {
-               strncpy(bcc_ptr, ses->userName, MAX_USERNAME_SIZE);
-       }
-       bcc_ptr += strnlen(ses->userName, MAX_USERNAME_SIZE);
+       if (ses->user_name != NULL)
+               strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE);
+       /* else null user mount */
+
+       bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE);
        *bcc_ptr = 0;
        bcc_ptr++; /* account for null termination */
 
@@ -277,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
 }
 
 static void
-decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
+decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
                      const struct nls_table *nls_cp)
 {
        int len;
@@ -285,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
 
        cFYI(1, "bleft %d", bleft);
 
-       /*
-        * Windows servers do not always double null terminate their final
-        * Unicode string. Check to see if there are an uneven number of bytes
-        * left. If so, then add an extra NULL pad byte to the end of the
-        * response.
-        *
-        * See section 2.7.2 in "Implementing CIFS" for details
-        */
-       if (bleft % 2) {
-               data[bleft] = 0;
-               ++bleft;
-       }
-
        kfree(ses->serverOS);
        ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp);
        cFYI(1, "serverOS=%s", ses->serverOS);
@@ -405,8 +391,8 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
        /* BB spec says that if AvId field of MsvAvTimestamp is populated then
                we must set the MIC field of the AUTHENTICATE_MESSAGE */
        ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags);
-       tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
-       tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
+       tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset);
+       tilen = le16_to_cpu(pblob->TargetInfoArray.Length);
        if (tilen) {
                ses->auth_key.response = kmalloc(tilen, GFP_KERNEL);
                if (!ses->auth_key.response) {
@@ -523,14 +509,14 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                tmp += len;
        }
 
-       if (ses->userName == NULL) {
+       if (ses->user_name == NULL) {
                sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
                sec_blob->UserName.Length = 0;
                sec_blob->UserName.MaximumLength = 0;
                tmp += 2;
        } else {
                int len;
-               len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
+               len = cifs_strtoUCS((__le16 *)tmp, ses->user_name,
                                    MAX_USERNAME_SIZE, nls_cp);
                len *= 2; /* unicode is 2 bytes each */
                sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
@@ -930,7 +916,9 @@ ssetup_ntlmssp_authenticate:
        }
 
        /* BB check if Unicode and decode strings */
-       if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
+       if (bytes_remaining == 0) {
+               /* no string area to decode, do nothing */
+       } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
                /* unicode string area must be word-aligned */
                if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
                        ++bcc_ptr;
index ad25c4cec7d50a7185459609bf6e5f63b9e9dcbd..22a0ef41bad1b1cd17fc6ce84023d52f65096ba5 100644 (file)
@@ -99,12 +99,9 @@ static struct kmem_cache *dentry_cache __read_mostly;
 static unsigned int d_hash_mask __read_mostly;
 static unsigned int d_hash_shift __read_mostly;
 
-struct dcache_hash_bucket {
-       struct hlist_bl_head head;
-};
-static struct dcache_hash_bucket *dentry_hashtable __read_mostly;
+static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
-static inline struct dcache_hash_bucket *d_hash(struct dentry *parent,
+static inline struct hlist_bl_head *d_hash(struct dentry *parent,
                                        unsigned long hash)
 {
        hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;
@@ -112,16 +109,6 @@ static inline struct dcache_hash_bucket *d_hash(struct dentry *parent,
        return dentry_hashtable + (hash & D_HASHMASK);
 }
 
-static inline void spin_lock_bucket(struct dcache_hash_bucket *b)
-{
-       bit_spin_lock(0, (unsigned long *)&b->head.first);
-}
-
-static inline void spin_unlock_bucket(struct dcache_hash_bucket *b)
-{
-       __bit_spin_unlock(0, (unsigned long *)&b->head.first);
-}
-
 /* Statistics gathering. */
 struct dentry_stat_t dentry_stat = {
        .age_limit = 45,
@@ -167,8 +154,8 @@ static void d_free(struct dentry *dentry)
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
 
-       /* if dentry was never inserted into hash, immediate free is OK */
-       if (hlist_bl_unhashed(&dentry->d_hash))
+       /* if dentry was never visible to RCU, immediate free is OK */
+       if (!(dentry->d_flags & DCACHE_RCUACCESS))
                __d_free(&dentry->d_u.d_rcu);
        else
                call_rcu(&dentry->d_u.d_rcu, __d_free);
@@ -330,28 +317,19 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
  */
 void __d_drop(struct dentry *dentry)
 {
-       if (!(dentry->d_flags & DCACHE_UNHASHED)) {
-               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) {
-                       bit_spin_lock(0,
-                               (unsigned long *)&dentry->d_sb->s_anon.first);
-                       dentry->d_flags |= DCACHE_UNHASHED;
-                       hlist_bl_del_init(&dentry->d_hash);
-                       __bit_spin_unlock(0,
-                               (unsigned long *)&dentry->d_sb->s_anon.first);
-               } else {
-                       struct dcache_hash_bucket *b;
+       if (!d_unhashed(dentry)) {
+               struct hlist_bl_head *b;
+               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+                       b = &dentry->d_sb->s_anon;
+               else
                        b = d_hash(dentry->d_parent, dentry->d_name.hash);
-                       spin_lock_bucket(b);
-                       /*
-                        * We may not actually need to put DCACHE_UNHASHED
-                        * manipulations under the hash lock, but follow
-                        * the principle of least surprise.
-                        */
-                       dentry->d_flags |= DCACHE_UNHASHED;
-                       hlist_bl_del_rcu(&dentry->d_hash);
-                       spin_unlock_bucket(b);
-                       dentry_rcuwalk_barrier(dentry);
-               }
+
+               hlist_bl_lock(b);
+               __hlist_bl_del(&dentry->d_hash);
+               dentry->d_hash.pprev = NULL;
+               hlist_bl_unlock(b);
+
+               dentry_rcuwalk_barrier(dentry);
        }
 }
 EXPORT_SYMBOL(__d_drop);
@@ -1304,7 +1282,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        dname[name->len] = 0;
 
        dentry->d_count = 1;
-       dentry->d_flags = DCACHE_UNHASHED;
+       dentry->d_flags = 0;
        spin_lock_init(&dentry->d_lock);
        seqcount_init(&dentry->d_seq);
        dentry->d_inode = NULL;
@@ -1606,10 +1584,9 @@ struct dentry *d_obtain_alias(struct inode *inode)
        tmp->d_inode = inode;
        tmp->d_flags |= DCACHE_DISCONNECTED;
        list_add(&tmp->d_alias, &inode->i_dentry);
-       bit_spin_lock(0, (unsigned long *)&tmp->d_sb->s_anon.first);
-       tmp->d_flags &= ~DCACHE_UNHASHED;
+       hlist_bl_lock(&tmp->d_sb->s_anon);
        hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
-       __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first);
+       hlist_bl_unlock(&tmp->d_sb->s_anon);
        spin_unlock(&tmp->d_lock);
        spin_unlock(&inode->i_lock);
        security_d_instantiate(tmp, inode);
@@ -1789,7 +1766,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
        unsigned int len = name->len;
        unsigned int hash = name->hash;
        const unsigned char *str = name->name;
-       struct dcache_hash_bucket *b = d_hash(parent, hash);
+       struct hlist_bl_head *b = d_hash(parent, hash);
        struct hlist_bl_node *node;
        struct dentry *dentry;
 
@@ -1813,7 +1790,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
         *
         * See Documentation/filesystems/path-lookup.txt for more details.
         */
-       hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) {
+       hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
                struct inode *i;
                const char *tname;
                int tlen;
@@ -1908,7 +1885,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
        unsigned int len = name->len;
        unsigned int hash = name->hash;
        const unsigned char *str = name->name;
-       struct dcache_hash_bucket *b = d_hash(parent, hash);
+       struct hlist_bl_head *b = d_hash(parent, hash);
        struct hlist_bl_node *node;
        struct dentry *found = NULL;
        struct dentry *dentry;
@@ -1935,7 +1912,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
         */
        rcu_read_lock();
        
-       hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) {
+       hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
                const char *tname;
                int tlen;
 
@@ -2086,13 +2063,13 @@ again:
 }
 EXPORT_SYMBOL(d_delete);
 
-static void __d_rehash(struct dentry * entry, struct dcache_hash_bucket *b)
+static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
 {
        BUG_ON(!d_unhashed(entry));
-       spin_lock_bucket(b);
-       entry->d_flags &= ~DCACHE_UNHASHED;
-       hlist_bl_add_head_rcu(&entry->d_hash, &b->head);
-       spin_unlock_bucket(b);
+       hlist_bl_lock(b);
+       entry->d_flags |= DCACHE_RCUACCESS;
+       hlist_bl_add_head_rcu(&entry->d_hash, b);
+       hlist_bl_unlock(b);
 }
 
 static void _d_rehash(struct dentry * entry)
@@ -2131,7 +2108,7 @@ EXPORT_SYMBOL(d_rehash);
  */
 void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
 {
-       BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
+       BUG_ON(!mutex_is_locked(&dentry->d_parent->d_inode->i_mutex));
        BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
 
        spin_lock(&dentry->d_lock);
@@ -3025,7 +3002,7 @@ static void __init dcache_init_early(void)
 
        dentry_hashtable =
                alloc_large_system_hash("Dentry cache",
-                                       sizeof(struct dcache_hash_bucket),
+                                       sizeof(struct hlist_bl_head),
                                        dhash_entries,
                                        13,
                                        HASH_EARLY,
@@ -3034,7 +3011,7 @@ static void __init dcache_init_early(void)
                                        0);
 
        for (loop = 0; loop < (1 << d_hash_shift); loop++)
-               INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head);
+               INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
 }
 
 static void __init dcache_init(void)
@@ -3057,7 +3034,7 @@ static void __init dcache_init(void)
 
        dentry_hashtable =
                alloc_large_system_hash("Dentry cache",
-                                       sizeof(struct dcache_hash_bucket),
+                                       sizeof(struct hlist_bl_head),
                                        dhash_entries,
                                        13,
                                        0,
@@ -3066,7 +3043,7 @@ static void __init dcache_init(void)
                                        0);
 
        for (loop = 0; loop < (1 << d_hash_shift); loop++)
-               INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head);
+               INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
 }
 
 /* SLAB cache for __getname() consumers */
index d2a70a4561f91257fe44d7cb867e9d14ec1ff908..b8d5c8091024cd1a66d8f36cf9d8fde25f3d2052 100644 (file)
@@ -1452,6 +1452,25 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
        crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
 }
 
+void ecryptfs_i_size_init(const char *page_virt, struct inode *inode)
+{
+       struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+       struct ecryptfs_crypt_stat *crypt_stat;
+       u64 file_size;
+
+       crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+       mount_crypt_stat =
+               &ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat;
+       if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
+               file_size = i_size_read(ecryptfs_inode_to_lower(inode));
+               if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
+                       file_size += crypt_stat->metadata_size;
+       } else
+               file_size = get_unaligned_be64(page_virt);
+       i_size_write(inode, (loff_t)file_size);
+       crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED;
+}
+
 /**
  * ecryptfs_read_headers_virt
  * @page_virt: The virtual address into which to read the headers
@@ -1482,6 +1501,8 @@ static int ecryptfs_read_headers_virt(char *page_virt,
                rc = -EINVAL;
                goto out;
        }
+       if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED))
+               ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
        offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
        rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
                                    &bytes_read);
index bd3cafd0949de6d22179ca5f91115edf18f38fda..e70282775e2c193f11da232c897f6859a2e4334b 100644 (file)
@@ -269,6 +269,7 @@ struct ecryptfs_crypt_stat {
 #define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800
 #define ECRYPTFS_ENCFN_USE_FEK        0x00001000
 #define ECRYPTFS_UNLINK_SIGS          0x00002000
+#define ECRYPTFS_I_SIZE_INITIALIZED   0x00004000
        u32 flags;
        unsigned int file_version;
        size_t iv_bytes;
@@ -295,6 +296,8 @@ struct ecryptfs_crypt_stat {
 struct ecryptfs_inode_info {
        struct inode vfs_inode;
        struct inode *wii_inode;
+       struct mutex lower_file_mutex;
+       atomic_t lower_file_count;
        struct file *lower_file;
        struct ecryptfs_crypt_stat crypt_stat;
 };
@@ -626,6 +629,7 @@ struct ecryptfs_open_req {
 int ecryptfs_interpose(struct dentry *hidden_dentry,
                       struct dentry *this_dentry, struct super_block *sb,
                       u32 flags);
+void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
                                        struct inode *ecryptfs_dir_inode);
@@ -757,7 +761,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
                             struct dentry *lower_dentry,
                             struct vfsmount *lower_mnt,
                             const struct cred *cred);
-int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);
+int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry);
+void ecryptfs_put_lower_file(struct inode *inode);
 int
 ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                             size_t *packet_size,
index cedc913d11ba908f62be8711190a0883f4e95fbe..566e5472f78c3d6dae8e5008689eef281cba37ab 100644 (file)
@@ -191,10 +191,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                                      | ECRYPTFS_ENCRYPTED);
        }
        mutex_unlock(&crypt_stat->cs_mutex);
-       rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
-                       "the persistent file for the dentry with name "
+                       "the lower file for the dentry with name "
                        "[%s]; rc = [%d]\n", __func__,
                        ecryptfs_dentry->d_name.name, rc);
                goto out_free;
@@ -202,9 +202,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
        if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
            == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
                rc = -EPERM;
-               printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs "
+               printk(KERN_WARNING "%s: Lower file is RO; eCryptfs "
                       "file must hence be opened RO\n", __func__);
-               goto out_free;
+               goto out_put;
        }
        ecryptfs_set_file_lower(
                file, ecryptfs_inode_to_private(inode)->lower_file);
@@ -232,10 +232,11 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                                       "Plaintext passthrough mode is not "
                                       "enabled; returning -EIO\n");
                                mutex_unlock(&crypt_stat->cs_mutex);
-                               goto out_free;
+                               goto out_put;
                        }
                        rc = 0;
-                       crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+                       crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
+                                              | ECRYPTFS_ENCRYPTED);
                        mutex_unlock(&crypt_stat->cs_mutex);
                        goto out;
                }
@@ -245,6 +246,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                        "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
                        (unsigned long long)i_size_read(inode));
        goto out;
+out_put:
+       ecryptfs_put_lower_file(inode);
 out_free:
        kmem_cache_free(ecryptfs_file_info_cache,
                        ecryptfs_file_to_private(file));
@@ -254,17 +257,13 @@ out:
 
 static int ecryptfs_flush(struct file *file, fl_owner_t td)
 {
-       int rc = 0;
-       struct file *lower_file = NULL;
-
-       lower_file = ecryptfs_file_to_lower(file);
-       if (lower_file->f_op && lower_file->f_op->flush)
-               rc = lower_file->f_op->flush(lower_file, td);
-       return rc;
+       return file->f_mode & FMODE_WRITE
+              ? filemap_write_and_wait(file->f_mapping) : 0;
 }
 
 static int ecryptfs_release(struct inode *inode, struct file *file)
 {
+       ecryptfs_put_lower_file(inode);
        kmem_cache_free(ecryptfs_file_info_cache,
                        ecryptfs_file_to_private(file));
        return 0;
index f99051b7adab1e7e107cc40e40bb39d57e20e5c1..4d4cc6a90cd57f18b330674f8e5320205cc2a5e6 100644 (file)
@@ -168,19 +168,18 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
                                "context; rc = [%d]\n", rc);
                goto out;
        }
-       rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
-                       "the persistent file for the dentry with name "
+                       "the lower file for the dentry with name "
                        "[%s]; rc = [%d]\n", __func__,
                        ecryptfs_dentry->d_name.name, rc);
                goto out;
        }
        rc = ecryptfs_write_metadata(ecryptfs_dentry);
-       if (rc) {
+       if (rc)
                printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc);
-               goto out;
-       }
+       ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
 out:
        return rc;
 }
@@ -226,11 +225,9 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
        struct dentry *lower_dir_dentry;
        struct vfsmount *lower_mnt;
        struct inode *lower_inode;
-       struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
        struct ecryptfs_crypt_stat *crypt_stat;
        char *page_virt = NULL;
-       u64 file_size;
-       int rc = 0;
+       int put_lower = 0, rc = 0;
 
        lower_dir_dentry = lower_dentry->d_parent;
        lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
@@ -277,14 +274,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                rc = -ENOMEM;
                goto out;
        }
-       rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
-                       "the persistent file for the dentry with name "
+                       "the lower file for the dentry with name "
                        "[%s]; rc = [%d]\n", __func__,
                        ecryptfs_dentry->d_name.name, rc);
                goto out_free_kmem;
        }
+       put_lower = 1;
        crypt_stat = &ecryptfs_inode_to_private(
                                        ecryptfs_dentry->d_inode)->crypt_stat;
        /* TODO: lock for crypt_stat comparison */
@@ -302,18 +300,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                }
                crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
        }
-       mount_crypt_stat = &ecryptfs_superblock_to_private(
-               ecryptfs_dentry->d_sb)->mount_crypt_stat;
-       if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
-               if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-                       file_size = (crypt_stat->metadata_size
-                                    + i_size_read(lower_dentry->d_inode));
-               else
-                       file_size = i_size_read(lower_dentry->d_inode);
-       } else {
-               file_size = get_unaligned_be64(page_virt);
-       }
-       i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size);
+       ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
 out_free_kmem:
        kmem_cache_free(ecryptfs_header_cache_2, page_virt);
        goto out;
@@ -322,6 +309,8 @@ out_put:
        mntput(lower_mnt);
        d_drop(ecryptfs_dentry);
 out:
+       if (put_lower)
+               ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
        return rc;
 }
 
@@ -538,8 +527,6 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
        dget(lower_dentry);
        rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
        dput(lower_dentry);
-       if (!rc)
-               d_delete(lower_dentry);
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
        dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
        unlock_dir(lower_dir_dentry);
@@ -610,8 +597,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
 out_lock:
        unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
-       dput(lower_new_dentry->d_parent);
-       dput(lower_old_dentry->d_parent);
+       dput(lower_new_dir_dentry);
+       dput(lower_old_dir_dentry);
        dput(lower_new_dentry);
        dput(lower_old_dentry);
        return rc;
@@ -759,8 +746,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
 
        if (unlikely((ia->ia_size == i_size))) {
                lower_ia->ia_valid &= ~ATTR_SIZE;
-               goto out;
+               return 0;
        }
+       rc = ecryptfs_get_lower_file(dentry);
+       if (rc)
+               return rc;
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
        /* Switch on growing or shrinking file */
        if (ia->ia_size > i_size) {
@@ -838,6 +828,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                        lower_ia->ia_valid &= ~ATTR_SIZE;
        }
 out:
+       ecryptfs_put_lower_file(inode);
        return rc;
 }
 
@@ -913,7 +904,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
 
                mount_crypt_stat = &ecryptfs_superblock_to_private(
                        dentry->d_sb)->mount_crypt_stat;
+               rc = ecryptfs_get_lower_file(dentry);
+               if (rc) {
+                       mutex_unlock(&crypt_stat->cs_mutex);
+                       goto out;
+               }
                rc = ecryptfs_read_metadata(dentry);
+               ecryptfs_put_lower_file(inode);
                if (rc) {
                        if (!(mount_crypt_stat->flags
                              & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
@@ -927,10 +924,17 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
                                goto out;
                        }
                        rc = 0;
-                       crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+                       crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
+                                              | ECRYPTFS_ENCRYPTED);
                }
        }
        mutex_unlock(&crypt_stat->cs_mutex);
+       if (S_ISREG(inode->i_mode)) {
+               rc = filemap_write_and_wait(inode->i_mapping);
+               if (rc)
+                       goto out;
+               fsstack_copy_attr_all(inode, lower_inode);
+       }
        memcpy(&lower_ia, ia, sizeof(lower_ia));
        if (ia->ia_valid & ATTR_FILE)
                lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
index 0851ab6980f54038b8f0ed9239712fea573622c5..69f994a7d5249589bf594adaa4780bca967f08b2 100644 (file)
@@ -44,7 +44,7 @@ static struct task_struct *ecryptfs_kthread;
  * @ignored: ignored
  *
  * The eCryptfs kernel thread that has the responsibility of getting
- * the lower persistent file with RW permissions.
+ * the lower file with RW permissions.
  *
  * Returns zero on success; non-zero otherwise
  */
@@ -141,8 +141,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
        int rc = 0;
 
        /* Corresponding dput() and mntput() are done when the
-        * persistent file is fput() when the eCryptfs inode is
-        * destroyed. */
+        * lower file is fput() when all eCryptfs files for the inode are
+        * released. */
        dget(lower_dentry);
        mntget(lower_mnt);
        flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
index fdb2eb0ad09e447d3701dcc31a9da29cc8619cbe..89b93389af8ee0a69b44cbfe709f4f766156a6c0 100644 (file)
@@ -96,7 +96,7 @@ void __ecryptfs_printk(const char *fmt, ...)
 }
 
 /**
- * ecryptfs_init_persistent_file
+ * ecryptfs_init_lower_file
  * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with
  *                   the lower dentry and the lower mount set
  *
@@ -104,42 +104,70 @@ void __ecryptfs_printk(const char *fmt, ...)
  * inode. All I/O operations to the lower inode occur through that
  * file. When the first eCryptfs dentry that interposes with the first
  * lower dentry for that inode is created, this function creates the
- * persistent file struct and associates it with the eCryptfs
- * inode. When the eCryptfs inode is destroyed, the file is closed.
+ * lower file struct and associates it with the eCryptfs
+ * inode. When all eCryptfs files associated with the inode are released, the
+ * file is closed.
  *
- * The persistent file will be opened with read/write permissions, if
+ * The lower file will be opened with read/write permissions, if
  * possible. Otherwise, it is opened read-only.
  *
- * This function does nothing if a lower persistent file is already
+ * This function does nothing if a lower file is already
  * associated with the eCryptfs inode.
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+static int ecryptfs_init_lower_file(struct dentry *dentry,
+                                   struct file **lower_file)
 {
        const struct cred *cred = current_cred();
-       struct ecryptfs_inode_info *inode_info =
-               ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
-       int rc = 0;
+       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+       int rc;
 
-       if (!inode_info->lower_file) {
-               struct dentry *lower_dentry;
-               struct vfsmount *lower_mnt =
-                       ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+       rc = ecryptfs_privileged_open(lower_file, lower_dentry, lower_mnt,
+                                     cred);
+       if (rc) {
+               printk(KERN_ERR "Error opening lower file "
+                      "for lower_dentry [0x%p] and lower_mnt [0x%p]; "
+                      "rc = [%d]\n", lower_dentry, lower_mnt, rc);
+               (*lower_file) = NULL;
+       }
+       return rc;
+}
 
-               lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
-               rc = ecryptfs_privileged_open(&inode_info->lower_file,
-                                             lower_dentry, lower_mnt, cred);
-               if (rc) {
-                       printk(KERN_ERR "Error opening lower persistent file "
-                              "for lower_dentry [0x%p] and lower_mnt [0x%p]; "
-                              "rc = [%d]\n", lower_dentry, lower_mnt, rc);
-                       inode_info->lower_file = NULL;
-               }
+int ecryptfs_get_lower_file(struct dentry *dentry)
+{
+       struct ecryptfs_inode_info *inode_info =
+               ecryptfs_inode_to_private(dentry->d_inode);
+       int count, rc = 0;
+
+       mutex_lock(&inode_info->lower_file_mutex);
+       count = atomic_inc_return(&inode_info->lower_file_count);
+       if (WARN_ON_ONCE(count < 1))
+               rc = -EINVAL;
+       else if (count == 1) {
+               rc = ecryptfs_init_lower_file(dentry,
+                                             &inode_info->lower_file);
+               if (rc)
+                       atomic_set(&inode_info->lower_file_count, 0);
        }
+       mutex_unlock(&inode_info->lower_file_mutex);
        return rc;
 }
 
+void ecryptfs_put_lower_file(struct inode *inode)
+{
+       struct ecryptfs_inode_info *inode_info;
+
+       inode_info = ecryptfs_inode_to_private(inode);
+       if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count,
+                                     &inode_info->lower_file_mutex)) {
+               fput(inode_info->lower_file);
+               inode_info->lower_file = NULL;
+               mutex_unlock(&inode_info->lower_file_mutex);
+       }
+}
+
 static struct inode *ecryptfs_get_inode(struct inode *lower_inode,
                       struct super_block *sb)
 {
index bacc882e1ae40454f7623ac81e78968155d9ae55..245b517bf1b65ec5dc5dfa294891e40038d201d7 100644 (file)
@@ -55,6 +55,8 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
        if (unlikely(!inode_info))
                goto out;
        ecryptfs_init_crypt_stat(&inode_info->crypt_stat);
+       mutex_init(&inode_info->lower_file_mutex);
+       atomic_set(&inode_info->lower_file_count, 0);
        inode_info->lower_file = NULL;
        inode = &inode_info->vfs_inode;
 out:
@@ -77,8 +79,7 @@ static void ecryptfs_i_callback(struct rcu_head *head)
  *
  * This is used during the final destruction of the inode.  All
  * allocation of memory related to the inode, including allocated
- * memory in the crypt_stat struct, will be released here. This
- * function also fput()'s the persistent file for the lower inode.
+ * memory in the crypt_stat struct, will be released here.
  * There should be no chance that this deallocation will be missed.
  */
 static void ecryptfs_destroy_inode(struct inode *inode)
@@ -86,16 +87,7 @@ static void ecryptfs_destroy_inode(struct inode *inode)
        struct ecryptfs_inode_info *inode_info;
 
        inode_info = ecryptfs_inode_to_private(inode);
-       if (inode_info->lower_file) {
-               struct dentry *lower_dentry =
-                       inode_info->lower_file->f_dentry;
-
-               BUG_ON(!lower_dentry);
-               if (lower_dentry->d_inode) {
-                       fput(inode_info->lower_file);
-                       inode_info->lower_file = NULL;
-               }
-       }
+       BUG_ON(inode_info->lower_file);
        ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
        call_rcu(&inode->i_rcu, ecryptfs_i_callback);
 }
index bf93ad2bee07fb9e8d0c6475a029bf740f0f6d6c..6b088641f5bf24ce72311a3b8073ce44516b8624 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/exportfs.h>
 #include <linux/fs_struct.h>
 #include <linux/fsnotify.h>
+#include <linux/personality.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
index 0be344755c020e8de53d26ff89f60d8a4778cf91..4c6992d8f3ba1e3056645e805ddcb4c879d82f93 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/mmzone.h>
 #include <linux/time.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -39,14 +40,17 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */
  */
 static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
 
-static inline void *alloc_fdmem(unsigned int size)
+static void *alloc_fdmem(unsigned int size)
 {
-       void *data;
-
-       data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN);
-       if (data != NULL)
-               return data;
-
+       /*
+        * Very large allocations can stress page reclaim, so fall back to
+        * vmalloc() if the allocation size will be considered "large" by the VM.
+        */
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
+               void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN);
+               if (data != NULL)
+                       return data;
+       }
        return vmalloc(size);
 }
 
index 751d6b255a12ab1abcf71e817f80f4ce11bbd647..0845f84f2a5fe2b8eaf95aaac05a06cfe21f79e0 100644 (file)
@@ -110,14 +110,13 @@ int unregister_filesystem(struct file_system_type * fs)
                        *tmp = fs->next;
                        fs->next = NULL;
                        write_unlock(&file_systems_lock);
+                       synchronize_rcu();
                        return 0;
                }
                tmp = &(*tmp)->next;
        }
        write_unlock(&file_systems_lock);
 
-       synchronize_rcu();
-
        return -EINVAL;
 }
 
index c71995b111bf6f4347ffb313692c4ee66ff6f74e..0f5c4f9d5d62beee06937a8d0c98bd015f7dc5ee 100644 (file)
@@ -884,8 +884,8 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        }
 
        brelse(dibh);
-       gfs2_trans_end(sdp);
 failed:
+       gfs2_trans_end(sdp);
        if (al) {
                gfs2_inplace_release(ip);
                gfs2_quota_unlock(ip);
index 5c356d09c321c10133afc7cf93aba2eddd1cb3c1..f789c5732b7c5fc695c7fdb97183402613dfd3c5 100644 (file)
@@ -1506,7 +1506,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name)
                inode = gfs2_inode_lookup(dir->i_sb, 
                                be16_to_cpu(dent->de_type),
                                be64_to_cpu(dent->de_inum.no_addr),
-                               be64_to_cpu(dent->de_inum.no_formal_ino));
+                               be64_to_cpu(dent->de_inum.no_formal_ino), 0);
                brelse(bh);
                return inode;
        }
index b2682e073eee0a593b1ab43c74291aa08e6af674..e48310885c48e8866c35647f7ea242e702df4ab2 100644 (file)
@@ -617,18 +617,51 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        return generic_file_aio_write(iocb, iov, nr_segs, pos);
 }
 
-static void empty_write_end(struct page *page, unsigned from,
-                          unsigned to)
+static int empty_write_end(struct page *page, unsigned from,
+                          unsigned to, int mode)
 {
-       struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+       struct inode *inode = page->mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct buffer_head *bh;
+       unsigned offset, blksize = 1 << inode->i_blkbits;
+       pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
 
        zero_user(page, from, to-from);
        mark_page_accessed(page);
 
-       if (!gfs2_is_writeback(ip))
-               gfs2_page_add_databufs(ip, page, from, to);
+       if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) {
+               if (!gfs2_is_writeback(ip))
+                       gfs2_page_add_databufs(ip, page, from, to);
+
+               block_commit_write(page, from, to);
+               return 0;
+       }
+
+       offset = 0;
+       bh = page_buffers(page);
+       while (offset < to) {
+               if (offset >= from) {
+                       set_buffer_uptodate(bh);
+                       mark_buffer_dirty(bh);
+                       clear_buffer_new(bh);
+                       write_dirty_buffer(bh, WRITE);
+               }
+               offset += blksize;
+               bh = bh->b_this_page;
+       }
 
-       block_commit_write(page, from, to);
+       offset = 0;
+       bh = page_buffers(page);
+       while (offset < to) {
+               if (offset >= from) {
+                       wait_on_buffer(bh);
+                       if (!buffer_uptodate(bh))
+                               return -EIO;
+               }
+               offset += blksize;
+               bh = bh->b_this_page;
+       }
+       return 0;
 }
 
 static int needs_empty_write(sector_t block, struct inode *inode)
@@ -643,7 +676,8 @@ static int needs_empty_write(sector_t block, struct inode *inode)
        return !buffer_mapped(&bh_map);
 }
 
-static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
+static int write_empty_blocks(struct page *page, unsigned from, unsigned to,
+                             int mode)
 {
        struct inode *inode = page->mapping->host;
        unsigned start, end, next, blksize;
@@ -668,7 +702,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
                                                          gfs2_block_map);
                                if (unlikely(ret))
                                        return ret;
-                               empty_write_end(page, start, end);
+                               ret = empty_write_end(page, start, end, mode);
+                               if (unlikely(ret))
+                                       return ret;
                                end = 0;
                        }
                        start = next;
@@ -682,7 +718,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
                ret = __block_write_begin(page, start, end - start, gfs2_block_map);
                if (unlikely(ret))
                        return ret;
-               empty_write_end(page, start, end);
+               ret = empty_write_end(page, start, end, mode);
+               if (unlikely(ret))
+                       return ret;
        }
 
        return 0;
@@ -731,7 +769,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
 
                if (curr == end)
                        to = end_offset;
-               error = write_empty_blocks(page, from, to);
+               error = write_empty_blocks(page, from, to, mode);
                if (!error && offset + to > inode->i_size &&
                    !(mode & FALLOC_FL_KEEP_SIZE)) {
                        i_size_write(inode, offset + to);
index f07643e21bfa20a46a541aaf160d164784ddcbe4..7a4fb630a320ef2f4aea4816ecbceefee07ad96d 100644 (file)
@@ -93,14 +93,12 @@ static unsigned int gl_hash(const struct gfs2_sbd *sdp,
 
 static inline void spin_lock_bucket(unsigned int hash)
 {
-       struct hlist_bl_head *bl = &gl_hash_table[hash];
-       bit_spin_lock(0, (unsigned long *)bl);
+       hlist_bl_lock(&gl_hash_table[hash]);
 }
 
 static inline void spin_unlock_bucket(unsigned int hash)
 {
-       struct hlist_bl_head *bl = &gl_hash_table[hash];
-       __bit_spin_unlock(0, (unsigned long *)bl);
+       hlist_bl_unlock(&gl_hash_table[hash]);
 }
 
 static void gfs2_glock_dealloc(struct rcu_head *rcu)
index 3754e3cbf02bce2bf04b683bc9d36d48ec6a8bbe..25eeb2bcee47e4e10d289510718d7c08539a3acb 100644 (file)
@@ -385,6 +385,10 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl)
 static void iopen_go_callback(struct gfs2_glock *gl)
 {
        struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;
+       struct gfs2_sbd *sdp = gl->gl_sbd;
+
+       if (sdp->sd_vfs->s_flags & MS_RDONLY)
+               return;
 
        if (gl->gl_demote_state == LM_ST_UNLOCKED &&
            gl->gl_state == LM_ST_SHARED && ip) {
index 97d54a28776a1851a004b62a7b7ecc41a84d0e04..9134dcb894790adfd487101565703e4e24a37075 100644 (file)
@@ -40,37 +40,61 @@ struct gfs2_inum_range_host {
        u64 ir_length;
 };
 
+struct gfs2_skip_data {
+       u64 no_addr;
+       int skipped;
+       int non_block;
+};
+
 static int iget_test(struct inode *inode, void *opaque)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
-       u64 *no_addr = opaque;
+       struct gfs2_skip_data *data = opaque;
 
-       if (ip->i_no_addr == *no_addr)
+       if (ip->i_no_addr == data->no_addr) {
+               if (data->non_block &&
+                   inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) {
+                       data->skipped = 1;
+                       return 0;
+               }
                return 1;
-
+       }
        return 0;
 }
 
 static int iget_set(struct inode *inode, void *opaque)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
-       u64 *no_addr = opaque;
+       struct gfs2_skip_data *data = opaque;
 
-       inode->i_ino = (unsigned long)*no_addr;
-       ip->i_no_addr = *no_addr;
+       if (data->skipped)
+               return -ENOENT;
+       inode->i_ino = (unsigned long)(data->no_addr);
+       ip->i_no_addr = data->no_addr;
        return 0;
 }
 
 struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr)
 {
        unsigned long hash = (unsigned long)no_addr;
-       return ilookup5(sb, hash, iget_test, &no_addr);
+       struct gfs2_skip_data data;
+
+       data.no_addr = no_addr;
+       data.skipped = 0;
+       data.non_block = 0;
+       return ilookup5(sb, hash, iget_test, &data);
 }
 
-static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
+static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr,
+                              int non_block)
 {
+       struct gfs2_skip_data data;
        unsigned long hash = (unsigned long)no_addr;
-       return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
+
+       data.no_addr = no_addr;
+       data.skipped = 0;
+       data.non_block = non_block;
+       return iget5_locked(sb, hash, iget_test, iget_set, &data);
 }
 
 /**
@@ -111,19 +135,20 @@ static void gfs2_set_iop(struct inode *inode)
  * @sb: The super block
  * @no_addr: The inode number
  * @type: The type of the inode
+ * non_block: Can we block on inodes that are being freed?
  *
  * Returns: A VFS inode, or an error
  */
 
 struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
-                               u64 no_addr, u64 no_formal_ino)
+                               u64 no_addr, u64 no_formal_ino, int non_block)
 {
        struct inode *inode;
        struct gfs2_inode *ip;
        struct gfs2_glock *io_gl = NULL;
        int error;
 
-       inode = gfs2_iget(sb, no_addr);
+       inode = gfs2_iget(sb, no_addr, non_block);
        ip = GFS2_I(inode);
 
        if (!inode)
@@ -185,11 +210,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
 {
        struct super_block *sb = sdp->sd_vfs;
        struct gfs2_holder i_gh;
-       struct inode *inode;
+       struct inode *inode = NULL;
        int error;
 
+       /* Must not read in block until block type is verified */
        error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops,
-                                 LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+                                 LM_ST_EXCLUSIVE, GL_SKIP, &i_gh);
        if (error)
                return ERR_PTR(error);
 
@@ -197,7 +223,7 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
        if (error)
                goto fail;
 
-       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0);
+       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1);
        if (IS_ERR(inode))
                goto fail;
 
@@ -843,7 +869,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
                goto fail_gunlock2;
 
        inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
-                                 inum.no_formal_ino);
+                                 inum.no_formal_ino, 0);
        if (IS_ERR(inode))
                goto fail_gunlock2;
 
index 3e00a66e7cbd04c707ce22686647e5800c7621a4..099ca305e518d25c8251e5163456635087b26828 100644 (file)
@@ -97,7 +97,8 @@ err:
 }
 
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
-                                      u64 no_addr, u64 no_formal_ino);
+                                      u64 no_addr, u64 no_formal_ino,
+                                      int non_block);
 extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
                                         u64 *no_formal_ino,
                                         unsigned int blktype);
index 42ef24355afbdb112e366269d3835cc40b37cff6..d3c69eb91c74e29c05af120f3938bffb9ebb1d75 100644 (file)
@@ -430,7 +430,7 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr,
        struct dentry *dentry;
        struct inode *inode;
 
-       inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0);
+       inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
        if (IS_ERR(inode)) {
                fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode));
                return PTR_ERR(inode);
index cf930cd9664af9ca0c351e08c0d852f52c52417d..6fcae8469f6d76a178710ee2ece82108c8ec2ba1 100644 (file)
@@ -945,7 +945,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
                /* rgblk_search can return a block < goal, so we need to
                   keep it marching forward. */
                no_addr = block + rgd->rd_data0;
-               goal++;
+               goal = max(block + 1, goal + 1);
                if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
                        continue;
                if (no_addr == skip)
@@ -971,7 +971,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
                        found++;
 
                /* Limit reclaim to sensible number of tasks */
-               if (found > 2*NR_CPUS)
+               if (found > NR_CPUS)
                        return;
        }
 
index a4e23d68a39862f08848c8a7d19136c1d6bb881e..b9f28e66dad190af29b389b2830f1ff66efff024 100644 (file)
@@ -1318,15 +1318,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
 
 static void gfs2_evict_inode(struct inode *inode)
 {
-       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+       struct super_block *sb = inode->i_sb;
+       struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int error;
 
-       if (inode->i_nlink)
+       if (inode->i_nlink || (sb->s_flags & MS_RDONLY))
                goto out;
 
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+       /* Must not read inode block until block type has been verified */
+       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
        if (unlikely(error)) {
                gfs2_glock_dq_uninit(&ip->i_iopen_gh);
                goto out;
@@ -1336,6 +1338,12 @@ static void gfs2_evict_inode(struct inode *inode)
        if (error)
                goto out_truncate;
 
+       if (test_bit(GIF_INVALID, &ip->i_flags)) {
+               error = gfs2_inode_refresh(ip);
+               if (error)
+                       goto out_truncate;
+       }
+
        ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
        gfs2_glock_dq_wait(&ip->i_iopen_gh);
        gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
index 0c39dc3ef7d71473a0a951612fd54e82a63cf3a2..56bd15c5bf6cffee6cdd2e36c379eeb42c22d604 100644 (file)
@@ -1,7 +1,6 @@
 config HPFS_FS
        tristate "OS/2 HPFS file system support"
        depends on BLOCK
-       depends on BROKEN || !PREEMPT
        help
          OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
          is the file system used for organizing files on OS/2 hard disk
index 5503e2c28910102bb0a2a22b97d8e2a7bf20cbad..7a5eb2c718c854206d6db419abe4ce7bc61d12c7 100644 (file)
@@ -8,8 +8,6 @@
 
 #include "hpfs_fn.h"
 
-static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec);
-
 /*
  * Check if a sector is allocated in bitmap
  * This is really slow. Turned on only if chk==2
@@ -18,9 +16,9 @@ static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec);
 static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
 {
        struct quad_buffer_head qbh;
-       unsigned *bmp;
+       u32 *bmp;
        if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail;
-       if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f)) & 1) {
+       if ((cpu_to_le32(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f)) & 1) {
                hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec);
                goto fail1;
        }
@@ -28,7 +26,7 @@ static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
        if (sec >= hpfs_sb(s)->sb_dirband_start && sec < hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) {
                unsigned ssec = (sec - hpfs_sb(s)->sb_dirband_start) / 4;
                if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto fail;
-               if ((bmp[ssec >> 5] >> (ssec & 0x1f)) & 1) {
+               if ((le32_to_cpu(bmp[ssec >> 5]) >> (ssec & 0x1f)) & 1) {
                        hpfs_error(s, "sector '%s' - %08x not allocated in directory bitmap", msg, sec);
                        goto fail1;
                }
@@ -75,7 +73,6 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
                hpfs_error(s, "Bad allocation size: %d", n);
                return 0;
        }
-       lock_super(s);
        if (bs != ~0x3fff) {
                if (!(bmp = hpfs_map_bitmap(s, near >> 14, &qbh, "aib"))) goto uls;
        } else {
@@ -85,10 +82,6 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
                ret = bs + nr;
                goto rt;
        }
-       /*if (!tstbits(bmp, nr + n, n + forward)) {
-               ret = bs + nr + n;
-               goto rt;
-       }*/
        q = nr + n; b = 0;
        while ((a = tstbits(bmp, q, n + forward)) != 0) {
                q += a;
@@ -105,14 +98,14 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
                goto rt;
        }
        nr >>= 5;
-       /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) {*/
+       /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) */
        i = nr;
        do {
-               if (!bmp[i]) goto cont;
-               if (n + forward >= 0x3f && bmp[i] != -1) goto cont;
+               if (!le32_to_cpu(bmp[i])) goto cont;
+               if (n + forward >= 0x3f && le32_to_cpu(bmp[i]) != 0xffffffff) goto cont;
                q = i<<5;
                if (i > 0) {
-                       unsigned k = bmp[i-1];
+                       unsigned k = le32_to_cpu(bmp[i-1]);
                        while (k & 0x80000000) {
                                q--; k <<= 1;
                        }
@@ -132,18 +125,17 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
        } while (i != nr);
        rt:
        if (ret) {
-               if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) {
+               if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (le32_to_cpu(bmp[(ret & 0x3fff) >> 5]) | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) {
                        hpfs_error(s, "Allocation doesn't work! Wanted %d, allocated at %08x", n, ret);
                        ret = 0;
                        goto b;
                }
-               bmp[(ret & 0x3fff) >> 5] &= ~(((1 << n) - 1) << (ret & 0x1f));
+               bmp[(ret & 0x3fff) >> 5] &= cpu_to_le32(~(((1 << n) - 1) << (ret & 0x1f)));
                hpfs_mark_4buffers_dirty(&qbh);
        }
        b:
        hpfs_brelse4(&qbh);
        uls:
-       unlock_super(s);
        return ret;
 }
 
@@ -155,7 +147,7 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
  *                             sectors
  */
 
-secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward, int lock)
+secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward)
 {
        secno sec;
        int i;
@@ -167,7 +159,6 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa
                forward = -forward;
                f_p = 1;
        }
-       if (lock) hpfs_lock_creation(s);
        n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14;
        if (near && near < sbi->sb_fs_size) {
                if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret;
@@ -214,18 +205,17 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa
        ret:
        if (sec && f_p) {
                for (i = 0; i < forward; i++) {
-                       if (!hpfs_alloc_if_possible_nolock(s, sec + i + 1)) {
+                       if (!hpfs_alloc_if_possible(s, sec + i + 1)) {
                                hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
                                sec = 0;
                                break;
                        }
                }
        }
-       if (lock) hpfs_unlock_creation(s);
        return sec;
 }
 
-static secno alloc_in_dirband(struct super_block *s, secno near, int lock)
+static secno alloc_in_dirband(struct super_block *s, secno near)
 {
        unsigned nr = near;
        secno sec;
@@ -236,49 +226,35 @@ static secno alloc_in_dirband(struct super_block *s, secno near, int lock)
                nr = sbi->sb_dirband_start + sbi->sb_dirband_size - 4;
        nr -= sbi->sb_dirband_start;
        nr >>= 2;
-       if (lock) hpfs_lock_creation(s);
        sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
-       if (lock) hpfs_unlock_creation(s);
        if (!sec) return 0;
        return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start;
 }
 
 /* Alloc sector if it's free */
 
-static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec)
+int hpfs_alloc_if_possible(struct super_block *s, secno sec)
 {
        struct quad_buffer_head qbh;
-       unsigned *bmp;
-       lock_super(s);
+       u32 *bmp;
        if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end;
-       if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) {
-               bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f));
+       if (le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) & (1 << (sec & 0x1f))) {
+               bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f)));
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
-               unlock_super(s);
                return 1;
        }
        hpfs_brelse4(&qbh);
        end:
-       unlock_super(s);
        return 0;
 }
 
-int hpfs_alloc_if_possible(struct super_block *s, secno sec)
-{
-       int r;
-       hpfs_lock_creation(s);
-       r = hpfs_alloc_if_possible_nolock(s, sec);
-       hpfs_unlock_creation(s);
-       return r;
-}
-
 /* Free sectors in bitmaps */
 
 void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
 {
        struct quad_buffer_head qbh;
-       unsigned *bmp;
+       u32 *bmp;
        struct hpfs_sb_info *sbi = hpfs_sb(s);
        /*printk("2 - ");*/
        if (!n) return;
@@ -286,26 +262,22 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
                hpfs_error(s, "Trying to free reserved sector %08x", sec);
                return;
        }
-       lock_super(s);
        sbi->sb_max_fwd_alloc += n > 0xffff ? 0xffff : n;
        if (sbi->sb_max_fwd_alloc > 0xffffff) sbi->sb_max_fwd_alloc = 0xffffff;
        new_map:
        if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) {
-               unlock_super(s);
                return;
        }       
        new_tst:
-       if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) {
+       if ((le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f) & 1)) {
                hpfs_error(s, "sector %08x not allocated", sec);
                hpfs_brelse4(&qbh);
-               unlock_super(s);
                return;
        }
-       bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f);
+       bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f));
        if (!--n) {
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
-               unlock_super(s);
                return;
        }       
        if (!(++sec & 0x3fff)) {
@@ -327,13 +299,13 @@ int hpfs_check_free_dnodes(struct super_block *s, int n)
        int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14;
        int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff;
        int i, j;
-       unsigned *bmp;
+       u32 *bmp;
        struct quad_buffer_head qbh;
        if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
                for (j = 0; j < 512; j++) {
                        unsigned k;
-                       if (!bmp[j]) continue;
-                       for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) {
+                       if (!le32_to_cpu(bmp[j])) continue;
+                       for (k = le32_to_cpu(bmp[j]); k; k >>= 1) if (k & 1) if (!--n) {
                                hpfs_brelse4(&qbh);
                                return 0;
                        }
@@ -352,10 +324,10 @@ int hpfs_check_free_dnodes(struct super_block *s, int n)
        chk_bmp:
        if (bmp) {
                for (j = 0; j < 512; j++) {
-                       unsigned k;
-                       if (!bmp[j]) continue;
+                       u32 k;
+                       if (!le32_to_cpu(bmp[j])) continue;
                        for (k = 0xf; k; k <<= 4)
-                               if ((bmp[j] & k) == k) {
+                               if ((le32_to_cpu(bmp[j]) & k) == k) {
                                        if (!--n) {
                                                hpfs_brelse4(&qbh);
                                                return 0;
@@ -379,44 +351,40 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
                hpfs_free_sectors(s, dno, 4);
        } else {
                struct quad_buffer_head qbh;
-               unsigned *bmp;
+               u32 *bmp;
                unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4;
-               lock_super(s);
                if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
-                       unlock_super(s);
                        return;
                }
-               bmp[ssec >> 5] |= 1 << (ssec & 0x1f);
+               bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f));
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
-               unlock_super(s);
        }
 }
 
 struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near,
-                        dnode_secno *dno, struct quad_buffer_head *qbh,
-                        int lock)
+                        dnode_secno *dno, struct quad_buffer_head *qbh)
 {
        struct dnode *d;
        if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) {
-               if (!(*dno = alloc_in_dirband(s, near, lock)))
-                       if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL;
+               if (!(*dno = alloc_in_dirband(s, near)))
+                       if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
        } else {
-               if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock)))
-                       if (!(*dno = alloc_in_dirband(s, near, lock))) return NULL;
+               if (!(*dno = hpfs_alloc_sector(s, near, 4, 0)))
+                       if (!(*dno = alloc_in_dirband(s, near))) return NULL;
        }
        if (!(d = hpfs_get_4sectors(s, *dno, qbh))) {
                hpfs_free_dnode(s, *dno);
                return NULL;
        }
        memset(d, 0, 2048);
-       d->magic = DNODE_MAGIC;
-       d->first_free = 52;
+       d->magic = cpu_to_le32(DNODE_MAGIC);
+       d->first_free = cpu_to_le32(52);
        d->dirent[0] = 32;
        d->dirent[2] = 8;
        d->dirent[30] = 1;
        d->dirent[31] = 255;
-       d->self = *dno;
+       d->self = cpu_to_le32(*dno);
        return d;
 }
 
@@ -424,16 +392,16 @@ struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *f
                          struct buffer_head **bh)
 {
        struct fnode *f;
-       if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD, 1))) return NULL;
+       if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD))) return NULL;
        if (!(f = hpfs_get_sector(s, *fno, bh))) {
                hpfs_free_sectors(s, *fno, 1);
                return NULL;
        }       
        memset(f, 0, 512);
-       f->magic = FNODE_MAGIC;
-       f->ea_offs = 0xc4;
+       f->magic = cpu_to_le32(FNODE_MAGIC);
+       f->ea_offs = cpu_to_le16(0xc4);
        f->btree.n_free_nodes = 8;
-       f->btree.first_free = 8;
+       f->btree.first_free = cpu_to_le16(8);
        return f;
 }
 
@@ -441,16 +409,16 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a
                          struct buffer_head **bh)
 {
        struct anode *a;
-       if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD, 1))) return NULL;
+       if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD))) return NULL;
        if (!(a = hpfs_get_sector(s, *ano, bh))) {
                hpfs_free_sectors(s, *ano, 1);
                return NULL;
        }
        memset(a, 0, 512);
-       a->magic = ANODE_MAGIC;
-       a->self = *ano;
+       a->magic = cpu_to_le32(ANODE_MAGIC);
+       a->self = cpu_to_le32(*ano);
        a->btree.n_free_nodes = 40;
        a->btree.n_used_nodes = 0;
-       a->btree.first_free = 8;
+       a->btree.first_free = cpu_to_le16(8);
        return a;
 }
index 6a2f04bf3df007249047523e10a098fd2b43c603..08b503e8ed29ec610a098cb9658e1a2ecaa1779c 100644 (file)
@@ -22,8 +22,8 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
        if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1;
        if (btree->internal) {
                for (i = 0; i < btree->n_used_nodes; i++)
-                       if (btree->u.internal[i].file_secno > sec) {
-                               a = btree->u.internal[i].down;
+                       if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) {
+                               a = le32_to_cpu(btree->u.internal[i].down);
                                brelse(bh);
                                if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
                                btree = &anode->btree;
@@ -34,18 +34,18 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
                return -1;
        }
        for (i = 0; i < btree->n_used_nodes; i++)
-               if (btree->u.external[i].file_secno <= sec &&
-                   btree->u.external[i].file_secno + btree->u.external[i].length > sec) {
-                       a = btree->u.external[i].disk_secno + sec - btree->u.external[i].file_secno;
+               if (le32_to_cpu(btree->u.external[i].file_secno) <= sec &&
+                   le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > sec) {
+                       a = le32_to_cpu(btree->u.external[i].disk_secno) + sec - le32_to_cpu(btree->u.external[i].file_secno);
                        if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, a, 1, "data")) {
                                brelse(bh);
                                return -1;
                        }
                        if (inode) {
                                struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
-                               hpfs_inode->i_file_sec = btree->u.external[i].file_secno;
-                               hpfs_inode->i_disk_sec = btree->u.external[i].disk_secno;
-                               hpfs_inode->i_n_secs = btree->u.external[i].length;
+                               hpfs_inode->i_file_sec = le32_to_cpu(btree->u.external[i].file_secno);
+                               hpfs_inode->i_disk_sec = le32_to_cpu(btree->u.external[i].disk_secno);
+                               hpfs_inode->i_n_secs = le32_to_cpu(btree->u.external[i].length);
                        }
                        brelse(bh);
                        return a;
@@ -83,8 +83,8 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                return -1;
        }
        if (btree->internal) {
-               a = btree->u.internal[n].down;
-               btree->u.internal[n].file_secno = -1;
+               a = le32_to_cpu(btree->u.internal[n].down);
+               btree->u.internal[n].file_secno = cpu_to_le32(-1);
                mark_buffer_dirty(bh);
                brelse(bh);
                if (hpfs_sb(s)->sb_chk)
@@ -94,15 +94,15 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                goto go_down;
        }
        if (n >= 0) {
-               if (btree->u.external[n].file_secno + btree->u.external[n].length != fsecno) {
+               if (le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length) != fsecno) {
                        hpfs_error(s, "allocated size %08x, trying to add sector %08x, %cnode %08x",
-                               btree->u.external[n].file_secno + btree->u.external[n].length, fsecno,
+                               le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length), fsecno,
                                fnod?'f':'a', node);
                        brelse(bh);
                        return -1;
                }
-               if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) {
-                       btree->u.external[n].length++;
+               if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) {
+                       btree->u.external[n].length = cpu_to_le32(le32_to_cpu(btree->u.external[n].length) + 1);
                        mark_buffer_dirty(bh);
                        brelse(bh);
                        return se;
@@ -115,20 +115,20 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                }
                se = !fnod ? node : (node + 16384) & ~16383;
        }       
-       if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M, 1))) {
+       if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M))) {
                brelse(bh);
                return -1;
        }
-       fs = n < 0 ? 0 : btree->u.external[n].file_secno + btree->u.external[n].length;
+       fs = n < 0 ? 0 : le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length);
        if (!btree->n_free_nodes) {
-               up = a != node ? anode->up : -1;
+               up = a != node ? le32_to_cpu(anode->up) : -1;
                if (!(anode = hpfs_alloc_anode(s, a, &na, &bh1))) {
                        brelse(bh);
                        hpfs_free_sectors(s, se, 1);
                        return -1;
                }
                if (a == node && fnod) {
-                       anode->up = node;
+                       anode->up = cpu_to_le32(node);
                        anode->btree.fnode_parent = 1;
                        anode->btree.n_used_nodes = btree->n_used_nodes;
                        anode->btree.first_free = btree->first_free;
@@ -137,9 +137,9 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                        btree->internal = 1;
                        btree->n_free_nodes = 11;
                        btree->n_used_nodes = 1;
-                       btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree;
-                       btree->u.internal[0].file_secno = -1;
-                       btree->u.internal[0].down = na;
+                       btree->first_free = cpu_to_le16((char *)&(btree->u.internal[1]) - (char *)btree);
+                       btree->u.internal[0].file_secno = cpu_to_le32(-1);
+                       btree->u.internal[0].down = cpu_to_le32(na);
                        mark_buffer_dirty(bh);
                } else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) {
                        brelse(bh);
@@ -153,15 +153,15 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                btree = &anode->btree;
        }
        btree->n_free_nodes--; n = btree->n_used_nodes++;
-       btree->first_free += 12;
-       btree->u.external[n].disk_secno = se;
-       btree->u.external[n].file_secno = fs;
-       btree->u.external[n].length = 1;
+       btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 12);
+       btree->u.external[n].disk_secno = cpu_to_le32(se);
+       btree->u.external[n].file_secno = cpu_to_le32(fs);
+       btree->u.external[n].length = cpu_to_le32(1);
        mark_buffer_dirty(bh);
        brelse(bh);
        if ((a == node && fnod) || na == -1) return se;
        c2 = 0;
-       while (up != -1) {
+       while (up != (anode_secno)-1) {
                struct anode *new_anode;
                if (hpfs_sb(s)->sb_chk)
                        if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1;
@@ -174,47 +174,47 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                }
                if (btree->n_free_nodes) {
                        btree->n_free_nodes--; n = btree->n_used_nodes++;
-                       btree->first_free += 8;
-                       btree->u.internal[n].file_secno = -1;
-                       btree->u.internal[n].down = na;
-                       btree->u.internal[n-1].file_secno = fs;
+                       btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 8);
+                       btree->u.internal[n].file_secno = cpu_to_le32(-1);
+                       btree->u.internal[n].down = cpu_to_le32(na);
+                       btree->u.internal[n-1].file_secno = cpu_to_le32(fs);
                        mark_buffer_dirty(bh);
                        brelse(bh);
                        brelse(bh2);
                        hpfs_free_sectors(s, ra, 1);
                        if ((anode = hpfs_map_anode(s, na, &bh))) {
-                               anode->up = up;
+                               anode->up = cpu_to_le32(up);
                                anode->btree.fnode_parent = up == node && fnod;
                                mark_buffer_dirty(bh);
                                brelse(bh);
                        }
                        return se;
                }
-               up = up != node ? anode->up : -1;
-               btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1;
+               up = up != node ? le32_to_cpu(anode->up) : -1;
+               btree->u.internal[btree->n_used_nodes - 1].file_secno = cpu_to_le32(/*fs*/-1);
                mark_buffer_dirty(bh);
                brelse(bh);
                a = na;
                if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) {
                        anode = new_anode;
-                       /*anode->up = up != -1 ? up : ra;*/
+                       /*anode->up = cpu_to_le32(up != -1 ? up : ra);*/
                        anode->btree.internal = 1;
                        anode->btree.n_used_nodes = 1;
                        anode->btree.n_free_nodes = 59;
-                       anode->btree.first_free = 16;
-                       anode->btree.u.internal[0].down = a;
-                       anode->btree.u.internal[0].file_secno = -1;
+                       anode->btree.first_free = cpu_to_le16(16);
+                       anode->btree.u.internal[0].down = cpu_to_le32(a);
+                       anode->btree.u.internal[0].file_secno = cpu_to_le32(-1);
                        mark_buffer_dirty(bh);
                        brelse(bh);
                        if ((anode = hpfs_map_anode(s, a, &bh))) {
-                               anode->up = na;
+                               anode->up = cpu_to_le32(na);
                                mark_buffer_dirty(bh);
                                brelse(bh);
                        }
                } else na = a;
        }
        if ((anode = hpfs_map_anode(s, na, &bh))) {
-               anode->up = node;
+               anode->up = cpu_to_le32(node);
                if (fnod) anode->btree.fnode_parent = 1;
                mark_buffer_dirty(bh);
                brelse(bh);
@@ -232,14 +232,14 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                }
                btree = &fnode->btree;
        }
-       ranode->up = node;
-       memcpy(&ranode->btree, btree, btree->first_free);
+       ranode->up = cpu_to_le32(node);
+       memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free));
        if (fnod) ranode->btree.fnode_parent = 1;
        ranode->btree.n_free_nodes = (ranode->btree.internal ? 60 : 40) - ranode->btree.n_used_nodes;
        if (ranode->btree.internal) for (n = 0; n < ranode->btree.n_used_nodes; n++) {
                struct anode *unode;
-               if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) {
-                       unode->up = ra;
+               if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) {
+                       unode->up = cpu_to_le32(ra);
                        unode->btree.fnode_parent = 0;
                        mark_buffer_dirty(bh1);
                        brelse(bh1);
@@ -248,11 +248,11 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
        btree->internal = 1;
        btree->n_free_nodes = fnod ? 10 : 58;
        btree->n_used_nodes = 2;
-       btree->first_free = (char *)&btree->u.internal[2] - (char *)btree;
-       btree->u.internal[0].file_secno = fs;
-       btree->u.internal[0].down = ra;
-       btree->u.internal[1].file_secno = -1;
-       btree->u.internal[1].down = na;
+       btree->first_free = cpu_to_le16((char *)&btree->u.internal[2] - (char *)btree);
+       btree->u.internal[0].file_secno = cpu_to_le32(fs);
+       btree->u.internal[0].down = cpu_to_le32(ra);
+       btree->u.internal[1].file_secno = cpu_to_le32(-1);
+       btree->u.internal[1].down = cpu_to_le32(na);
        mark_buffer_dirty(bh);
        brelse(bh);
        mark_buffer_dirty(bh2);
@@ -279,7 +279,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
        go_down:
        d2 = 0;
        while (btree1->internal) {
-               ano = btree1->u.internal[pos].down;
+               ano = le32_to_cpu(btree1->u.internal[pos].down);
                if (level) brelse(bh);
                if (hpfs_sb(s)->sb_chk)
                        if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1"))
@@ -290,7 +290,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
                pos = 0;
        }
        for (i = 0; i < btree1->n_used_nodes; i++)
-               hpfs_free_sectors(s, btree1->u.external[i].disk_secno, btree1->u.external[i].length);
+               hpfs_free_sectors(s, le32_to_cpu(btree1->u.external[i].disk_secno), le32_to_cpu(btree1->u.external[i].length));
        go_up:
        if (!level) return;
        brelse(bh);
@@ -298,13 +298,13 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
                if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return;
        hpfs_free_sectors(s, ano, 1);
        oano = ano;
-       ano = anode->up;
+       ano = le32_to_cpu(anode->up);
        if (--level) {
                if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
                btree1 = &anode->btree;
        } else btree1 = btree;
        for (i = 0; i < btree1->n_used_nodes; i++) {
-               if (btree1->u.internal[i].down == oano) {
+               if (le32_to_cpu(btree1->u.internal[i].down) == oano) {
                        if ((pos = i + 1) < btree1->n_used_nodes)
                                goto go_down;
                        else
@@ -411,7 +411,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
                if (fno) {
                        btree->n_free_nodes = 8;
                        btree->n_used_nodes = 0;
-                       btree->first_free = 8;
+                       btree->first_free = cpu_to_le16(8);
                        btree->internal = 0;
                        mark_buffer_dirty(bh);
                } else hpfs_free_sectors(s, f, 1);
@@ -421,22 +421,22 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
        while (btree->internal) {
                nodes = btree->n_used_nodes + btree->n_free_nodes;
                for (i = 0; i < btree->n_used_nodes; i++)
-                       if (btree->u.internal[i].file_secno >= secs) goto f;
+                       if (le32_to_cpu(btree->u.internal[i].file_secno) >= secs) goto f;
                brelse(bh);
                hpfs_error(s, "internal btree %08x doesn't end with -1", node);
                return;
                f:
                for (j = i + 1; j < btree->n_used_nodes; j++)
-                       hpfs_ea_remove(s, btree->u.internal[j].down, 1, 0);
+                       hpfs_ea_remove(s, le32_to_cpu(btree->u.internal[j].down), 1, 0);
                btree->n_used_nodes = i + 1;
                btree->n_free_nodes = nodes - btree->n_used_nodes;
-               btree->first_free = 8 + 8 * btree->n_used_nodes;
+               btree->first_free = cpu_to_le16(8 + 8 * btree->n_used_nodes);
                mark_buffer_dirty(bh);
-               if (btree->u.internal[i].file_secno == secs) {
+               if (btree->u.internal[i].file_secno == cpu_to_le32(secs)) {
                        brelse(bh);
                        return;
                }
-               node = btree->u.internal[i].down;
+               node = le32_to_cpu(btree->u.internal[i].down);
                brelse(bh);
                if (hpfs_sb(s)->sb_chk)
                        if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree"))
@@ -446,25 +446,25 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
        }       
        nodes = btree->n_used_nodes + btree->n_free_nodes;
        for (i = 0; i < btree->n_used_nodes; i++)
-               if (btree->u.external[i].file_secno + btree->u.external[i].length >= secs) goto ff;
+               if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) >= secs) goto ff;
        brelse(bh);
        return;
        ff:
-       if (secs <= btree->u.external[i].file_secno) {
+       if (secs <= le32_to_cpu(btree->u.external[i].file_secno)) {
                hpfs_error(s, "there is an allocation error in file %08x, sector %08x", f, secs);
                if (i) i--;
        }
-       else if (btree->u.external[i].file_secno + btree->u.external[i].length > secs) {
-               hpfs_free_sectors(s, btree->u.external[i].disk_secno + secs -
-                       btree->u.external[i].file_secno, btree->u.external[i].length
-                       - secs + btree->u.external[i].file_secno); /* I hope gcc optimizes this :-) */
-               btree->u.external[i].length = secs - btree->u.external[i].file_secno;
+       else if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > secs) {
+               hpfs_free_sectors(s, le32_to_cpu(btree->u.external[i].disk_secno) + secs -
+                       le32_to_cpu(btree->u.external[i].file_secno), le32_to_cpu(btree->u.external[i].length)
+                       - secs + le32_to_cpu(btree->u.external[i].file_secno)); /* I hope gcc optimizes this :-) */
+               btree->u.external[i].length = cpu_to_le32(secs - le32_to_cpu(btree->u.external[i].file_secno));
        }
        for (j = i + 1; j < btree->n_used_nodes; j++)
-               hpfs_free_sectors(s, btree->u.external[j].disk_secno, btree->u.external[j].length);
+               hpfs_free_sectors(s, le32_to_cpu(btree->u.external[j].disk_secno), le32_to_cpu(btree->u.external[j].length));
        btree->n_used_nodes = i + 1;
        btree->n_free_nodes = nodes - btree->n_used_nodes;
-       btree->first_free = 8 + 12 * btree->n_used_nodes;
+       btree->first_free = cpu_to_le16(8 + 12 * btree->n_used_nodes);
        mark_buffer_dirty(bh);
        brelse(bh);
 }
@@ -480,12 +480,12 @@ void hpfs_remove_fnode(struct super_block *s, fnode_secno fno)
        struct extended_attribute *ea_end;
        if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return;
        if (!fnode->dirflag) hpfs_remove_btree(s, &fnode->btree);
-       else hpfs_remove_dtree(s, fnode->u.external[0].disk_secno);
+       else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno));
        ea_end = fnode_end_ea(fnode);
        for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
                if (ea->indirect)
                        hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea));
-       hpfs_ea_ext_remove(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l);
+       hpfs_ea_ext_remove(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l));
        brelse(bh);
        hpfs_free_sectors(s, fno, 1);
 }
index 793cb9d943d21a70584958c27fba6b2f97b37f93..9ecde27d1e297ed3d42a742352f469f1bf2dfb9a 100644 (file)
@@ -9,22 +9,6 @@
 #include <linux/slab.h>
 #include "hpfs_fn.h"
 
-void hpfs_lock_creation(struct super_block *s)
-{
-#ifdef DEBUG_LOCKS
-       printk("lock creation\n");
-#endif
-       mutex_lock(&hpfs_sb(s)->hpfs_creation_de);
-}
-
-void hpfs_unlock_creation(struct super_block *s)
-{
-#ifdef DEBUG_LOCKS
-       printk("unlock creation\n");
-#endif
-       mutex_unlock(&hpfs_sb(s)->hpfs_creation_de);
-}
-
 /* Map a sector into a buffer and return pointers to it and to the buffer. */
 
 void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
@@ -32,6 +16,8 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head
 {
        struct buffer_head *bh;
 
+       hpfs_lock_assert(s);
+
        cond_resched();
 
        *bhp = bh = sb_bread(s, secno);
@@ -50,6 +36,8 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head
        struct buffer_head *bh;
        /*return hpfs_map_sector(s, secno, bhp, 0);*/
 
+       hpfs_lock_assert(s);
+
        cond_resched();
 
        if ((*bhp = bh = sb_getblk(s, secno)) != NULL) {
@@ -70,6 +58,8 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
        struct buffer_head *bh;
        char *data;
 
+       hpfs_lock_assert(s);
+
        cond_resched();
 
        if (secno & 3) {
@@ -125,6 +115,8 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno,
 {
        cond_resched();
 
+       hpfs_lock_assert(s);
+
        if (secno & 3) {
                printk("HPFS: hpfs_get_4sectors: unaligned read\n");
                return NULL;
index b3d7c0ddb60971e2cb4217afb0bf22d4683c2988..f46ae025bfb58bc172716efcb66772add1daac43 100644 (file)
@@ -88,9 +88,9 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        hpfs_error(inode->i_sb, "not a directory, fnode %08lx",
                                        (unsigned long)inode->i_ino);
                }
-               if (hpfs_inode->i_dno != fno->u.external[0].disk_secno) {
+               if (hpfs_inode->i_dno != le32_to_cpu(fno->u.external[0].disk_secno)) {
                        e = 1;
-                       hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno);
+                       hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, le32_to_cpu(fno->u.external[0].disk_secno));
                }
                brelse(bh);
                if (e) {
@@ -156,7 +156,7 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        goto again;
                }
                tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
-               if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
+               if (filldir(dirent, tempname, de->namelen, old_pos, le32_to_cpu(de->fnode), DT_UNKNOWN) < 0) {
                        filp->f_pos = old_pos;
                        if (tempname != de->name) kfree(tempname);
                        hpfs_brelse4(&qbh);
@@ -221,7 +221,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
         * Get inode number, what we're after.
         */
 
-       ino = de->fnode;
+       ino = le32_to_cpu(de->fnode);
 
        /*
         * Go find or make an inode.
@@ -236,7 +236,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
                hpfs_init_inode(result);
                if (de->directory)
                        hpfs_read_inode(result);
-               else if (de->ea_size && hpfs_sb(dir->i_sb)->sb_eas)
+               else if (le32_to_cpu(de->ea_size) && hpfs_sb(dir->i_sb)->sb_eas)
                        hpfs_read_inode(result);
                else {
                        result->i_mode |= S_IFREG;
@@ -250,8 +250,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
        hpfs_result = hpfs_i(result);
        if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
 
-       hpfs_decide_conv(result, name, len);
-
        if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
                hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
                goto bail1;
@@ -263,19 +261,19 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
         */
 
        if (!result->i_ctime.tv_sec) {
-               if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, de->creation_date)))
+               if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->creation_date))))
                        result->i_ctime.tv_sec = 1;
                result->i_ctime.tv_nsec = 0;
-               result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, de->write_date);
+               result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->write_date));
                result->i_mtime.tv_nsec = 0;
-               result->i_atime.tv_sec = local_to_gmt(dir->i_sb, de->read_date);
+               result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->read_date));
                result->i_atime.tv_nsec = 0;
-               hpfs_result->i_ea_size = de->ea_size;
+               hpfs_result->i_ea_size = le32_to_cpu(de->ea_size);
                if (!hpfs_result->i_ea_mode && de->read_only)
                        result->i_mode &= ~0222;
                if (!de->directory) {
                        if (result->i_size == -1) {
-                               result->i_size = de->file_size;
+                               result->i_size = le32_to_cpu(de->file_size);
                                result->i_data.a_ops = &hpfs_aops;
                                hpfs_i(result)->mmu_private = result->i_size;
                        /*
index 9b2ffadfc8c42dd9a39f86a0bdedb6a8dbbd0df5..1e0e2ac30fd3be93f8e5b7a97618f19a52220ec4 100644 (file)
@@ -14,11 +14,11 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
        struct hpfs_dirent *de_end = dnode_end_de(d);
        int i = 1;
        for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
-               if (de == fde) return ((loff_t) d->self << 4) | (loff_t)i;
+               if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i;
                i++;
        }
        printk("HPFS: get_pos: not_found\n");
-       return ((loff_t)d->self << 4) | (loff_t)1;
+       return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1;
 }
 
 void hpfs_add_pos(struct inode *inode, loff_t *pos)
@@ -130,29 +130,30 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno
 {
        struct hpfs_dirent *de;
        if (!(de = dnode_last_de(d))) {
-               hpfs_error(s, "set_last_pointer: empty dnode %08x", d->self);
+               hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self));
                return;
        }
        if (hpfs_sb(s)->sb_chk) {
                if (de->down) {
                        hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x",
-                               d->self, de_down_pointer(de));
+                               le32_to_cpu(d->self), de_down_pointer(de));
                        return;
                }
-               if (de->length != 32) {
-                       hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", d->self);
+               if (le16_to_cpu(de->length) != 32) {
+                       hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self));
                        return;
                }
        }
        if (ptr) {
-               if ((d->first_free += 4) > 2048) {
-                       hpfs_error(s,"set_last_pointer: too long dnode %08x", d->self);
-                       d->first_free -= 4;
+               d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + 4);
+               if (le32_to_cpu(d->first_free) > 2048) {
+                       hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self));
+                       d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - 4);
                        return;
                }
-               de->length = 36;
+               de->length = cpu_to_le16(36);
                de->down = 1;
-               *(dnode_secno *)((char *)de + 32) = ptr;
+               *(dnode_secno *)((char *)de + 32) = cpu_to_le32(ptr);
        }
 }
 
@@ -168,7 +169,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
        for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
                int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last);
                if (!c) {
-                       hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, d->self);
+                       hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self));
                        return NULL;
                }
                if (c < 0) break;
@@ -176,15 +177,14 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
        memmove((char *)de + d_size, de, (char *)de_end - (char *)de);
        memset(de, 0, d_size);
        if (down_ptr) {
-               *(int *)((char *)de + d_size - 4) = down_ptr;
+               *(dnode_secno *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr);
                de->down = 1;
        }
-       de->length = d_size;
-       if (down_ptr) de->down = 1;
+       de->length = cpu_to_le16(d_size);
        de->not_8x3 = hpfs_is_name_long(name, namelen);
        de->namelen = namelen;
        memcpy(de->name, name, namelen);
-       d->first_free += d_size;
+       d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + d_size);
        return de;
 }
 
@@ -194,25 +194,25 @@ static void hpfs_delete_de(struct super_block *s, struct dnode *d,
                           struct hpfs_dirent *de)
 {
        if (de->last) {
-               hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self);
+               hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self));
                return;
        }
-       d->first_free -= de->length;
-       memmove(de, de_next_de(de), d->first_free + (char *)d - (char *)de);
+       d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length));
+       memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de);
 }
 
 static void fix_up_ptrs(struct super_block *s, struct dnode *d)
 {
        struct hpfs_dirent *de;
        struct hpfs_dirent *de_end = dnode_end_de(d);
-       dnode_secno dno = d->self;
+       dnode_secno dno = le32_to_cpu(d->self);
        for (de = dnode_first_de(d); de < de_end; de = de_next_de(de))
                if (de->down) {
                        struct quad_buffer_head qbh;
                        struct dnode *dd;
                        if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) {
-                               if (dd->up != dno || dd->root_dnode) {
-                                       dd->up = dno;
+                               if (le32_to_cpu(dd->up) != dno || dd->root_dnode) {
+                                       dd->up = cpu_to_le32(dno);
                                        dd->root_dnode = 0;
                                        hpfs_mark_4buffers_dirty(&qbh);
                                }
@@ -262,7 +262,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
                        kfree(nname);
                        return 1;
                }
-       if (d->first_free + de_size(namelen, down_ptr) <= 2048) {
+       if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) {
                loff_t t;
                copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de);
                t = get_pos(d, de);
@@ -286,11 +286,11 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
                kfree(nname);
                return 1;
        }       
-       memcpy(nd, d, d->first_free);
+       memcpy(nd, d, le32_to_cpu(d->first_free));
        copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de);
        for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1);
        h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10;
-       if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1, 0))) {
+       if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) {
                hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
                hpfs_brelse4(&qbh);
                kfree(nd);
@@ -313,20 +313,21 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
        down_ptr = adno;
        set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0);
        de = de_next_de(de);
-       memmove((char *)nd + 20, de, nd->first_free + (char *)nd - (char *)de);
-       nd->first_free -= (char *)de - (char *)nd - 20;
-       memcpy(d, nd, nd->first_free);
+       memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de);
+       nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - ((char *)de - (char *)nd - 20));
+       memcpy(d, nd, le32_to_cpu(nd->first_free));
        for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos);
        fix_up_ptrs(i->i_sb, ad);
        if (!d->root_dnode) {
-               dno = ad->up = d->up;
+               ad->up = d->up;
+               dno = le32_to_cpu(ad->up);
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
                hpfs_mark_4buffers_dirty(&qbh1);
                hpfs_brelse4(&qbh1);
                goto go_up;
        }
-       if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2, 0))) {
+       if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) {
                hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
                hpfs_brelse4(&qbh);
                hpfs_brelse4(&qbh1);
@@ -338,7 +339,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
        i->i_blocks += 4;
        rd->root_dnode = 1;
        rd->up = d->up;
-       if (!(fnode = hpfs_map_fnode(i->i_sb, d->up, &bh))) {
+       if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) {
                hpfs_free_dnode(i->i_sb, rdno);
                hpfs_brelse4(&qbh);
                hpfs_brelse4(&qbh1);
@@ -347,10 +348,11 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
                kfree(nname);
                return 1;
        }
-       fnode->u.external[0].disk_secno = rdno;
+       fnode->u.external[0].disk_secno = cpu_to_le32(rdno);
        mark_buffer_dirty(bh);
        brelse(bh);
-       d->up = ad->up = hpfs_i(i)->i_dno = rdno;
+       hpfs_i(i)->i_dno = rdno;
+       d->up = ad->up = cpu_to_le32(rdno);
        d->root_dnode = ad->root_dnode = 0;
        hpfs_mark_4buffers_dirty(&qbh);
        hpfs_brelse4(&qbh);
@@ -373,7 +375,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
 
 int hpfs_add_dirent(struct inode *i,
                    const unsigned char *name, unsigned namelen,
-                   struct hpfs_dirent *new_de, int cdepth)
+                   struct hpfs_dirent *new_de)
 {
        struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
        struct dnode *d;
@@ -403,7 +405,6 @@ int hpfs_add_dirent(struct inode *i,
                }
        }
        hpfs_brelse4(&qbh);
-       if (!cdepth) hpfs_lock_creation(i->i_sb);
        if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) {
                c = 1;
                goto ret;
@@ -411,7 +412,6 @@ int hpfs_add_dirent(struct inode *i,
        i->i_version++;
        c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0);
        ret:
-       if (!cdepth) hpfs_unlock_creation(i->i_sb);
        return c;
 }
 
@@ -437,9 +437,9 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
                                return 0;
                if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0;
                if (hpfs_sb(i->i_sb)->sb_chk) {
-                       if (dnode->up != chk_up) {
+                       if (le32_to_cpu(dnode->up) != chk_up) {
                                hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x",
-                                       dno, chk_up, dnode->up);
+                                       dno, chk_up, le32_to_cpu(dnode->up));
                                hpfs_brelse4(&qbh);
                                return 0;
                        }
@@ -455,7 +455,7 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
                hpfs_brelse4(&qbh);
        }
        while (!(de = dnode_pre_last_de(dnode))) {
-               dnode_secno up = dnode->up;
+               dnode_secno up = le32_to_cpu(dnode->up);
                hpfs_brelse4(&qbh);
                hpfs_free_dnode(i->i_sb, dno);
                i->i_size -= 2048;
@@ -474,8 +474,8 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
                        hpfs_brelse4(&qbh);
                        return 0;
                }
-               dnode->first_free -= 4;
-               de->length -= 4;
+               dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4);
+               de->length = cpu_to_le16(le16_to_cpu(de->length) - 4);
                de->down = 0;
                hpfs_mark_4buffers_dirty(&qbh);
                dno = up;
@@ -483,12 +483,12 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
        t = get_pos(dnode, de);
        for_all_poss(i, hpfs_pos_subst, t, 4);
        for_all_poss(i, hpfs_pos_subst, t + 1, 5);
-       if (!(nde = kmalloc(de->length, GFP_NOFS))) {
+       if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
                hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted");
                hpfs_brelse4(&qbh);
                return 0;
        }
-       memcpy(nde, de, de->length);
+       memcpy(nde, de, le16_to_cpu(de->length));
        ddno = de->down ? de_down_pointer(de) : 0;
        hpfs_delete_de(i->i_sb, dnode, de);
        set_last_pointer(i->i_sb, dnode, ddno);
@@ -517,11 +517,11 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
        try_it_again:
        if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return;
        if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return;
-       if (dnode->first_free > 56) goto end;
-       if (dnode->first_free == 52 || dnode->first_free == 56) {
+       if (le32_to_cpu(dnode->first_free) > 56) goto end;
+       if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) {
                struct hpfs_dirent *de_end;
                int root = dnode->root_dnode;
-               up = dnode->up;
+               up = le32_to_cpu(dnode->up);
                de = dnode_first_de(dnode);
                down = de->down ? de_down_pointer(de) : 0;
                if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) {
@@ -545,13 +545,13 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
                                return;
                            }
                        if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
-                               d1->up = up;
+                               d1->up = cpu_to_le32(up);
                                d1->root_dnode = 1;
                                hpfs_mark_4buffers_dirty(&qbh1);
                                hpfs_brelse4(&qbh1);
                        }
                        if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) {
-                               fnode->u.external[0].disk_secno = down;
+                               fnode->u.external[0].disk_secno = cpu_to_le32(down);
                                mark_buffer_dirty(bh);
                                brelse(bh);
                        }
@@ -570,22 +570,22 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
                for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p);
                if (!down) {
                        de->down = 0;
-                       de->length -= 4;
-                       dnode->first_free -= 4;
+                       de->length = cpu_to_le16(le16_to_cpu(de->length) - 4);
+                       dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4);
                        memmove(de_next_de(de), (char *)de_next_de(de) + 4,
-                               (char *)dnode + dnode->first_free - (char *)de_next_de(de));
+                               (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de));
                } else {
                        struct dnode *d1;
                        struct quad_buffer_head qbh1;
-                       *(dnode_secno *) ((void *) de + de->length - 4) = down;
+                       *(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down;
                        if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
-                               d1->up = up;
+                               d1->up = cpu_to_le32(up);
                                hpfs_mark_4buffers_dirty(&qbh1);
                                hpfs_brelse4(&qbh1);
                        }
                }
        } else {
-               hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, dnode->first_free);
+               hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free));
                goto end;
        }
 
@@ -596,18 +596,18 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
                struct quad_buffer_head qbh1;
                if (!de_next->down) goto endm;
                ndown = de_down_pointer(de_next);
-               if (!(de_cp = kmalloc(de->length, GFP_NOFS))) {
+               if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
                        printk("HPFS: out of memory for dtree balancing\n");
                        goto endm;
                }
-               memcpy(de_cp, de, de->length);
+               memcpy(de_cp, de, le16_to_cpu(de->length));
                hpfs_delete_de(i->i_sb, dnode, de);
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
                for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4);
                for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1);
                if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) {
-                       d1->up = ndown;
+                       d1->up = cpu_to_le32(ndown);
                        hpfs_mark_4buffers_dirty(&qbh1);
                        hpfs_brelse4(&qbh1);
                }
@@ -635,7 +635,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
                        struct hpfs_dirent *del = dnode_last_de(d1);
                        dlp = del->down ? de_down_pointer(del) : 0;
                        if (!dlp && down) {
-                               if (d1->first_free > 2044) {
+                               if (le32_to_cpu(d1->first_free) > 2044) {
                                        if (hpfs_sb(i->i_sb)->sb_chk >= 2) {
                                                printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n");
                                                printk("HPFS: warning: terminating balancing operation\n");
@@ -647,38 +647,38 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
                                        printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n");
                                        printk("HPFS: warning: goin'on\n");
                                }
-                               del->length += 4;
+                               del->length = cpu_to_le16(le16_to_cpu(del->length) + 4);
                                del->down = 1;
-                               d1->first_free += 4;
+                               d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) + 4);
                        }
                        if (dlp && !down) {
-                               del->length -= 4;
+                               del->length = cpu_to_le16(le16_to_cpu(del->length) - 4);
                                del->down = 0;
-                               d1->first_free -= 4;
+                               d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4);
                        } else if (down)
-                               *(dnode_secno *) ((void *) del + del->length - 4) = down;
+                               *(dnode_secno *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down);
                } else goto endm;
-               if (!(de_cp = kmalloc(de_prev->length, GFP_NOFS))) {
+               if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) {
                        printk("HPFS: out of memory for dtree balancing\n");
                        hpfs_brelse4(&qbh1);
                        goto endm;
                }
                hpfs_mark_4buffers_dirty(&qbh1);
                hpfs_brelse4(&qbh1);
-               memcpy(de_cp, de_prev, de_prev->length);
+               memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length));
                hpfs_delete_de(i->i_sb, dnode, de_prev);
                if (!de_prev->down) {
-                       de_prev->length += 4;
+                       de_prev->length = cpu_to_le16(le16_to_cpu(de_prev->length) + 4);
                        de_prev->down = 1;
-                       dnode->first_free += 4;
+                       dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4);
                }
-               *(dnode_secno *) ((void *) de_prev + de_prev->length - 4) = ndown;
+               *(dnode_secno *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown);
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
                for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4);
                for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1));
                if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) {
-                       d1->up = ndown;
+                       d1->up = cpu_to_le32(ndown);
                        hpfs_mark_4buffers_dirty(&qbh1);
                        hpfs_brelse4(&qbh1);
                }
@@ -701,7 +701,6 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
 {
        struct dnode *dnode = qbh->data;
        dnode_secno down = 0;
-       int lock = 0;
        loff_t t;
        if (de->first || de->last) {
                hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno);
@@ -710,11 +709,8 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
        }
        if (de->down) down = de_down_pointer(de);
        if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) {
-               lock = 1;
-               hpfs_lock_creation(i->i_sb);
                if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) {
                        hpfs_brelse4(qbh);
-                       hpfs_unlock_creation(i->i_sb);
                        return 2;
                }
        }
@@ -727,11 +723,9 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
                dnode_secno a = move_to_top(i, down, dno);
                for_all_poss(i, hpfs_pos_subst, 5, t);
                if (a) delete_empty_dnode(i, a);
-               if (lock) hpfs_unlock_creation(i->i_sb);
                return !a;
        }
        delete_empty_dnode(i, dno);
-       if (lock) hpfs_unlock_creation(i->i_sb);
        return 0;
 }
 
@@ -751,8 +745,8 @@ void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes,
        ptr = 0;
        go_up:
        if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
-       if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && dnode->up != odno)
-               hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, dnode->up);
+       if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno)
+               hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up));
        de = dnode_first_de(dnode);
        if (ptr) while(1) {
                if (de->down) if (de_down_pointer(de) == ptr) goto process_de;
@@ -776,7 +770,7 @@ void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes,
        if (!de->first && !de->last && n_items) (*n_items)++;
        if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de;
        ptr = dno;
-       dno = dnode->up;
+       dno = le32_to_cpu(dnode->up);
        if (dnode->root_dnode) {
                hpfs_brelse4(&qbh);
                return;
@@ -824,8 +818,8 @@ dnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno)
                        return d;
        if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno;
        if (hpfs_sb(s)->sb_chk)
-               if (up && ((struct dnode *)qbh.data)->up != up)
-                       hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, ((struct dnode *)qbh.data)->up);
+               if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up)
+                       hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, le32_to_cpu(((struct dnode *)qbh.data)->up));
        if (!de->down) {
                hpfs_brelse4(&qbh);
                return d;
@@ -874,7 +868,7 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
        /* Going up */
        if (dnode->root_dnode) goto bail;
 
-       if (!(up_dnode = hpfs_map_dnode(inode->i_sb, dnode->up, &qbh0)))
+       if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0)))
                goto bail;
 
        end_up_de = dnode_end_de(up_dnode);
@@ -882,16 +876,16 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
        for (up_de = dnode_first_de(up_dnode); up_de < end_up_de;
             up_de = de_next_de(up_de)) {
                if (!(++c & 077)) hpfs_error(inode->i_sb,
-                       "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", dnode->up);
+                       "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up));
                if (up_de->down && de_down_pointer(up_de) == dno) {
-                       *posp = ((loff_t) dnode->up << 4) + c;
+                       *posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c;
                        hpfs_brelse4(&qbh0);
                        return de;
                }
        }
        
        hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x",
-               dno, dnode->up);
+               dno, le32_to_cpu(dnode->up));
        hpfs_brelse4(&qbh0);
        
        bail:
@@ -1017,17 +1011,17 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
                /*name2[15] = 0xff;*/
                name1len = 15; name2len = 256;
        }
-       if (!(upf = hpfs_map_fnode(s, f->up, &bh))) {
+       if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) {
                kfree(name2);
                return NULL;
        }       
        if (!upf->dirflag) {
                brelse(bh);
-               hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, f->up);
+               hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up));
                kfree(name2);
                return NULL;
        }
-       dno = upf->u.external[0].disk_secno;
+       dno = le32_to_cpu(upf->u.external[0].disk_secno);
        brelse(bh);
        go_down:
        downd = 0;
@@ -1049,7 +1043,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
                return NULL;
        }
        next_de:
-       if (de->fnode == fno) {
+       if (le32_to_cpu(de->fnode) == fno) {
                kfree(name2);
                return de;
        }
@@ -1065,7 +1059,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
                goto go_down;
        }
        f:
-       if (de->fnode == fno) {
+       if (le32_to_cpu(de->fnode) == fno) {
                kfree(name2);
                return de;
        }
@@ -1074,7 +1068,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
        if ((de = de_next_de(de)) < de_end) goto next_de;
        if (d->root_dnode) goto not_found;
        downd = dno;
-       dno = d->up;
+       dno = le32_to_cpu(d->up);
        hpfs_brelse4(qbh);
        if (hpfs_sb(s)->sb_chk)
                if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) {
index 45e53d972b42ed27e931c5fa01ae5fb194b0c5f2..d8b84d113c891bbcfd8416d3f35153983b0549a7 100644 (file)
@@ -24,7 +24,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
                }
                if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return;
                if (ea->indirect) {
-                       if (ea->valuelen != 8) {
+                       if (ea_valuelen(ea) != 8) {
                                hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x",
                                        ano ? "anode" : "sectors", a, pos);
                                return;
@@ -33,7 +33,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
                                return;
                        hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea));
                }
-               pos += ea->namelen + ea->valuelen + 5;
+               pos += ea->namelen + ea_valuelen(ea) + 5;
        }
        if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9);
        else {
@@ -76,24 +76,24 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
        unsigned pos;
        int ano, len;
        secno a;
+       char ex[4 + 255 + 1 + 8];
        struct extended_attribute *ea;
        struct extended_attribute *ea_end = fnode_end_ea(fnode);
        for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
                if (!strcmp(ea->name, key)) {
                        if (ea->indirect)
                                goto indirect;
-                       if (ea->valuelen >= size)
+                       if (ea_valuelen(ea) >= size)
                                return -EINVAL;
-                       memcpy(buf, ea_data(ea), ea->valuelen);
-                       buf[ea->valuelen] = 0;
+                       memcpy(buf, ea_data(ea), ea_valuelen(ea));
+                       buf[ea_valuelen(ea)] = 0;
                        return 0;
                }
-       a = fnode->ea_secno;
-       len = fnode->ea_size_l;
+       a = le32_to_cpu(fnode->ea_secno);
+       len = le32_to_cpu(fnode->ea_size_l);
        ano = fnode->ea_anode;
        pos = 0;
        while (pos < len) {
-               char ex[4 + 255 + 1 + 8];
                ea = (struct extended_attribute *)ex;
                if (pos + 4 > len) {
                        hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x",
@@ -106,14 +106,14 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
                if (!strcmp(ea->name, key)) {
                        if (ea->indirect)
                                goto indirect;
-                       if (ea->valuelen >= size)
+                       if (ea_valuelen(ea) >= size)
                                return -EINVAL;
-                       if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, buf))
+                       if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), buf))
                                return -EIO;
-                       buf[ea->valuelen] = 0;
+                       buf[ea_valuelen(ea)] = 0;
                        return 0;
                }
-               pos += ea->namelen + ea->valuelen + 5;
+               pos += ea->namelen + ea_valuelen(ea) + 5;
        }
        return -ENOENT;
 indirect:
@@ -138,16 +138,16 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
                if (!strcmp(ea->name, key)) {
                        if (ea->indirect)
                                return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
-                       if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) {
+                       if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) {
                                printk("HPFS: out of memory for EA\n");
                                return NULL;
                        }
-                       memcpy(ret, ea_data(ea), ea->valuelen);
-                       ret[ea->valuelen] = 0;
+                       memcpy(ret, ea_data(ea), ea_valuelen(ea));
+                       ret[ea_valuelen(ea)] = 0;
                        return ret;
                }
-       a = fnode->ea_secno;
-       len = fnode->ea_size_l;
+       a = le32_to_cpu(fnode->ea_secno);
+       len = le32_to_cpu(fnode->ea_size_l);
        ano = fnode->ea_anode;
        pos = 0;
        while (pos < len) {
@@ -164,18 +164,18 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
                if (!strcmp(ea->name, key)) {
                        if (ea->indirect)
                                return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
-                       if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) {
+                       if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) {
                                printk("HPFS: out of memory for EA\n");
                                return NULL;
                        }
-                       if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, ret)) {
+                       if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), ret)) {
                                kfree(ret);
                                return NULL;
                        }
-                       ret[ea->valuelen] = 0;
+                       ret[ea_valuelen(ea)] = 0;
                        return ret;
                }
-               pos += ea->namelen + ea->valuelen + 5;
+               pos += ea->namelen + ea_valuelen(ea) + 5;
        }
        return NULL;
 }
@@ -202,13 +202,13 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
                        if (ea->indirect) {
                                if (ea_len(ea) == size)
                                        set_indirect_ea(s, ea->anode, ea_sec(ea), data, size);
-                       } else if (ea->valuelen == size) {
+                       } else if (ea_valuelen(ea) == size) {
                                memcpy(ea_data(ea), data, size);
                        }
                        return;
                }
-       a = fnode->ea_secno;
-       len = fnode->ea_size_l;
+       a = le32_to_cpu(fnode->ea_secno);
+       len = le32_to_cpu(fnode->ea_size_l);
        ano = fnode->ea_anode;
        pos = 0;
        while (pos < len) {
@@ -228,68 +228,70 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
                                        set_indirect_ea(s, ea->anode, ea_sec(ea), data, size);
                        }
                        else {
-                               if (ea->valuelen == size)
+                               if (ea_valuelen(ea) == size)
                                        hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data);
                        }
                        return;
                }
-               pos += ea->namelen + ea->valuelen + 5;
+               pos += ea->namelen + ea_valuelen(ea) + 5;
        }
-       if (!fnode->ea_offs) {
-               /*if (fnode->ea_size_s) {
+       if (!le16_to_cpu(fnode->ea_offs)) {
+               /*if (le16_to_cpu(fnode->ea_size_s)) {
                        hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0",
-                               inode->i_ino, fnode->ea_size_s);
+                               inode->i_ino, le16_to_cpu(fnode->ea_size_s));
                        return;
                }*/
-               fnode->ea_offs = 0xc4;
+               fnode->ea_offs = cpu_to_le16(0xc4);
        }
-       if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200) {
+       if (le16_to_cpu(fnode->ea_offs) < 0xc4 || le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200) {
                hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x",
                        (unsigned long)inode->i_ino,
-                       fnode->ea_offs, fnode->ea_size_s);
+                       le32_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s));
                return;
        }
-       if ((fnode->ea_size_s || !fnode->ea_size_l) &&
-            fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) {
+       if ((le16_to_cpu(fnode->ea_size_s) || !le32_to_cpu(fnode->ea_size_l)) &&
+            le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5 <= 0x200) {
                ea = fnode_end_ea(fnode);
                *(char *)ea = 0;
                ea->namelen = strlen(key);
-               ea->valuelen = size;
+               ea->valuelen_lo = size;
+               ea->valuelen_hi = size >> 8;
                strcpy(ea->name, key);
                memcpy(ea_data(ea), data, size);
-               fnode->ea_size_s += strlen(key) + size + 5;
+               fnode->ea_size_s = cpu_to_le16(le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5);
                goto ret;
        }
        /* Most the code here is 99.9993422% unused. I hope there are no bugs.
           But what .. HPFS.IFS has also bugs in ea management. */
-       if (fnode->ea_size_s && !fnode->ea_size_l) {
+       if (le16_to_cpu(fnode->ea_size_s) && !le32_to_cpu(fnode->ea_size_l)) {
                secno n;
                struct buffer_head *bh;
                char *data;
-               if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return;
+               if (!(n = hpfs_alloc_sector(s, fno, 1, 0))) return;
                if (!(data = hpfs_get_sector(s, n, &bh))) {
                        hpfs_free_sectors(s, n, 1);
                        return;
                }
-               memcpy(data, fnode_ea(fnode), fnode->ea_size_s);
-               fnode->ea_size_l = fnode->ea_size_s;
-               fnode->ea_size_s = 0;
-               fnode->ea_secno = n;
-               fnode->ea_anode = 0;
+               memcpy(data, fnode_ea(fnode), le16_to_cpu(fnode->ea_size_s));
+               fnode->ea_size_l = cpu_to_le32(le16_to_cpu(fnode->ea_size_s));
+               fnode->ea_size_s = cpu_to_le16(0);
+               fnode->ea_secno = cpu_to_le32(n);
+               fnode->ea_anode = cpu_to_le32(0);
                mark_buffer_dirty(bh);
                brelse(bh);
        }
-       pos = fnode->ea_size_l + 5 + strlen(key) + size;
-       len = (fnode->ea_size_l + 511) >> 9;
+       pos = le32_to_cpu(fnode->ea_size_l) + 5 + strlen(key) + size;
+       len = (le32_to_cpu(fnode->ea_size_l) + 511) >> 9;
        if (pos >= 30000) goto bail;
        while (((pos + 511) >> 9) > len) {
                if (!len) {
-                       if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1)))
-                               goto bail;
+                       secno q = hpfs_alloc_sector(s, fno, 1, 0);
+                       if (!q) goto bail;
+                       fnode->ea_secno = cpu_to_le32(q);
                        fnode->ea_anode = 0;
                        len++;
                } else if (!fnode->ea_anode) {
-                       if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) {
+                       if (hpfs_alloc_if_possible(s, le32_to_cpu(fnode->ea_secno) + len)) {
                                len++;
                        } else {
                                /* Aargh... don't know how to create ea anodes :-( */
@@ -298,26 +300,26 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
                                anode_secno a_s;
                                if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh)))
                                        goto bail;
-                               anode->up = fno;
+                               anode->up = cpu_to_le32(fno);
                                anode->btree.fnode_parent = 1;
                                anode->btree.n_free_nodes--;
                                anode->btree.n_used_nodes++;
-                               anode->btree.first_free += 12;
-                               anode->u.external[0].disk_secno = fnode->ea_secno;
-                               anode->u.external[0].file_secno = 0;
-                               anode->u.external[0].length = len;
+                               anode->btree.first_free = cpu_to_le16(le16_to_cpu(anode->btree.first_free) + 12);
+                               anode->u.external[0].disk_secno = cpu_to_le32(le32_to_cpu(fnode->ea_secno));
+                               anode->u.external[0].file_secno = cpu_to_le32(0);
+                               anode->u.external[0].length = cpu_to_le32(len);
                                mark_buffer_dirty(bh);
                                brelse(bh);
                                fnode->ea_anode = 1;
-                               fnode->ea_secno = a_s;*/
+                               fnode->ea_secno = cpu_to_le32(a_s);*/
                                secno new_sec;
                                int i;
-                               if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1)))
+                               if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9))))
                                        goto bail;
                                for (i = 0; i < len; i++) {
                                        struct buffer_head *bh1, *bh2;
                                        void *b1, *b2;
-                                       if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) {
+                                       if (!(b1 = hpfs_map_sector(s, le32_to_cpu(fnode->ea_secno) + i, &bh1, len - i - 1))) {
                                                hpfs_free_sectors(s, new_sec, (pos + 511) >> 9);
                                                goto bail;
                                        }
@@ -331,13 +333,13 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
                                        mark_buffer_dirty(bh2);
                                        brelse(bh2);
                                }
-                               hpfs_free_sectors(s, fnode->ea_secno, len);
-                               fnode->ea_secno = new_sec;
+                               hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno), len);
+                               fnode->ea_secno = cpu_to_le32(new_sec);
                                len = (pos + 511) >> 9;
                        }
                }
                if (fnode->ea_anode) {
-                       if (hpfs_add_sector_to_btree(s, fnode->ea_secno,
+                       if (hpfs_add_sector_to_btree(s, le32_to_cpu(fnode->ea_secno),
                                                     0, len) != -1) {
                                len++;
                        } else {
@@ -349,17 +351,17 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
        h[1] = strlen(key);
        h[2] = size & 0xff;
        h[3] = size >> 8;
-       if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail;
-       if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail;
-       if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail;
-       fnode->ea_size_l = pos;
+       if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l), 4, h)) goto bail;
+       if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 4, h[1] + 1, key)) goto bail;
+       if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 5 + h[1], size, data)) goto bail;
+       fnode->ea_size_l = cpu_to_le32(pos);
        ret:
        hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size;
        return;
        bail:
-       if (fnode->ea_secno)
-               if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9);
-               else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9));
-       else fnode->ea_secno = fnode->ea_size_l = 0;
+       if (le32_to_cpu(fnode->ea_secno))
+               if (fnode->ea_anode) hpfs_truncate_btree(s, le32_to_cpu(fnode->ea_secno), 1, (le32_to_cpu(fnode->ea_size_l) + 511) >> 9);
+               else hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno) + ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9), len - ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9));
+       else fnode->ea_secno = fnode->ea_size_l = cpu_to_le32(0);
 }
        
index 9b9eb6933e43d8620a38ec744f77d4d8712e3b9a..89c500ee521382c2250c0a818a3c18c773025ac8 100644 (file)
@@ -20,8 +20,8 @@ static int hpfs_file_release(struct inode *inode, struct file *file)
 
 int hpfs_file_fsync(struct file *file, int datasync)
 {
-       /*return file_fsync(file, datasync);*/
-       return 0; /* Don't fsync :-) */
+       struct inode *inode = file->f_mapping->host;
+       return sync_blockdev(inode->i_sb->s_bdev);
 }
 
 /*
@@ -48,38 +48,46 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
 static void hpfs_truncate(struct inode *i)
 {
        if (IS_IMMUTABLE(i)) return /*-EPERM*/;
-       hpfs_lock(i->i_sb);
+       hpfs_lock_assert(i->i_sb);
+
        hpfs_i(i)->i_n_secs = 0;
        i->i_blocks = 1 + ((i->i_size + 511) >> 9);
        hpfs_i(i)->mmu_private = i->i_size;
        hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
        hpfs_write_inode(i);
        hpfs_i(i)->i_n_secs = 0;
-       hpfs_unlock(i->i_sb);
 }
 
 static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
 {
+       int r;
        secno s;
+       hpfs_lock(inode->i_sb);
        s = hpfs_bmap(inode, iblock);
        if (s) {
                map_bh(bh_result, inode->i_sb, s);
-               return 0;
+               goto ret_0;
        }
-       if (!create) return 0;
+       if (!create) goto ret_0;
        if (iblock<<9 != hpfs_i(inode)->mmu_private) {
                BUG();
-               return -EIO;
+               r = -EIO;
+               goto ret_r;
        }
        if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) {
                hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
-               return -ENOSPC;
+               r = -ENOSPC;
+               goto ret_r;
        }
        inode->i_blocks++;
        hpfs_i(inode)->mmu_private += 512;
        set_buffer_new(bh_result);
        map_bh(bh_result, inode->i_sb, s);
-       return 0;
+       ret_0:
+       r = 0;
+       ret_r:
+       hpfs_unlock(inode->i_sb);
+       return r;
 }
 
 static int hpfs_writepage(struct page *page, struct writeback_control *wbc)
@@ -130,8 +138,11 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
        ssize_t retval;
 
        retval = do_sync_write(file, buf, count, ppos);
-       if (retval > 0)
+       if (retval > 0) {
+               hpfs_lock(file->f_path.dentry->d_sb);
                hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1;
+               hpfs_unlock(file->f_path.dentry->d_sb);
+       }
        return retval;
 }
 
index 0e84c73cd9c4ea88514e6d145bb6a753a3205c03..8b0650aae32812bac9abbb581439b592d64949d2 100644 (file)
    For definitive information on HPFS, ask somebody else -- this is guesswork.
    There are certain to be many mistakes. */
 
+#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
+#error unknown endian
+#endif
+
 /* Notation */
 
-typedef unsigned secno;                        /* sector number, partition relative */
+typedef u32 secno;                     /* sector number, partition relative */
 
 typedef secno dnode_secno;             /* sector number of a dnode */
 typedef secno fnode_secno;             /* sector number of an fnode */
@@ -38,28 +42,28 @@ typedef u32 time32_t;               /* 32-bit time_t type */
 
 struct hpfs_boot_block
 {
-  unsigned char jmp[3];
-  unsigned char oem_id[8];
-  unsigned char bytes_per_sector[2];   /* 512 */
-  unsigned char sectors_per_cluster;
-  unsigned char n_reserved_sectors[2];
-  unsigned char n_fats;
-  unsigned char n_rootdir_entries[2];
-  unsigned char n_sectors_s[2];
-  unsigned char media_byte;
-  unsigned short sectors_per_fat;
-  unsigned short sectors_per_track;
-  unsigned short heads_per_cyl;
-  unsigned int n_hidden_sectors;
-  unsigned int n_sectors_l;            /* size of partition */
-  unsigned char drive_number;
-  unsigned char mbz;
-  unsigned char sig_28h;               /* 28h */
-  unsigned char vol_serno[4];
-  unsigned char vol_label[11];
-  unsigned char sig_hpfs[8];           /* "HPFS    " */
-  unsigned char pad[448];
-  unsigned short magic;                        /* aa55 */
+  u8 jmp[3];
+  u8 oem_id[8];
+  u8 bytes_per_sector[2];      /* 512 */
+  u8 sectors_per_cluster;
+  u8 n_reserved_sectors[2];
+  u8 n_fats;
+  u8 n_rootdir_entries[2];
+  u8 n_sectors_s[2];
+  u8 media_byte;
+  u16 sectors_per_fat;
+  u16 sectors_per_track;
+  u16 heads_per_cyl;
+  u32 n_hidden_sectors;
+  u32 n_sectors_l;             /* size of partition */
+  u8 drive_number;
+  u8 mbz;
+  u8 sig_28h;                  /* 28h */
+  u8 vol_serno[4];
+  u8 vol_label[11];
+  u8 sig_hpfs[8];              /* "HPFS    " */
+  u8 pad[448];
+  u16 magic;                   /* aa55 */
 };
 
 
@@ -71,31 +75,29 @@ struct hpfs_boot_block
 
 struct hpfs_super_block
 {
-  unsigned magic;                      /* f995 e849 */
-  unsigned magic1;                     /* fa53 e9c5, more magic? */
-  /*unsigned huh202;*/                 /* ?? 202 = N. of B. in 1.00390625 S.*/
-  char version;                                /* version of a filesystem  usually 2 */
-  char funcversion;                    /* functional version - oldest version
+  u32 magic;                           /* f995 e849 */
+  u32 magic1;                          /* fa53 e9c5, more magic? */
+  u8 version;                          /* version of a filesystem  usually 2 */
+  u8 funcversion;                      /* functional version - oldest version
                                           of filesystem that can understand
                                           this disk */
-  unsigned short int zero;             /* 0 */
+  u16 zero;                            /* 0 */
   fnode_secno root;                    /* fnode of root directory */
   secno n_sectors;                     /* size of filesystem */
-  unsigned n_badblocks;                        /* number of bad blocks */
+  u32 n_badblocks;                     /* number of bad blocks */
   secno bitmaps;                       /* pointers to free space bit maps */
-  unsigned zero1;                      /* 0 */
+  u32 zero1;                           /* 0 */
   secno badblocks;                     /* bad block list */
-  unsigned zero3;                      /* 0 */
+  u32 zero3;                           /* 0 */
   time32_t last_chkdsk;                        /* date last checked, 0 if never */
-  /*unsigned zero4;*/                  /* 0 */
-  time32_t last_optimize;                      /* date last optimized, 0 if never */
+  time32_t last_optimize;              /* date last optimized, 0 if never */
   secno n_dir_band;                    /* number of sectors in dir band */
   secno dir_band_start;                        /* first sector in dir band */
   secno dir_band_end;                  /* last sector in dir band */
   secno dir_band_bitmap;               /* free space map, 1 dnode per bit */
-  char volume_name[32];                        /* not used */
+  u8 volume_name[32];                  /* not used */
   secno user_id_table;                 /* 8 preallocated sectors - user id */
-  unsigned zero6[103];                 /* 0 */
+  u32 zero6[103];                      /* 0 */
 };
 
 
@@ -107,44 +109,65 @@ struct hpfs_super_block
 
 struct hpfs_spare_block
 {
-  unsigned magic;                      /* f991 1849 */
-  unsigned magic1;                     /* fa52 29c5, more magic? */
-
-  unsigned dirty: 1;                   /* 0 clean, 1 "improperly stopped" */
-  /*unsigned flag1234: 4;*/            /* unknown flags */
-  unsigned sparedir_used: 1;           /* spare dirblks used */
-  unsigned hotfixes_used: 1;           /* hotfixes used */
-  unsigned bad_sector: 1;              /* bad sector, corrupted disk (???) */
-  unsigned bad_bitmap: 1;              /* bad bitmap */
-  unsigned fast: 1;                    /* partition was fast formatted */
-  unsigned old_wrote: 1;               /* old version wrote to partion */
-  unsigned old_wrote_1: 1;             /* old version wrote to partion (?) */
-  unsigned install_dasd_limits: 1;     /* HPFS386 flags */
-  unsigned resynch_dasd_limits: 1;
-  unsigned dasd_limits_operational: 1;
-  unsigned multimedia_active: 1;
-  unsigned dce_acls_active: 1;
-  unsigned dasd_limits_dirty: 1;
-  unsigned flag67: 2;
-  unsigned char mm_contlgulty;
-  unsigned char unused;
+  u32 magic;                           /* f991 1849 */
+  u32 magic1;                          /* fa52 29c5, more magic? */
+
+#ifdef __LITTLE_ENDIAN
+  u8 dirty: 1;                         /* 0 clean, 1 "improperly stopped" */
+  u8 sparedir_used: 1;                 /* spare dirblks used */
+  u8 hotfixes_used: 1;                 /* hotfixes used */
+  u8 bad_sector: 1;                    /* bad sector, corrupted disk (???) */
+  u8 bad_bitmap: 1;                    /* bad bitmap */
+  u8 fast: 1;                          /* partition was fast formatted */
+  u8 old_wrote: 1;                     /* old version wrote to partion */
+  u8 old_wrote_1: 1;                   /* old version wrote to partion (?) */
+#else
+  u8 old_wrote_1: 1;                   /* old version wrote to partion (?) */
+  u8 old_wrote: 1;                     /* old version wrote to partion */
+  u8 fast: 1;                          /* partition was fast formatted */
+  u8 bad_bitmap: 1;                    /* bad bitmap */
+  u8 bad_sector: 1;                    /* bad sector, corrupted disk (???) */
+  u8 hotfixes_used: 1;                 /* hotfixes used */
+  u8 sparedir_used: 1;                 /* spare dirblks used */
+  u8 dirty: 1;                         /* 0 clean, 1 "improperly stopped" */
+#endif
+
+#ifdef __LITTLE_ENDIAN
+  u8 install_dasd_limits: 1;           /* HPFS386 flags */
+  u8 resynch_dasd_limits: 1;
+  u8 dasd_limits_operational: 1;
+  u8 multimedia_active: 1;
+  u8 dce_acls_active: 1;
+  u8 dasd_limits_dirty: 1;
+  u8 flag67: 2;
+#else
+  u8 flag67: 2;
+  u8 dasd_limits_dirty: 1;
+  u8 dce_acls_active: 1;
+  u8 multimedia_active: 1;
+  u8 dasd_limits_operational: 1;
+  u8 resynch_dasd_limits: 1;
+  u8 install_dasd_limits: 1;           /* HPFS386 flags */
+#endif
+
+  u8 mm_contlgulty;
+  u8 unused;
 
   secno hotfix_map;                    /* info about remapped bad sectors */
-  unsigned n_spares_used;              /* number of hotfixes */
-  unsigned n_spares;                   /* number of spares in hotfix map */
-  unsigned n_dnode_spares_free;                /* spare dnodes unused */
-  unsigned n_dnode_spares;             /* length of spare_dnodes[] list,
+  u32 n_spares_used;                   /* number of hotfixes */
+  u32 n_spares;                                /* number of spares in hotfix map */
+  u32 n_dnode_spares_free;             /* spare dnodes unused */
+  u32 n_dnode_spares;                  /* length of spare_dnodes[] list,
                                           follows in this block*/
   secno code_page_dir;                 /* code page directory block */
-  unsigned n_code_pages;               /* number of code pages */
-  /*unsigned large_numbers[2];*/       /* ?? */
-  unsigned super_crc;                  /* on HPFS386 and LAN Server this is
+  u32 n_code_pages;                    /* number of code pages */
+  u32 super_crc;                       /* on HPFS386 and LAN Server this is
                                           checksum of superblock, on normal
                                           OS/2 unused */
-  unsigned spare_crc;                  /* on HPFS386 checksum of spareblock */
-  unsigned zero1[15];                  /* unused */
+  u32 spare_crc;                       /* on HPFS386 checksum of spareblock */
+  u32 zero1[15];                       /* unused */
   dnode_secno spare_dnodes[100];       /* emergency free dnode list */
-  unsigned zero2[1];                   /* room for more? */
+  u32 zero2[1];                                /* room for more? */
 };
 
 /* The bad block list is 4 sectors long.  The first word must be zero,
@@ -179,18 +202,18 @@ struct hpfs_spare_block
 
 struct code_page_directory
 {
-  unsigned magic;                      /* 4945 21f7 */
-  unsigned n_code_pages;               /* number of pointers following */
-  unsigned zero1[2];
+  u32 magic;                           /* 4945 21f7 */
+  u32 n_code_pages;                    /* number of pointers following */
+  u32 zero1[2];
   struct {
-    unsigned short ix;                 /* index */
-    unsigned short code_page_number;   /* code page number */
-    unsigned bounds;                   /* matches corresponding word
+    u16 ix;                            /* index */
+    u16 code_page_number;              /* code page number */
+    u32 bounds;                                /* matches corresponding word
                                           in data block */
     secno code_page_data;              /* sector number of a code_page_data
                                           containing c.p. array */
-    unsigned short index;              /* index in c.p. array in that sector*/
-    unsigned short unknown;            /* some unknown value; usually 0;
+    u16 index;                         /* index in c.p. array in that sector*/
+    u16 unknown;                       /* some unknown value; usually 0;
                                           2 in Japanese version */
   } array[31];                         /* unknown length */
 };
@@ -201,21 +224,21 @@ struct code_page_directory
 
 struct code_page_data
 {
-  unsigned magic;                      /* 8945 21f7 */
-  unsigned n_used;                     /* # elements used in c_p_data[] */
-  unsigned bounds[3];                  /* looks a bit like
+  u32 magic;                           /* 8945 21f7 */
+  u32 n_used;                          /* # elements used in c_p_data[] */
+  u32 bounds[3];                       /* looks a bit like
                                             (beg1,end1), (beg2,end2)
                                           one byte each */
-  unsigned short offs[3];              /* offsets from start of sector
+  u16 offs[3];                         /* offsets from start of sector
                                           to start of c_p_data[ix] */
   struct {
-    unsigned short ix;                 /* index */
-    unsigned short code_page_number;   /* code page number */
-    unsigned short unknown;            /* the same as in cp directory */
-    unsigned char map[128];            /* upcase table for chars 80..ff */
-    unsigned short zero2;
+    u16 ix;                            /* index */
+    u16 code_page_number;              /* code page number */
+    u16 unknown;                       /* the same as in cp directory */
+    u8 map[128];                       /* upcase table for chars 80..ff */
+    u16 zero2;
   } code_page[3];
-  unsigned char incognita[78];
+  u8 incognita[78];
 };
 
 
@@ -255,50 +278,84 @@ struct code_page_data
 #define DNODE_MAGIC   0x77e40aae
 
 struct dnode {
-  unsigned magic;                      /* 77e4 0aae */
-  unsigned first_free;                 /* offset from start of dnode to
+  u32 magic;                           /* 77e4 0aae */
+  u32 first_free;                      /* offset from start of dnode to
                                           first free dir entry */
-  unsigned root_dnode:1;               /* Is it root dnode? */
-  unsigned increment_me:31;            /* some kind of activity counter?
-                                          Neither HPFS.IFS nor CHKDSK cares
+#ifdef __LITTLE_ENDIAN
+  u8 root_dnode: 1;                    /* Is it root dnode? */
+  u8 increment_me: 7;                  /* some kind of activity counter? */
+                                       /* Neither HPFS.IFS nor CHKDSK cares
+                                          if you change this word */
+#else
+  u8 increment_me: 7;                  /* some kind of activity counter? */
+                                       /* Neither HPFS.IFS nor CHKDSK cares
                                           if you change this word */
+  u8 root_dnode: 1;                    /* Is it root dnode? */
+#endif
+  u8 increment_me2[3];
   secno up;                            /* (root dnode) directory's fnode
                                           (nonroot) parent dnode */
   dnode_secno self;                    /* pointer to this dnode */
-  unsigned char dirent[2028];          /* one or more dirents */
+  u8 dirent[2028];                     /* one or more dirents */
 };
 
 struct hpfs_dirent {
-  unsigned short length;               /* offset to next dirent */
-  unsigned first: 1;                   /* set on phony ^A^A (".") entry */
-  unsigned has_acl: 1;
-  unsigned down: 1;                    /* down pointer present (after name) */
-  unsigned last: 1;                    /* set on phony \377 entry */
-  unsigned has_ea: 1;                  /* entry has EA */
-  unsigned has_xtd_perm: 1;            /* has extended perm list (???) */
-  unsigned has_explicit_acl: 1;
-  unsigned has_needea: 1;              /* ?? some EA has NEEDEA set
+  u16 length;                          /* offset to next dirent */
+
+#ifdef __LITTLE_ENDIAN
+  u8 first: 1;                         /* set on phony ^A^A (".") entry */
+  u8 has_acl: 1;
+  u8 down: 1;                          /* down pointer present (after name) */
+  u8 last: 1;                          /* set on phony \377 entry */
+  u8 has_ea: 1;                                /* entry has EA */
+  u8 has_xtd_perm: 1;                  /* has extended perm list (???) */
+  u8 has_explicit_acl: 1;
+  u8 has_needea: 1;                    /* ?? some EA has NEEDEA set
+                                          I have no idea why this is
+                                          interesting in a dir entry */
+#else
+  u8 has_needea: 1;                    /* ?? some EA has NEEDEA set
                                           I have no idea why this is
                                           interesting in a dir entry */
-  unsigned read_only: 1;               /* dos attrib */
-  unsigned hidden: 1;                  /* dos attrib */
-  unsigned system: 1;                  /* dos attrib */
-  unsigned flag11: 1;                  /* would be volume label dos attrib */
-  unsigned directory: 1;               /* dos attrib */
-  unsigned archive: 1;                 /* dos attrib */
-  unsigned not_8x3: 1;                 /* name is not 8.3 */
-  unsigned flag15: 1;
+  u8 has_explicit_acl: 1;
+  u8 has_xtd_perm: 1;                  /* has extended perm list (???) */
+  u8 has_ea: 1;                                /* entry has EA */
+  u8 last: 1;                          /* set on phony \377 entry */
+  u8 down: 1;                          /* down pointer present (after name) */
+  u8 has_acl: 1;
+  u8 first: 1;                         /* set on phony ^A^A (".") entry */
+#endif
+
+#ifdef __LITTLE_ENDIAN
+  u8 read_only: 1;                     /* dos attrib */
+  u8 hidden: 1;                                /* dos attrib */
+  u8 system: 1;                                /* dos attrib */
+  u8 flag11: 1;                                /* would be volume label dos attrib */
+  u8 directory: 1;                     /* dos attrib */
+  u8 archive: 1;                       /* dos attrib */
+  u8 not_8x3: 1;                       /* name is not 8.3 */
+  u8 flag15: 1;
+#else
+  u8 flag15: 1;
+  u8 not_8x3: 1;                       /* name is not 8.3 */
+  u8 archive: 1;                       /* dos attrib */
+  u8 directory: 1;                     /* dos attrib */
+  u8 flag11: 1;                                /* would be volume label dos attrib */
+  u8 system: 1;                                /* dos attrib */
+  u8 hidden: 1;                                /* dos attrib */
+  u8 read_only: 1;                     /* dos attrib */
+#endif
+
   fnode_secno fnode;                   /* fnode giving allocation info */
   time32_t write_date;                 /* mtime */
-  unsigned file_size;                  /* file length, bytes */
+  u32 file_size;                       /* file length, bytes */
   time32_t read_date;                  /* atime */
   time32_t creation_date;                      /* ctime */
-  unsigned ea_size;                    /* total EA length, bytes */
-  unsigned char no_of_acls : 3;                /* number of ACL's */
-  unsigned char reserver : 5;
-  unsigned char ix;                    /* code page index (of filename), see
+  u32 ea_size;                         /* total EA length, bytes */
+  u8 no_of_acls;                       /* number of ACL's (low 3 bits) */
+  u8 ix;                               /* code page index (of filename), see
                                           struct code_page_data */
-  unsigned char namelen, name[1];      /* file name */
+  u8 namelen, name[1];                 /* file name */
   /* dnode_secno down;   btree down pointer, if present,
                          follows name on next word boundary, or maybe it
                          precedes next dirent, which is on a word boundary. */
@@ -318,38 +375,50 @@ struct hpfs_dirent {
 
 struct bplus_leaf_node
 {
-  unsigned file_secno;                 /* first file sector in extent */
-  unsigned length;                     /* length, sectors */
+  u32 file_secno;                      /* first file sector in extent */
+  u32 length;                          /* length, sectors */
   secno disk_secno;                    /* first corresponding disk sector */
 };
 
 struct bplus_internal_node
 {
-  unsigned file_secno;                 /* subtree maps sectors < this  */
+  u32 file_secno;                      /* subtree maps sectors < this  */
   anode_secno down;                    /* pointer to subtree */
 };
 
 struct bplus_header
 {
-  unsigned hbff: 1;    /* high bit of first free entry offset */
-  unsigned flag1: 1;
-  unsigned flag2: 1;
-  unsigned flag3: 1;
-  unsigned flag4: 1;
-  unsigned fnode_parent: 1;            /* ? we're pointed to by an fnode,
+#ifdef __LITTLE_ENDIAN
+  u8 hbff: 1;                  /* high bit of first free entry offset */
+  u8 flag1234: 4;
+  u8 fnode_parent: 1;                  /* ? we're pointed to by an fnode,
                                           the data btree or some ea or the
                                           main ea bootage pointer ea_secno */
                                        /* also can get set in fnodes, which
                                           may be a chkdsk glitch or may mean
                                           this bit is irrelevant in fnodes,
                                           or this interpretation is all wet */
-  unsigned binary_search: 1;           /* suggest binary search (unused) */
-  unsigned internal: 1;                        /* 1 -> (internal) tree of anodes
+  u8 binary_search: 1;                 /* suggest binary search (unused) */
+  u8 internal: 1;                      /* 1 -> (internal) tree of anodes
+                                          0 -> (leaf) list of extents */
+#else
+  u8 internal: 1;                      /* 1 -> (internal) tree of anodes
                                           0 -> (leaf) list of extents */
-  unsigned char fill[3];
-  unsigned char n_free_nodes;          /* free nodes in following array */
-  unsigned char n_used_nodes;          /* used nodes in following array */
-  unsigned short first_free;           /* offset from start of header to
+  u8 binary_search: 1;                 /* suggest binary search (unused) */
+  u8 fnode_parent: 1;                  /* ? we're pointed to by an fnode,
+                                          the data btree or some ea or the
+                                          main ea bootage pointer ea_secno */
+                                       /* also can get set in fnodes, which
+                                          may be a chkdsk glitch or may mean
+                                          this bit is irrelevant in fnodes,
+                                          or this interpretation is all wet */
+  u8 flag1234: 4;
+  u8 hbff: 1;                  /* high bit of first free entry offset */
+#endif
+  u8 fill[3];
+  u8 n_free_nodes;                     /* free nodes in following array */
+  u8 n_used_nodes;                     /* used nodes in following array */
+  u16 first_free;                      /* offset from start of header to
                                           first free node in array */
   union {
     struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving
@@ -369,37 +438,38 @@ struct bplus_header
 
 struct fnode
 {
-  unsigned magic;                      /* f7e4 0aae */
-  unsigned zero1[2];                   /* read history */
-  unsigned char len, name[15];         /* true length, truncated name */
+  u32 magic;                           /* f7e4 0aae */
+  u32 zero1[2];                                /* read history */
+  u8 len, name[15];                    /* true length, truncated name */
   fnode_secno up;                      /* pointer to file's directory fnode */
-  /*unsigned zero2[3];*/
   secno acl_size_l;
   secno acl_secno;
-  unsigned short acl_size_s;
-  char acl_anode;
-  char zero2;                          /* history bit count */
-  unsigned ea_size_l;                  /* length of disk-resident ea's */
+  u16 acl_size_s;
+  u8 acl_anode;
+  u8 zero2;                            /* history bit count */
+  u32 ea_size_l;                       /* length of disk-resident ea's */
   secno ea_secno;                      /* first sector of disk-resident ea's*/
-  unsigned short ea_size_s;            /* length of fnode-resident ea's */
-
-  unsigned flag0: 1;
-  unsigned ea_anode: 1;                        /* 1 -> ea_secno is an anode */
-  unsigned flag2: 1;
-  unsigned flag3: 1;
-  unsigned flag4: 1;
-  unsigned flag5: 1;
-  unsigned flag6: 1;
-  unsigned flag7: 1;
-  unsigned dirflag: 1;                 /* 1 -> directory.  first & only extent
+  u16 ea_size_s;                       /* length of fnode-resident ea's */
+
+#ifdef __LITTLE_ENDIAN
+  u8 flag0: 1;
+  u8 ea_anode: 1;                      /* 1 -> ea_secno is an anode */
+  u8 flag234567: 6;
+#else
+  u8 flag234567: 6;
+  u8 ea_anode: 1;                      /* 1 -> ea_secno is an anode */
+  u8 flag0: 1;
+#endif
+
+#ifdef __LITTLE_ENDIAN
+  u8 dirflag: 1;                       /* 1 -> directory.  first & only extent
                                           points to dnode. */
-  unsigned flag9: 1;
-  unsigned flag10: 1;
-  unsigned flag11: 1;
-  unsigned flag12: 1;
-  unsigned flag13: 1;
-  unsigned flag14: 1;
-  unsigned flag15: 1;
+  u8 flag9012345: 7;
+#else
+  u8 flag9012345: 7;
+  u8 dirflag: 1;                       /* 1 -> directory.  first & only extent
+                                          points to dnode. */
+#endif
 
   struct bplus_header btree;           /* b+ tree, 8 extents or 12 subtrees */
   union {
@@ -407,17 +477,16 @@ struct fnode
     struct bplus_internal_node internal[12];
   } u;
 
-  unsigned file_size;                  /* file length, bytes */
-  unsigned n_needea;                   /* number of EA's with NEEDEA set */
-  char user_id[16];                    /* unused */
-  unsigned short ea_offs;              /* offset from start of fnode
+  u32 file_size;                       /* file length, bytes */
+  u32 n_needea;                                /* number of EA's with NEEDEA set */
+  u8 user_id[16];                      /* unused */
+  u16 ea_offs;                         /* offset from start of fnode
                                           to first fnode-resident ea */
-  char dasd_limit_treshhold;
-  char dasd_limit_delta;
-  unsigned dasd_limit;
-  unsigned dasd_usage;
-  /*unsigned zero5[2];*/
-  unsigned char ea[316];               /* zero or more EA's, packed together
+  u8 dasd_limit_treshhold;
+  u8 dasd_limit_delta;
+  u32 dasd_limit;
+  u32 dasd_usage;
+  u8 ea[316];                          /* zero or more EA's, packed together
                                           with no alignment padding.
                                           (Do not use this name, get here
                                           via fnode + ea_offs. I think.) */
@@ -430,7 +499,7 @@ struct fnode
 
 struct anode
 {
-  unsigned magic;                      /* 37e4 0aae */
+  u32 magic;                           /* 37e4 0aae */
   anode_secno self;                    /* pointer to this anode */
   secno up;                            /* parent anode or fnode */
 
@@ -440,7 +509,7 @@ struct anode
     struct bplus_internal_node internal[60];
   } u;
 
-  unsigned fill[3];                    /* unused */
+  u32 fill[3];                         /* unused */
 };
 
 
@@ -461,25 +530,31 @@ struct anode
 
 struct extended_attribute
 {
-  unsigned indirect: 1;                        /* 1 -> value gives sector number
+#ifdef __LITTLE_ENDIAN
+  u8 indirect: 1;                      /* 1 -> value gives sector number
                                           where real value starts */
-  unsigned anode: 1;                   /* 1 -> sector is an anode
+  u8 anode: 1;                         /* 1 -> sector is an anode
+                                          that points to fragmented value */
+  u8 flag23456: 5;
+  u8 needea: 1;                                /* required ea */
+#else
+  u8 needea: 1;                                /* required ea */
+  u8 flag23456: 5;
+  u8 anode: 1;                         /* 1 -> sector is an anode
                                           that points to fragmented value */
-  unsigned flag2: 1;
-  unsigned flag3: 1;
-  unsigned flag4: 1;
-  unsigned flag5: 1;
-  unsigned flag6: 1;
-  unsigned needea: 1;                  /* required ea */
-  unsigned char namelen;               /* length of name, bytes */
-  unsigned short valuelen;             /* length of value, bytes */
-  unsigned char name[0];
+  u8 indirect: 1;                      /* 1 -> value gives sector number
+                                          where real value starts */
+#endif
+  u8 namelen;                          /* length of name, bytes */
+  u8 valuelen_lo;                      /* length of value, bytes */
+  u8 valuelen_hi;                      /* length of value, bytes */
+  u8 name[0];
   /*
-    unsigned char name[namelen];       ascii attrib name
-    unsigned char nul;                 terminating '\0', not counted
-    unsigned char value[valuelen];     value, arbitrary
+    u8 name[namelen];                  ascii attrib name
+    u8 nul;                            terminating '\0', not counted
+    u8 value[valuelen];                        value, arbitrary
       if this.indirect, valuelen is 8 and the value is
-        unsigned length;               real length of value, bytes
+        u32 length;                    real length of value, bytes
         secno secno;                   sector address where it starts
       if this.anode, the above sector number is the root of an anode tree
         which points to the value.
index c15adbca07ff1a433fbf8ec9d2ac03fb34d057c5..dd552f862c8f1c562a34768f970b6ddcb68b2336 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
+#include <asm/unaligned.h>
 
 #include "hpfs.h"
 
@@ -51,18 +52,16 @@ struct hpfs_inode_info {
        unsigned i_disk_sec;    /* (files) minimalist cache of alloc info */
        unsigned i_n_secs;      /* (files) minimalist cache of alloc info */
        unsigned i_ea_size;     /* size of extended attributes */
-       unsigned i_conv : 2;    /* (files) crlf->newline hackery */
        unsigned i_ea_mode : 1; /* file's permission is stored in ea */
        unsigned i_ea_uid : 1;  /* file's uid is stored in ea */
        unsigned i_ea_gid : 1;  /* file's gid is stored in ea */
        unsigned i_dirty : 1;
-       struct mutex i_mutex;
-       struct mutex i_parent_mutex;
        loff_t **i_rddir_off;
        struct inode vfs_inode;
 };
 
 struct hpfs_sb_info {
+       struct mutex hpfs_mutex;        /* global hpfs lock */
        ino_t sb_root;                  /* inode number of root dir */
        unsigned sb_fs_size;            /* file system size, sectors */
        unsigned sb_bitmaps;            /* sector number of bitmap list */
@@ -74,7 +73,6 @@ struct hpfs_sb_info {
        uid_t sb_uid;                   /* uid from mount options */
        gid_t sb_gid;                   /* gid from mount options */
        umode_t sb_mode;                /* mode from mount options */
-       unsigned sb_conv : 2;           /* crlf->newline hackery */
        unsigned sb_eas : 2;            /* eas: 0-ignore, 1-ro, 2-rw */
        unsigned sb_err : 2;            /* on errs: 0-cont, 1-ro, 2-panic */
        unsigned sb_chk : 2;            /* checks: 0-no, 1-normal, 2-strict */
@@ -87,20 +85,9 @@ struct hpfs_sb_info {
        unsigned *sb_bmp_dir;           /* main bitmap directory */
        unsigned sb_c_bitmap;           /* current bitmap */
        unsigned sb_max_fwd_alloc;      /* max forwad allocation */
-       struct mutex hpfs_creation_de;  /* when creating dirents, nobody else
-                                          can alloc blocks */
-       /*unsigned sb_mounting : 1;*/
        int sb_timeshift;
 };
 
-/*
- * conv= options
- */
-
-#define CONV_BINARY 0                  /* no conversion */
-#define CONV_TEXT 1                    /* crlf->newline */
-#define CONV_AUTO 2                    /* decide based on file contents */
-
 /* Four 512-byte buffers and the 2k block obtained by concatenating them */
 
 struct quad_buffer_head {
@@ -113,7 +100,7 @@ struct quad_buffer_head {
 static inline dnode_secno de_down_pointer (struct hpfs_dirent *de)
 {
   CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n"));
-  return *(dnode_secno *) ((void *) de + de->length - 4);
+  return le32_to_cpu(*(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4));
 }
 
 /* The first dir entry in a dnode */
@@ -127,41 +114,46 @@ static inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode)
 
 static inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode)
 {
-  CHKCOND(dnode->first_free>=0x14 && dnode->first_free<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %d\n",(int)dnode->first_free));
-  return (void *) dnode + dnode->first_free;
+  CHKCOND(le32_to_cpu(dnode->first_free)>=0x14 && le32_to_cpu(dnode->first_free)<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %x\n",(unsigned)le32_to_cpu(dnode->first_free)));
+  return (void *) dnode + le32_to_cpu(dnode->first_free);
 }
 
 /* The dir entry after dir entry de */
 
 static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de)
 {
-  CHKCOND(de->length>=0x20 && de->length<0x800,("HPFS: de_next_de: de->length = %d\n",(int)de->length));
-  return (void *) de + de->length;
+  CHKCOND(le16_to_cpu(de->length)>=0x20 && le16_to_cpu(de->length)<0x800,("HPFS: de_next_de: de->length = %x\n",(unsigned)le16_to_cpu(de->length)));
+  return (void *) de + le16_to_cpu(de->length);
 }
 
 static inline struct extended_attribute *fnode_ea(struct fnode *fnode)
 {
-       return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s);
+       return (struct extended_attribute *)((char *)fnode + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s));
 }
 
 static inline struct extended_attribute *fnode_end_ea(struct fnode *fnode)
 {
-       return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s);
+       return (struct extended_attribute *)((char *)fnode + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s));
+}
+
+static unsigned ea_valuelen(struct extended_attribute *ea)
+{
+       return ea->valuelen_lo + 256 * ea->valuelen_hi;
 }
 
 static inline struct extended_attribute *next_ea(struct extended_attribute *ea)
 {
-       return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea->valuelen);
+       return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea_valuelen(ea));
 }
 
 static inline secno ea_sec(struct extended_attribute *ea)
 {
-       return *(secno *)((char *)ea + 9 + ea->namelen);
+       return le32_to_cpu(get_unaligned((secno *)((char *)ea + 9 + ea->namelen)));
 }
 
 static inline secno ea_len(struct extended_attribute *ea)
 {
-       return *(secno *)((char *)ea + 5 + ea->namelen);
+       return le32_to_cpu(get_unaligned((secno *)((char *)ea + 5 + ea->namelen)));
 }
 
 static inline char *ea_data(struct extended_attribute *ea)
@@ -186,13 +178,13 @@ static inline void copy_de(struct hpfs_dirent *dst, struct hpfs_dirent *src)
        dst->not_8x3 = n;
 }
 
-static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n)
+static inline unsigned tstbits(u32 *bmp, unsigned b, unsigned n)
 {
        int i;
        if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n;
-       if (!((bmp[(b & 0x3fff) >> 5] >> (b & 0x1f)) & 1)) return 1;
+       if (!((le32_to_cpu(bmp[(b & 0x3fff) >> 5]) >> (b & 0x1f)) & 1)) return 1;
        for (i = 1; i < n; i++)
-               if (/*b+i < 0x4000 &&*/ !((bmp[((b+i) & 0x3fff) >> 5] >> ((b+i) & 0x1f)) & 1))
+               if (!((le32_to_cpu(bmp[((b+i) & 0x3fff) >> 5]) >> ((b+i) & 0x1f)) & 1))
                        return i + 1;
        return 0;
 }
@@ -200,12 +192,12 @@ static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n)
 /* alloc.c */
 
 int hpfs_chk_sectors(struct super_block *, secno, int, char *);
-secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int, int);
+secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int);
 int hpfs_alloc_if_possible(struct super_block *, secno);
 void hpfs_free_sectors(struct super_block *, secno, unsigned);
 int hpfs_check_free_dnodes(struct super_block *, int);
 void hpfs_free_dnode(struct super_block *, secno);
-struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *, int);
+struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *);
 struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
 struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
 
@@ -222,8 +214,6 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno);
 
 /* buffer.c */
 
-void hpfs_lock_creation(struct super_block *);
-void hpfs_unlock_creation(struct super_block *);
 void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int);
 void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **);
 void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int);
@@ -247,7 +237,7 @@ void hpfs_del_pos(struct inode *, loff_t *);
 struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *,
                                const unsigned char *, unsigned, secno);
 int hpfs_add_dirent(struct inode *, const unsigned char *, unsigned,
-                   struct hpfs_dirent *, int);
+                   struct hpfs_dirent *);
 int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int);
 void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *);
 dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno);
@@ -303,7 +293,6 @@ int hpfs_compare_names(struct super_block *, const unsigned char *, unsigned,
                       const unsigned char *, unsigned, int);
 int hpfs_is_name_long(const unsigned char *, unsigned);
 void hpfs_adjust_length(const unsigned char *, unsigned *);
-void hpfs_decide_conv(struct inode *, const unsigned char *, unsigned);
 
 /* namei.c */
 
@@ -346,21 +335,26 @@ static inline time32_t gmt_to_local(struct super_block *s, time_t t)
 /*
  * Locking:
  *
- * hpfs_lock() is a leftover from the big kernel lock.
- * Right now, these functions are empty and only left
- * for documentation purposes. The file system no longer
- * works on SMP systems, so the lock is not needed
- * any more.
+ * hpfs_lock() locks the whole filesystem. It must be taken
+ * on any method called by the VFS.
  *
- * If someone is interested in making it work again, this
- * would be the place to start by adding a per-superblock
- * mutex and fixing all the bugs and performance issues
- * caused by that.
+ * We don't do any per-file locking anymore, it is hard to
+ * review and HPFS is not performance-sensitive anyway.
  */
 static inline void hpfs_lock(struct super_block *s)
 {
+       struct hpfs_sb_info *sbi = hpfs_sb(s);
+       mutex_lock(&sbi->hpfs_mutex);
 }
 
 static inline void hpfs_unlock(struct super_block *s)
 {
+       struct hpfs_sb_info *sbi = hpfs_sb(s);
+       mutex_unlock(&sbi->hpfs_mutex);
+}
+
+static inline void hpfs_lock_assert(struct super_block *s)
+{
+       struct hpfs_sb_info *sbi = hpfs_sb(s);
+       WARN_ON(!mutex_is_locked(&sbi->hpfs_mutex));
 }
index 87f1f787e7677efdd7a17a4e9a8ed2f71c397606..338cd8368451cd081a800aa77440ce237f24b592 100644 (file)
@@ -17,7 +17,6 @@ void hpfs_init_inode(struct inode *i)
        i->i_uid = hpfs_sb(sb)->sb_uid;
        i->i_gid = hpfs_sb(sb)->sb_gid;
        i->i_mode = hpfs_sb(sb)->sb_mode;
-       hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv;
        i->i_size = -1;
        i->i_blocks = -1;
        
@@ -116,8 +115,8 @@ void hpfs_read_inode(struct inode *i)
                i->i_mode |= S_IFDIR;
                i->i_op = &hpfs_dir_iops;
                i->i_fop = &hpfs_dir_ops;
-               hpfs_inode->i_parent_dir = fnode->up;
-               hpfs_inode->i_dno = fnode->u.external[0].disk_secno;
+               hpfs_inode->i_parent_dir = le32_to_cpu(fnode->up);
+               hpfs_inode->i_dno = le32_to_cpu(fnode->u.external[0].disk_secno);
                if (hpfs_sb(sb)->sb_chk >= 2) {
                        struct buffer_head *bh0;
                        if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0);
@@ -133,7 +132,7 @@ void hpfs_read_inode(struct inode *i)
                i->i_op = &hpfs_file_iops;
                i->i_fop = &hpfs_file_ops;
                i->i_nlink = 1;
-               i->i_size = fnode->file_size;
+               i->i_size = le32_to_cpu(fnode->file_size);
                i->i_blocks = ((i->i_size + 511) >> 9) + 1;
                i->i_data.a_ops = &hpfs_aops;
                hpfs_i(i)->mmu_private = i->i_size;
@@ -144,7 +143,7 @@ void hpfs_read_inode(struct inode *i)
 static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
 {
        struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
-       /*if (fnode->acl_size_l || fnode->acl_size_s) {
+       /*if (le32_to_cpu(fnode->acl_size_l) || le16_to_cpu(fnode->acl_size_s)) {
                   Some unknown structures like ACL may be in fnode,
                   we'd better not overwrite them
                hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
@@ -187,9 +186,7 @@ void hpfs_write_inode(struct inode *i)
                kfree(hpfs_inode->i_rddir_off);
                hpfs_inode->i_rddir_off = NULL;
        }
-       mutex_lock(&hpfs_inode->i_parent_mutex);
        if (!i->i_nlink) {
-               mutex_unlock(&hpfs_inode->i_parent_mutex);
                return;
        }
        parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
@@ -200,14 +197,9 @@ void hpfs_write_inode(struct inode *i)
                        hpfs_read_inode(parent);
                        unlock_new_inode(parent);
                }
-               mutex_lock(&hpfs_inode->i_mutex);
                hpfs_write_inode_nolock(i);
-               mutex_unlock(&hpfs_inode->i_mutex);
                iput(parent);
-       } else {
-               mark_inode_dirty(i);
        }
-       mutex_unlock(&hpfs_inode->i_parent_mutex);
 }
 
 void hpfs_write_inode_nolock(struct inode *i)
@@ -226,30 +218,30 @@ void hpfs_write_inode_nolock(struct inode *i)
                }
        } else de = NULL;
        if (S_ISREG(i->i_mode)) {
-               fnode->file_size = i->i_size;
-               if (de) de->file_size = i->i_size;
+               fnode->file_size = cpu_to_le32(i->i_size);
+               if (de) de->file_size = cpu_to_le32(i->i_size);
        } else if (S_ISDIR(i->i_mode)) {
-               fnode->file_size = 0;
-               if (de) de->file_size = 0;
+               fnode->file_size = cpu_to_le32(0);
+               if (de) de->file_size = cpu_to_le32(0);
        }
        hpfs_write_inode_ea(i, fnode);
        if (de) {
-               de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec);
-               de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec);
-               de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec);
+               de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec));
+               de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec));
+               de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec));
                de->read_only = !(i->i_mode & 0222);
-               de->ea_size = hpfs_inode->i_ea_size;
+               de->ea_size = cpu_to_le32(hpfs_inode->i_ea_size);
                hpfs_mark_4buffers_dirty(&qbh);
                hpfs_brelse4(&qbh);
        }
        if (S_ISDIR(i->i_mode)) {
                if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) {
-                       de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec);
-                       de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec);
-                       de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec);
+                       de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec));
+                       de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec));
+                       de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec));
                        de->read_only = !(i->i_mode & 0222);
-                       de->ea_size = /*hpfs_inode->i_ea_size*/0;
-                       de->file_size = 0;
+                       de->ea_size = cpu_to_le32(/*hpfs_inode->i_ea_size*/0);
+                       de->file_size = cpu_to_le32(0);
                        hpfs_mark_4buffers_dirty(&qbh);
                        hpfs_brelse4(&qbh);
                } else
@@ -269,6 +261,10 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
        hpfs_lock(inode->i_sb);
        if (inode->i_ino == hpfs_sb(inode->i_sb)->sb_root)
                goto out_unlock;
+       if ((attr->ia_valid & ATTR_UID) && attr->ia_uid >= 0x10000)
+               goto out_unlock;
+       if ((attr->ia_valid & ATTR_GID) && attr->ia_gid >= 0x10000)
+               goto out_unlock;
        if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
                goto out_unlock;
 
@@ -284,7 +280,6 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        setattr_copy(inode, attr);
-       mark_inode_dirty(inode);
 
        hpfs_write_inode(inode);
 
index 840d033ecee832561f7f9ed91cec78527a62e38f..a790821366a7f045d068fe47df517dc479b0ecce 100644 (file)
@@ -21,7 +21,7 @@ unsigned int *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block,
                hpfs_error(s, "hpfs_map_bitmap called with bad parameter: %08x at %s", bmp_block, id);
                return NULL;
        }
-       sec = hpfs_sb(s)->sb_bmp_dir[bmp_block];
+       sec = le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[bmp_block]);
        if (!sec || sec > hpfs_sb(s)->sb_fs_size-4) {
                hpfs_error(s, "invalid bitmap block pointer %08x -> %08x at %s", bmp_block, sec, id);
                return NULL;
@@ -46,18 +46,18 @@ unsigned char *hpfs_load_code_page(struct super_block *s, secno cps)
        struct code_page_data *cpd;
        struct code_page_directory *cp = hpfs_map_sector(s, cps, &bh, 0);
        if (!cp) return NULL;
-       if (cp->magic != CP_DIR_MAGIC) {
-               printk("HPFS: Code page directory magic doesn't match (magic = %08x)\n", cp->magic);
+       if (le32_to_cpu(cp->magic) != CP_DIR_MAGIC) {
+               printk("HPFS: Code page directory magic doesn't match (magic = %08x)\n", le32_to_cpu(cp->magic));
                brelse(bh);
                return NULL;
        }
-       if (!cp->n_code_pages) {
+       if (!le32_to_cpu(cp->n_code_pages)) {
                printk("HPFS: n_code_pages == 0\n");
                brelse(bh);
                return NULL;
        }
-       cpds = cp->array[0].code_page_data;
-       cpi = cp->array[0].index;
+       cpds = le32_to_cpu(cp->array[0].code_page_data);
+       cpi = le16_to_cpu(cp->array[0].index);
        brelse(bh);
 
        if (cpi >= 3) {
@@ -66,12 +66,12 @@ unsigned char *hpfs_load_code_page(struct super_block *s, secno cps)
        }
        
        if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL;
-       if ((unsigned)cpd->offs[cpi] > 0x178) {
+       if (le16_to_cpu(cpd->offs[cpi]) > 0x178) {
                printk("HPFS: Code page index out of sector\n");
                brelse(bh);
                return NULL;
        }
-       ptr = (unsigned char *)cpd + cpd->offs[cpi] + 6;
+       ptr = (unsigned char *)cpd + le16_to_cpu(cpd->offs[cpi]) + 6;
        if (!(cp_table = kmalloc(256, GFP_KERNEL))) {
                printk("HPFS: out of memory for code page table\n");
                brelse(bh);
@@ -125,7 +125,7 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
                if (hpfs_sb(s)->sb_chk) {
                        struct extended_attribute *ea;
                        struct extended_attribute *ea_end;
-                       if (fnode->magic != FNODE_MAGIC) {
+                       if (le32_to_cpu(fnode->magic) != FNODE_MAGIC) {
                                hpfs_error(s, "bad magic on fnode %08lx",
                                        (unsigned long)ino);
                                goto bail;
@@ -138,7 +138,7 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
                                            (unsigned long)ino);
                                        goto bail;
                                }
-                               if (fnode->btree.first_free !=
+                               if (le16_to_cpu(fnode->btree.first_free) !=
                                    8 + fnode->btree.n_used_nodes * (fnode->btree.internal ? 8 : 12)) {
                                        hpfs_error(s,
                                            "bad first_free pointer in fnode %08lx",
@@ -146,12 +146,12 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
                                        goto bail;
                                }
                        }
-                       if (fnode->ea_size_s && ((signed int)fnode->ea_offs < 0xc4 ||
-                          (signed int)fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200)) {
+                       if (le16_to_cpu(fnode->ea_size_s) && (le16_to_cpu(fnode->ea_offs) < 0xc4 ||
+                          le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200)) {
                                hpfs_error(s,
                                        "bad EA info in fnode %08lx: ea_offs == %04x ea_size_s == %04x",
                                        (unsigned long)ino,
-                                       fnode->ea_offs, fnode->ea_size_s);
+                                       le16_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s));
                                goto bail;
                        }
                        ea = fnode_ea(fnode);
@@ -178,16 +178,20 @@ struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buff
        if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ano, 1, "anode")) return NULL;
        if ((anode = hpfs_map_sector(s, ano, bhp, ANODE_RD_AHEAD)))
                if (hpfs_sb(s)->sb_chk) {
-                       if (anode->magic != ANODE_MAGIC || anode->self != ano) {
+                       if (le32_to_cpu(anode->magic) != ANODE_MAGIC) {
                                hpfs_error(s, "bad magic on anode %08x", ano);
                                goto bail;
                        }
+                       if (le32_to_cpu(anode->self) != ano) {
+                               hpfs_error(s, "self pointer invalid on anode %08x", ano);
+                               goto bail;
+                       }
                        if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes !=
                            (anode->btree.internal ? 60 : 40)) {
                                hpfs_error(s, "bad number of nodes in anode %08x", ano);
                                goto bail;
                        }
-                       if (anode->btree.first_free !=
+                       if (le16_to_cpu(anode->btree.first_free) !=
                            8 + anode->btree.n_used_nodes * (anode->btree.internal ? 8 : 12)) {
                                hpfs_error(s, "bad first_free pointer in anode %08x", ano);
                                goto bail;
@@ -219,26 +223,26 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
                        unsigned p, pp = 0;
                        unsigned char *d = (unsigned char *)dnode;
                        int b = 0;
-                       if (dnode->magic != DNODE_MAGIC) {
+                       if (le32_to_cpu(dnode->magic) != DNODE_MAGIC) {
                                hpfs_error(s, "bad magic on dnode %08x", secno);
                                goto bail;
                        }
-                       if (dnode->self != secno)
-                               hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, dnode->self);
+                       if (le32_to_cpu(dnode->self) != secno)
+                               hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, le32_to_cpu(dnode->self));
                        /* Check dirents - bad dirents would cause infinite
                           loops or shooting to memory */
-                       if (dnode->first_free > 2048/* || dnode->first_free < 84*/) {
-                               hpfs_error(s, "dnode %08x has first_free == %08x", secno, dnode->first_free);
+                       if (le32_to_cpu(dnode->first_free) > 2048) {
+                               hpfs_error(s, "dnode %08x has first_free == %08x", secno, le32_to_cpu(dnode->first_free));
                                goto bail;
                        }
-                       for (p = 20; p < dnode->first_free; p += d[p] + (d[p+1] << 8)) {
+                       for (p = 20; p < le32_to_cpu(dnode->first_free); p += d[p] + (d[p+1] << 8)) {
                                struct hpfs_dirent *de = (struct hpfs_dirent *)((char *)dnode + p);
-                               if (de->length > 292 || (de->length < 32) || (de->length & 3) || p + de->length > 2048) {
+                               if (le16_to_cpu(de->length) > 292 || (le16_to_cpu(de->length) < 32) || (le16_to_cpu(de->length) & 3) || p + le16_to_cpu(de->length) > 2048) {
                                        hpfs_error(s, "bad dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
                                        goto bail;
                                }
-                               if (((31 + de->namelen + de->down*4 + 3) & ~3) != de->length) {
-                                       if (((31 + de->namelen + de->down*4 + 3) & ~3) < de->length && s->s_flags & MS_RDONLY) goto ok;
+                               if (((31 + de->namelen + de->down*4 + 3) & ~3) != le16_to_cpu(de->length)) {
+                                       if (((31 + de->namelen + de->down*4 + 3) & ~3) < le16_to_cpu(de->length) && s->s_flags & MS_RDONLY) goto ok;
                                        hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
                                        goto bail;
                                }
@@ -251,7 +255,7 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
                                pp = p;
                                
                        }
-                       if (p != dnode->first_free) {
+                       if (p != le32_to_cpu(dnode->first_free)) {
                                hpfs_error(s, "size on last dirent does not match first_free; dnode %08x", secno);
                                goto bail;
                        }
@@ -277,7 +281,7 @@ dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino)
        if (!fnode)
                return 0;
 
-       dno = fnode->u.external[0].disk_secno;
+       dno = le32_to_cpu(fnode->u.external[0].disk_secno);
        brelse(bh);
        return dno;
 }
index f24736d7a439218aa238f75df3338c3e3e64744f..9acdf338def0b4d3dc26c59171b9dc337217ec30 100644 (file)
@@ -8,39 +8,6 @@
 
 #include "hpfs_fn.h"
 
-static const char *text_postfix[]={
-".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF",
-".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS",
-".RC", ".TEX", ".TXT", ".Y", ""};
-
-static const char *text_prefix[]={
-"AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ",
-"MAKEFILE", "READ.ME", "README", "TERMCAP", ""};
-
-void hpfs_decide_conv(struct inode *inode, const unsigned char *name, unsigned len)
-{
-       struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
-       int i;
-       if (hpfs_inode->i_conv != CONV_AUTO) return;
-       for (i = 0; *text_postfix[i]; i++) {
-               int l = strlen(text_postfix[i]);
-               if (l <= len)
-                       if (!hpfs_compare_names(inode->i_sb, text_postfix[i], l, name + len - l, l, 0))
-                               goto text;
-       }
-       for (i = 0; *text_prefix[i]; i++) {
-               int l = strlen(text_prefix[i]);
-               if (l <= len)
-                       if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0))
-                               goto text;
-       }
-       hpfs_inode->i_conv = CONV_BINARY;
-       return;
-       text:
-       hpfs_inode->i_conv = CONV_TEXT;
-       return;
-}
-
 static inline int not_allowed_char(unsigned char c)
 {
        return c<' ' || c=='"' || c=='*' || c=='/' || c==':' || c=='<' ||
index d5f8c8a190233dc8cd066b065868aca822989128..1f05839c27a7fca1f24c99dda71adf07bb2930c5 100644 (file)
@@ -29,7 +29,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
        if (!fnode)
                goto bail;
-       dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1);
+       dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0);
        if (!dnode)
                goto bail1;
        memset(&dee, 0, sizeof dee);
@@ -37,8 +37,8 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (!(mode & 0222)) dee.read_only = 1;
        /*dee.archive = 0;*/
        dee.hidden = name[0] == '.';
-       dee.fnode = fno;
-       dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
+       dee.fnode = cpu_to_le32(fno);
+       dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
        result = new_inode(dir->i_sb);
        if (!result)
                goto bail2;
@@ -46,7 +46,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        result->i_ino = fno;
        hpfs_i(result)->i_parent_dir = dir->i_ino;
        hpfs_i(result)->i_dno = dno;
-       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
        result->i_ctime.tv_nsec = 0; 
        result->i_mtime.tv_nsec = 0; 
        result->i_atime.tv_nsec = 0; 
@@ -60,8 +60,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (dee.read_only)
                result->i_mode &= ~0222;
 
-       mutex_lock(&hpfs_i(dir)->i_mutex);
-       r = hpfs_add_dirent(dir, name, len, &dee, 0);
+       r = hpfs_add_dirent(dir, name, len, &dee);
        if (r == 1)
                goto bail3;
        if (r == -1) {
@@ -70,21 +69,21 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        }
        fnode->len = len;
        memcpy(fnode->name, name, len > 15 ? 15 : len);
-       fnode->up = dir->i_ino;
+       fnode->up = cpu_to_le32(dir->i_ino);
        fnode->dirflag = 1;
        fnode->btree.n_free_nodes = 7;
        fnode->btree.n_used_nodes = 1;
-       fnode->btree.first_free = 0x14;
-       fnode->u.external[0].disk_secno = dno;
-       fnode->u.external[0].file_secno = -1;
+       fnode->btree.first_free = cpu_to_le16(0x14);
+       fnode->u.external[0].disk_secno = cpu_to_le32(dno);
+       fnode->u.external[0].file_secno = cpu_to_le32(-1);
        dnode->root_dnode = 1;
-       dnode->up = fno;
+       dnode->up = cpu_to_le32(fno);
        de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0);
-       de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds());
+       de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
        if (!(mode & 0222)) de->read_only = 1;
        de->first = de->directory = 1;
        /*de->hidden = de->system = 0;*/
-       de->fnode = fno;
+       de->fnode = cpu_to_le32(fno);
        mark_buffer_dirty(bh);
        brelse(bh);
        hpfs_mark_4buffers_dirty(&qbh0);
@@ -101,11 +100,9 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                hpfs_write_inode_nolock(result);
        }
        d_instantiate(dentry, result);
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        hpfs_unlock(dir->i_sb);
        return 0;
 bail3:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        iput(result);
 bail2:
        hpfs_brelse4(&qbh0);
@@ -140,8 +137,8 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
        if (!(mode & 0222)) dee.read_only = 1;
        dee.archive = 1;
        dee.hidden = name[0] == '.';
-       dee.fnode = fno;
-       dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
+       dee.fnode = cpu_to_le32(fno);
+       dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
 
        result = new_inode(dir->i_sb);
        if (!result)
@@ -154,9 +151,8 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
        result->i_op = &hpfs_file_iops;
        result->i_fop = &hpfs_file_ops;
        result->i_nlink = 1;
-       hpfs_decide_conv(result, name, len);
        hpfs_i(result)->i_parent_dir = dir->i_ino;
-       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
        result->i_ctime.tv_nsec = 0;
        result->i_mtime.tv_nsec = 0;
        result->i_atime.tv_nsec = 0;
@@ -168,8 +164,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
        result->i_data.a_ops = &hpfs_aops;
        hpfs_i(result)->mmu_private = 0;
 
-       mutex_lock(&hpfs_i(dir)->i_mutex);
-       r = hpfs_add_dirent(dir, name, len, &dee, 0);
+       r = hpfs_add_dirent(dir, name, len, &dee);
        if (r == 1)
                goto bail2;
        if (r == -1) {
@@ -178,7 +173,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
        }
        fnode->len = len;
        memcpy(fnode->name, name, len > 15 ? 15 : len);
-       fnode->up = dir->i_ino;
+       fnode->up = cpu_to_le32(dir->i_ino);
        mark_buffer_dirty(bh);
        brelse(bh);
 
@@ -193,12 +188,10 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
                hpfs_write_inode_nolock(result);
        }
        d_instantiate(dentry, result);
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        hpfs_unlock(dir->i_sb);
        return 0;
 
 bail2:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        iput(result);
 bail1:
        brelse(bh);
@@ -232,8 +225,8 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
        if (!(mode & 0222)) dee.read_only = 1;
        dee.archive = 1;
        dee.hidden = name[0] == '.';
-       dee.fnode = fno;
-       dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
+       dee.fnode = cpu_to_le32(fno);
+       dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
 
        result = new_inode(dir->i_sb);
        if (!result)
@@ -242,7 +235,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
        hpfs_init_inode(result);
        result->i_ino = fno;
        hpfs_i(result)->i_parent_dir = dir->i_ino;
-       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
        result->i_ctime.tv_nsec = 0;
        result->i_mtime.tv_nsec = 0;
        result->i_atime.tv_nsec = 0;
@@ -254,8 +247,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
        result->i_blocks = 1;
        init_special_inode(result, mode, rdev);
 
-       mutex_lock(&hpfs_i(dir)->i_mutex);
-       r = hpfs_add_dirent(dir, name, len, &dee, 0);
+       r = hpfs_add_dirent(dir, name, len, &dee);
        if (r == 1)
                goto bail2;
        if (r == -1) {
@@ -264,19 +256,17 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
        }
        fnode->len = len;
        memcpy(fnode->name, name, len > 15 ? 15 : len);
-       fnode->up = dir->i_ino;
+       fnode->up = cpu_to_le32(dir->i_ino);
        mark_buffer_dirty(bh);
 
        insert_inode_hash(result);
 
        hpfs_write_inode_nolock(result);
        d_instantiate(dentry, result);
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        brelse(bh);
        hpfs_unlock(dir->i_sb);
        return 0;
 bail2:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        iput(result);
 bail1:
        brelse(bh);
@@ -310,8 +300,8 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
        memset(&dee, 0, sizeof dee);
        dee.archive = 1;
        dee.hidden = name[0] == '.';
-       dee.fnode = fno;
-       dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
+       dee.fnode = cpu_to_le32(fno);
+       dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
 
        result = new_inode(dir->i_sb);
        if (!result)
@@ -319,7 +309,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
        result->i_ino = fno;
        hpfs_init_inode(result);
        hpfs_i(result)->i_parent_dir = dir->i_ino;
-       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+       result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
        result->i_ctime.tv_nsec = 0;
        result->i_mtime.tv_nsec = 0;
        result->i_atime.tv_nsec = 0;
@@ -333,8 +323,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
        result->i_op = &page_symlink_inode_operations;
        result->i_data.a_ops = &hpfs_symlink_aops;
 
-       mutex_lock(&hpfs_i(dir)->i_mutex);
-       r = hpfs_add_dirent(dir, name, len, &dee, 0);
+       r = hpfs_add_dirent(dir, name, len, &dee);
        if (r == 1)
                goto bail2;
        if (r == -1) {
@@ -343,7 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
        }
        fnode->len = len;
        memcpy(fnode->name, name, len > 15 ? 15 : len);
-       fnode->up = dir->i_ino;
+       fnode->up = cpu_to_le32(dir->i_ino);
        hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink));
        mark_buffer_dirty(bh);
        brelse(bh);
@@ -352,11 +341,9 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
 
        hpfs_write_inode_nolock(result);
        d_instantiate(dentry, result);
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        hpfs_unlock(dir->i_sb);
        return 0;
 bail2:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
        iput(result);
 bail1:
        brelse(bh);
@@ -374,7 +361,6 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
        struct hpfs_dirent *de;
        struct inode *inode = dentry->d_inode;
        dnode_secno dno;
-       fnode_secno fno;
        int r;
        int rep = 0;
        int err;
@@ -382,8 +368,6 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
        hpfs_lock(dir->i_sb);
        hpfs_adjust_length(name, &len);
 again:
-       mutex_lock(&hpfs_i(inode)->i_parent_mutex);
-       mutex_lock(&hpfs_i(dir)->i_mutex);
        err = -ENOENT;
        de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
        if (!de)
@@ -397,7 +381,6 @@ again:
        if (de->directory)
                goto out1;
 
-       fno = de->fnode;
        r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
        switch (r) {
        case 1:
@@ -410,8 +393,6 @@ again:
                if (rep++)
                        break;
 
-               mutex_unlock(&hpfs_i(dir)->i_mutex);
-               mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
                dentry_unhash(dentry);
                if (!d_unhashed(dentry)) {
                        dput(dentry);
@@ -445,8 +426,6 @@ again:
 out1:
        hpfs_brelse4(&qbh);
 out:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
-       mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
        hpfs_unlock(dir->i_sb);
        return err;
 }
@@ -459,15 +438,12 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
        struct hpfs_dirent *de;
        struct inode *inode = dentry->d_inode;
        dnode_secno dno;
-       fnode_secno fno;
        int n_items = 0;
        int err;
        int r;
 
        hpfs_adjust_length(name, &len);
        hpfs_lock(dir->i_sb);
-       mutex_lock(&hpfs_i(inode)->i_parent_mutex);
-       mutex_lock(&hpfs_i(dir)->i_mutex);
        err = -ENOENT;
        de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
        if (!de)
@@ -486,7 +462,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (n_items)
                goto out1;
 
-       fno = de->fnode;
        r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
        switch (r) {
        case 1:
@@ -505,8 +480,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
 out1:
        hpfs_brelse4(&qbh);
 out:
-       mutex_unlock(&hpfs_i(dir)->i_mutex);
-       mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
        hpfs_unlock(dir->i_sb);
        return err;
 }
@@ -568,12 +541,6 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        hpfs_lock(i->i_sb);
        /* order doesn't matter, due to VFS exclusion */
-       mutex_lock(&hpfs_i(i)->i_parent_mutex);
-       if (new_inode)
-               mutex_lock(&hpfs_i(new_inode)->i_parent_mutex);
-       mutex_lock(&hpfs_i(old_dir)->i_mutex);
-       if (new_dir != old_dir)
-               mutex_lock(&hpfs_i(new_dir)->i_mutex);
        
        /* Erm? Moving over the empty non-busy directory is perfectly legal */
        if (new_inode && S_ISDIR(new_inode->i_mode)) {
@@ -610,9 +577,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        if (new_dir == old_dir) hpfs_brelse4(&qbh);
 
-       hpfs_lock_creation(i->i_sb);
-       if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) {
-               hpfs_unlock_creation(i->i_sb);
+       if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) {
                if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!");
                err = r == 1 ? -ENOSPC : -EFSERROR;
                if (new_dir != old_dir) hpfs_brelse4(&qbh);
@@ -621,20 +586,17 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        
        if (new_dir == old_dir)
                if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
-                       hpfs_unlock_creation(i->i_sb);
                        hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
                        err = -ENOENT;
                        goto end1;
                }
 
        if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) {
-               hpfs_unlock_creation(i->i_sb);
                hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent");
                err = r == 2 ? -ENOSPC : -EFSERROR;
                goto end1;
        }
-       hpfs_unlock_creation(i->i_sb);
-       
+
        end:
        hpfs_i(i)->i_parent_dir = new_dir->i_ino;
        if (S_ISDIR(i->i_mode)) {
@@ -642,22 +604,14 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                drop_nlink(old_dir);
        }
        if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
-               fnode->up = new_dir->i_ino;
+               fnode->up = cpu_to_le32(new_dir->i_ino);
                fnode->len = new_len;
                memcpy(fnode->name, new_name, new_len>15?15:new_len);
                if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len);
                mark_buffer_dirty(bh);
                brelse(bh);
        }
-       hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv;
-       hpfs_decide_conv(i, new_name, new_len);
 end1:
-       if (old_dir != new_dir)
-               mutex_unlock(&hpfs_i(new_dir)->i_mutex);
-       mutex_unlock(&hpfs_i(old_dir)->i_mutex);
-       mutex_unlock(&hpfs_i(i)->i_parent_mutex);
-       if (new_inode)
-               mutex_unlock(&hpfs_i(new_inode)->i_parent_mutex);
        hpfs_unlock(i->i_sb);
        return err;
 }
index c89b40808587925c616c4c20cc5e6ee5b6932aa0..98580a3b5005feea514e961476d9a0686c912979 100644 (file)
 
 /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
 
-static void mark_dirty(struct super_block *s)
+static void mark_dirty(struct super_block *s, int remount)
 {
-       if (hpfs_sb(s)->sb_chkdsk && !(s->s_flags & MS_RDONLY)) {
+       if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) {
                struct buffer_head *bh;
                struct hpfs_spare_block *sb;
                if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
                        sb->dirty = 1;
                        sb->old_wrote = 0;
                        mark_buffer_dirty(bh);
+                       sync_dirty_buffer(bh);
                        brelse(bh);
                }
        }
@@ -40,10 +41,12 @@ static void unmark_dirty(struct super_block *s)
        struct buffer_head *bh;
        struct hpfs_spare_block *sb;
        if (s->s_flags & MS_RDONLY) return;
+       sync_blockdev(s->s_bdev);
        if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
                sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error;
                sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error;
                mark_buffer_dirty(bh);
+               sync_dirty_buffer(bh);
                brelse(bh);
        }
 }
@@ -63,13 +66,13 @@ void hpfs_error(struct super_block *s, const char *fmt, ...)
        if (!hpfs_sb(s)->sb_was_error) {
                if (hpfs_sb(s)->sb_err == 2) {
                        printk("; crashing the system because you wanted it\n");
-                       mark_dirty(s);
+                       mark_dirty(s, 0);
                        panic("HPFS panic");
                } else if (hpfs_sb(s)->sb_err == 1) {
                        if (s->s_flags & MS_RDONLY) printk("; already mounted read-only\n");
                        else {
                                printk("; remounting read-only\n");
-                               mark_dirty(s);
+                               mark_dirty(s, 0);
                                s->s_flags |= MS_RDONLY;
                        }
                } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only\n");
@@ -102,9 +105,12 @@ static void hpfs_put_super(struct super_block *s)
 {
        struct hpfs_sb_info *sbi = hpfs_sb(s);
 
+       hpfs_lock(s);
+       unmark_dirty(s);
+       hpfs_unlock(s);
+
        kfree(sbi->sb_cp_table);
        kfree(sbi->sb_bmp_dir);
-       unmark_dirty(s);
        s->s_fs_info = NULL;
        kfree(sbi);
 }
@@ -129,7 +135,7 @@ static unsigned count_bitmaps(struct super_block *s)
        n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14;
        count = 0;
        for (n = 0; n < n_bands; n++)
-               count += hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_bmp_dir[n]);
+               count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
        return count;
 }
 
@@ -188,8 +194,6 @@ static void init_once(void *foo)
 {
        struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
 
-       mutex_init(&ei->i_mutex);
-       mutex_init(&ei->i_parent_mutex);
        inode_init_once(&ei->vfs_inode);
 }
 
@@ -218,7 +222,6 @@ static void destroy_inodecache(void)
 
 enum {
        Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis,
-       Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
        Opt_check_none, Opt_check_normal, Opt_check_strict,
        Opt_err_cont, Opt_err_ro, Opt_err_panic,
        Opt_eas_no, Opt_eas_ro, Opt_eas_rw,
@@ -233,9 +236,6 @@ static const match_table_t tokens = {
        {Opt_umask, "umask=%o"},
        {Opt_case_lower, "case=lower"},
        {Opt_case_asis, "case=asis"},
-       {Opt_conv_binary, "conv=binary"},
-       {Opt_conv_text, "conv=text"},
-       {Opt_conv_auto, "conv=auto"},
        {Opt_check_none, "check=none"},
        {Opt_check_normal, "check=normal"},
        {Opt_check_strict, "check=strict"},
@@ -253,7 +253,7 @@ static const match_table_t tokens = {
 };
 
 static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
-                     int *lowercase, int *conv, int *eas, int *chk, int *errs,
+                     int *lowercase, int *eas, int *chk, int *errs,
                      int *chkdsk, int *timeshift)
 {
        char *p;
@@ -295,15 +295,6 @@ static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
                case Opt_case_asis:
                        *lowercase = 0;
                        break;
-               case Opt_conv_binary:
-                       *conv = CONV_BINARY;
-                       break;
-               case Opt_conv_text:
-                       *conv = CONV_TEXT;
-                       break;
-               case Opt_conv_auto:
-                       *conv = CONV_AUTO;
-                       break;
                case Opt_check_none:
                        *chk = 0;
                        break;
@@ -370,9 +361,6 @@ HPFS filesystem options:\n\
       umask=xxx         set mode of files that don't have mode specified in eas\n\
       case=lower        lowercase all files\n\
       case=asis         do not lowercase files (default)\n\
-      conv=binary       do not convert CR/LF -> LF (default)\n\
-      conv=auto         convert only files with known text extensions\n\
-      conv=text         convert all files\n\
       check=none        no fs checks - kernel may crash on corrupted filesystem\n\
       check=normal      do some checks - it should not crash (default)\n\
       check=strict      do extra time-consuming checks, used for debugging\n\
@@ -394,7 +382,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
        uid_t uid;
        gid_t gid;
        umode_t umask;
-       int lowercase, conv, eas, chk, errs, chkdsk, timeshift;
+       int lowercase, eas, chk, errs, chkdsk, timeshift;
        int o;
        struct hpfs_sb_info *sbi = hpfs_sb(s);
        char *new_opts = kstrdup(data, GFP_KERNEL);
@@ -405,11 +393,11 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
        lock_super(s);
        uid = sbi->sb_uid; gid = sbi->sb_gid;
        umask = 0777 & ~sbi->sb_mode;
-       lowercase = sbi->sb_lowercase; conv = sbi->sb_conv;
+       lowercase = sbi->sb_lowercase;
        eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk;
        errs = sbi->sb_err; timeshift = sbi->sb_timeshift;
 
-       if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, &conv,
+       if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase,
            &eas, &chk, &errs, &chkdsk, &timeshift))) {
                printk("HPFS: bad mount options.\n");
                goto out_err;
@@ -427,11 +415,11 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 
        sbi->sb_uid = uid; sbi->sb_gid = gid;
        sbi->sb_mode = 0777 & ~umask;
-       sbi->sb_lowercase = lowercase; sbi->sb_conv = conv;
+       sbi->sb_lowercase = lowercase;
        sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk;
        sbi->sb_err = errs; sbi->sb_timeshift = timeshift;
 
-       if (!(*flags & MS_RDONLY)) mark_dirty(s);
+       if (!(*flags & MS_RDONLY)) mark_dirty(s, 1);
 
        replace_mount_options(s, new_opts);
 
@@ -471,7 +459,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        uid_t uid;
        gid_t gid;
        umode_t umask;
-       int lowercase, conv, eas, chk, errs, chkdsk, timeshift;
+       int lowercase, eas, chk, errs, chkdsk, timeshift;
 
        dnode_secno root_dno;
        struct hpfs_dirent *de = NULL;
@@ -479,11 +467,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 
        int o;
 
-       if (num_possible_cpus() > 1) {
-               printk(KERN_ERR "HPFS is not SMP safe\n");
-               return -EINVAL;
-       }
-
        save_mount_options(s, options);
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
@@ -495,20 +478,20 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        sbi->sb_bmp_dir = NULL;
        sbi->sb_cp_table = NULL;
 
-       mutex_init(&sbi->hpfs_creation_de);
+       mutex_init(&sbi->hpfs_mutex);
+       hpfs_lock(s);
 
        uid = current_uid();
        gid = current_gid();
        umask = current_umask();
        lowercase = 0;
-       conv = CONV_BINARY;
        eas = 2;
        chk = 1;
        errs = 1;
        chkdsk = 1;
        timeshift = 0;
 
-       if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &conv,
+       if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase,
            &eas, &chk, &errs, &chkdsk, &timeshift))) {
                printk("HPFS: bad mount options.\n");
                goto bail0;
@@ -526,9 +509,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3;
 
        /* Check magics */
-       if (/*bootblock->magic != BB_MAGIC
-           ||*/ superblock->magic != SB_MAGIC
-           || spareblock->magic != SP_MAGIC) {
+       if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC
+           ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC
+           || le32_to_cpu(spareblock->magic) != SP_MAGIC) {
                if (!silent) printk("HPFS: Bad magic ... probably not HPFS\n");
                goto bail4;
        }
@@ -549,19 +532,18 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        s->s_op = &hpfs_sops;
        s->s_d_op = &hpfs_dentry_operations;
 
-       sbi->sb_root = superblock->root;
-       sbi->sb_fs_size = superblock->n_sectors;
-       sbi->sb_bitmaps = superblock->bitmaps;
-       sbi->sb_dirband_start = superblock->dir_band_start;
-       sbi->sb_dirband_size = superblock->n_dir_band;
-       sbi->sb_dmap = superblock->dir_band_bitmap;
+       sbi->sb_root = le32_to_cpu(superblock->root);
+       sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors);
+       sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps);
+       sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start);
+       sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band);
+       sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap);
        sbi->sb_uid = uid;
        sbi->sb_gid = gid;
        sbi->sb_mode = 0777 & ~umask;
        sbi->sb_n_free = -1;
        sbi->sb_n_free_dnodes = -1;
        sbi->sb_lowercase = lowercase;
-       sbi->sb_conv = conv;
        sbi->sb_eas = eas;
        sbi->sb_chk = chk;
        sbi->sb_chkdsk = chkdsk;
@@ -573,7 +555,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        sbi->sb_max_fwd_alloc = 0xffffff;
        
        /* Load bitmap directory */
-       if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, superblock->bitmaps)))
+       if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps))))
                goto bail4;
        
        /* Check for general fs errors*/
@@ -591,20 +573,20 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
                mark_buffer_dirty(bh2);
        }
 
-       if (spareblock->hotfixes_used || spareblock->n_spares_used) {
+       if (le32_to_cpu(spareblock->hotfixes_used) || le32_to_cpu(spareblock->n_spares_used)) {
                if (errs >= 2) {
                        printk("HPFS: Hotfixes not supported here, try chkdsk\n");
-                       mark_dirty(s);
+                       mark_dirty(s, 0);
                        goto bail4;
                }
                hpfs_error(s, "hotfixes not supported here, try chkdsk");
                if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n");
                else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.\n");
        }
-       if (spareblock->n_dnode_spares != spareblock->n_dnode_spares_free) {
+       if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) {
                if (errs >= 2) {
                        printk("HPFS: Spare dnodes used, try chkdsk\n");
-                       mark_dirty(s);
+                       mark_dirty(s, 0);
                        goto bail4;
                }
                hpfs_error(s, "warning: spare dnodes used, try chkdsk");
@@ -612,26 +594,26 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        }
        if (chk) {
                unsigned a;
-               if (superblock->dir_band_end - superblock->dir_band_start + 1 != superblock->n_dir_band ||
-                   superblock->dir_band_end < superblock->dir_band_start || superblock->n_dir_band > 0x4000) {
+               if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) ||
+                   le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) {
                        hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x",
-                               superblock->dir_band_start, superblock->dir_band_end, superblock->n_dir_band);
+                               le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band));
                        goto bail4;
                }
                a = sbi->sb_dirband_size;
                sbi->sb_dirband_size = 0;
-               if (hpfs_chk_sectors(s, superblock->dir_band_start, superblock->n_dir_band, "dir_band") ||
-                   hpfs_chk_sectors(s, superblock->dir_band_bitmap, 4, "dir_band_bitmap") ||
-                   hpfs_chk_sectors(s, superblock->bitmaps, 4, "bitmaps")) {
-                       mark_dirty(s);
+               if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") ||
+                   hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") ||
+                   hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) {
+                       mark_dirty(s, 0);
                        goto bail4;
                }
                sbi->sb_dirband_size = a;
        } else printk("HPFS: You really don't want any checks? You are crazy...\n");
 
        /* Load code page table */
-       if (spareblock->n_code_pages)
-               if (!(sbi->sb_cp_table = hpfs_load_code_page(s, spareblock->code_page_dir)))
+       if (le32_to_cpu(spareblock->n_code_pages))
+               if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir))))
                        printk("HPFS: Warning: code page support is disabled\n");
 
        brelse(bh2);
@@ -660,13 +642,13 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        if (!de)
                hpfs_error(s, "unable to find root dir");
        else {
-               root->i_atime.tv_sec = local_to_gmt(s, de->read_date);
+               root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date));
                root->i_atime.tv_nsec = 0;
-               root->i_mtime.tv_sec = local_to_gmt(s, de->write_date);
+               root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date));
                root->i_mtime.tv_nsec = 0;
-               root->i_ctime.tv_sec = local_to_gmt(s, de->creation_date);
+               root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date));
                root->i_ctime.tv_nsec = 0;
-               hpfs_i(root)->i_ea_size = de->ea_size;
+               hpfs_i(root)->i_ea_size = le16_to_cpu(de->ea_size);
                hpfs_i(root)->i_parent_dir = root->i_ino;
                if (root->i_size == -1)
                        root->i_size = 2048;
@@ -674,6 +656,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
                        root->i_blocks = 5;
                hpfs_brelse4(&qbh);
        }
+       hpfs_unlock(s);
        return 0;
 
 bail4: brelse(bh2);
@@ -681,6 +664,7 @@ bail3:      brelse(bh1);
 bail2: brelse(bh0);
 bail1:
 bail0:
+       hpfs_unlock(s);
        kfree(sbi->sb_bmp_dir);
        kfree(sbi->sb_cp_table);
        s->s_fs_info = NULL;
index 33435e4b14d24aaad89bfab57da526870bbfa797..ce03a182c771c42e39e90c0f7b3737b897d02215 100644 (file)
@@ -480,10 +480,6 @@ static int logfs_read_sb(struct super_block *sb, int read_only)
                        !read_only)
                return -EIO;
 
-       mutex_init(&super->s_dirop_mutex);
-       mutex_init(&super->s_object_alias_mutex);
-       INIT_LIST_HEAD(&super->s_freeing_list);
-
        ret = logfs_init_rw(sb);
        if (ret)
                return ret;
@@ -601,6 +597,10 @@ static struct dentry *logfs_mount(struct file_system_type *type, int flags,
        if (!super)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&super->s_dirop_mutex);
+       mutex_init(&super->s_object_alias_mutex);
+       INIT_LIST_HEAD(&super->s_freeing_list);
+
        if (!devname)
                err = logfs_get_sb_bdev(super, type, devname);
        else if (strncmp(devname, "mtd", 3))
index e6cd6113872ccd4db1dadfa5deff08f90a45c8a0..54fc993e3027d4dff98dcf4f14ebbb4d817cdb0f 100644 (file)
@@ -697,6 +697,7 @@ static __always_inline void set_root_rcu(struct nameidata *nd)
                do {
                        seq = read_seqcount_begin(&fs->seq);
                        nd->root = fs->root;
+                       nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
                } while (read_seqcount_retry(&fs->seq, seq));
        }
 }
index 7dba2ed03429460f27aba058955208ed5dd929ec..d99bcf59e4c2fd23b2c03d2c9ed7471f7b2b230e 100644 (file)
@@ -1030,18 +1030,6 @@ const struct seq_operations mounts_op = {
        .show   = show_vfsmnt
 };
 
-static int uuid_is_nil(u8 *uuid)
-{
-       int i;
-       u8  *cp = (u8 *)uuid;
-
-       for (i = 0; i < 16; i++) {
-               if (*cp++)
-                       return 0;
-       }
-       return 1;
-}
-
 static int show_mountinfo(struct seq_file *m, void *v)
 {
        struct proc_mounts *p = m->private;
@@ -1085,10 +1073,6 @@ static int show_mountinfo(struct seq_file *m, void *v)
        if (IS_MNT_UNBINDABLE(mnt))
                seq_puts(m, " unbindable");
 
-       if (!uuid_is_nil(mnt->mnt_sb->s_uuid))
-               /* print the uuid */
-               seq_printf(m, " uuid:%pU", mnt->mnt_sb->s_uuid);
-
        /* Filesystem specific data */
        seq_puts(m, " - ");
        show_type(m, sb);
index 89fc160fd5b071af390ee4aea4590e929c43acee..1f063bacd2857caa119f4dce1bf429402b0be909 100644 (file)
@@ -119,7 +119,7 @@ Elong:
 }
 
 #ifdef CONFIG_NFS_V4
-static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode)
+static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
 {
        struct gss_api_mech *mech;
        struct xdr_netobj oid;
@@ -166,7 +166,7 @@ static int nfs_negotiate_security(const struct dentry *parent,
                }
                flavors = page_address(page);
                ret = secinfo(parent->d_inode, &dentry->d_name, flavors);
-               *flavor = nfs_find_best_sec(flavors, dentry->d_inode);
+               *flavor = nfs_find_best_sec(flavors);
                put_page(page);
        }
 
index e1c261ddd65dc591408633469e5e90ec176f476c..c4a69833dd0d5b1abf3223e6e63f2153606ef9c5 100644 (file)
@@ -47,6 +47,7 @@ enum nfs4_client_state {
        NFS4CLNT_LAYOUTRECALL,
        NFS4CLNT_SESSION_RESET,
        NFS4CLNT_RECALL_SLOT,
+       NFS4CLNT_LEASE_CONFIRM,
 };
 
 enum nfs4_session_state {
index 9bf41eab3e4646eb1256c1192c4482fc89c4c61d..69c0f3c5ee7a9c1bfa6374ea3aad7ed7421cf2fa 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
+#include <linux/nfs_mount.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/module.h>
@@ -443,8 +444,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
        if (res->sr_status == 1)
                res->sr_status = NFS_OK;
 
-       /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */
-       if (!res->sr_slot)
+       /* don't increment the sequence number if the task wasn't sent */
+       if (!RPC_WAS_SENT(task))
                goto out;
 
        /* Check the SEQUENCE operation status */
@@ -2185,9 +2186,14 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_lookup_root(server, fhandle, info),
-                               &exception);
+               err = _nfs4_lookup_root(server, fhandle, info);
+               switch (err) {
+               case 0:
+               case -NFS4ERR_WRONGSEC:
+                       break;
+               default:
+                       err = nfs4_handle_exception(server, err, &exception);
+               }
        } while (exception.retry);
        return err;
 }
@@ -2208,25 +2214,47 @@ out:
        return ret;
 }
 
-/*
- * get the file handle for the "/" directory on the server
- */
-static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                              struct nfs_fsinfo *info)
 {
        int i, len, status = 0;
-       rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2];
+       rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
 
-       flav_array[0] = RPC_AUTH_UNIX;
-       len = gss_mech_list_pseudoflavors(&flav_array[1]);
-       flav_array[1+len] = RPC_AUTH_NULL;
-       len += 2;
+       len = gss_mech_list_pseudoflavors(&flav_array[0]);
+       flav_array[len] = RPC_AUTH_NULL;
+       len += 1;
 
        for (i = 0; i < len; i++) {
                status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
-               if (status != -EPERM)
-                       break;
+               if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
+                       continue;
+               break;
        }
+       /*
+        * -EACCESS could mean that the user doesn't have correct permissions
+        * to access the mount.  It could also mean that we tried to mount
+        * with a gss auth flavor, but rpc.gssd isn't running.  Either way,
+        * existing mount programs don't handle -EACCES very well so it should
+        * be mapped to -EPERM instead.
+        */
+       if (status == -EACCES)
+               status = -EPERM;
+       return status;
+}
+
+/*
+ * get the file handle for the "/" directory on the server
+ */
+static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+                             struct nfs_fsinfo *info)
+{
+       int status = nfs4_lookup_root(server, fhandle, info);
+       if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
+               /*
+                * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
+                * by nfs4_map_errors() as this function exits.
+                */
+               status = nfs4_find_root_sec(server, fhandle, info);
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
        if (status == 0)
@@ -3723,21 +3751,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                                sizeof(setclientid.sc_uaddr), "%s.%u.%u",
                                clp->cl_ipaddr, port >> 8, port & 255);
 
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+               status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
                if (status != -NFS4ERR_CLID_INUSE)
                        break;
-               if (signalled())
+               if (loop != 0) {
+                       ++clp->cl_id_uniquifier;
                        break;
-               if (loop++ & 1)
-                       ssleep(clp->cl_lease_time / HZ + 1);
-               else
-                       if (++clp->cl_id_uniquifier == 0)
-                               break;
+               }
+               ++loop;
+               ssleep(clp->cl_lease_time / HZ + 1);
        }
        return status;
 }
 
-static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
+int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                struct nfs4_setclientid_res *arg,
                struct rpc_cred *cred)
 {
@@ -3752,7 +3779,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
        int status;
 
        now = jiffies;
-       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (status == 0) {
                spin_lock(&clp->cl_lock);
                clp->cl_lease_time = fsinfo.lease_time * HZ;
@@ -3762,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
        return status;
 }
 
-int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
-               struct nfs4_setclientid_res *arg,
-               struct rpc_cred *cred)
-{
-       long timeout = 0;
-       int err;
-       do {
-               err = _nfs4_proc_setclientid_confirm(clp, arg, cred);
-               switch (err) {
-                       case 0:
-                               return err;
-                       case -NFS4ERR_RESOURCE:
-                               /* The IBM lawyers misread another document! */
-                       case -NFS4ERR_DELAY:
-                               err = nfs4_delay(clp->cl_rpcclient, &timeout);
-               }
-       } while (err == 0);
-       return err;
-}
-
 struct nfs4_delegreturndata {
        struct nfs4_delegreturnargs args;
        struct nfs4_delegreturnres res;
@@ -4786,7 +4793,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                                init_utsname()->domainname,
                                clp->cl_rpcclient->cl_auth->au_flavor);
 
-       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (!status)
                status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
        dprintk("<-- %s status= %d\n", __func__, status);
@@ -4869,7 +4876,8 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
                .rpc_client = clp->cl_rpcclient,
                .rpc_message = &msg,
                .callback_ops = &nfs4_get_lease_time_ops,
-               .callback_data = &data
+               .callback_data = &data,
+               .flags = RPC_TASK_TIMEOUT,
        };
        int status;
 
@@ -5171,7 +5179,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp)
        nfs4_init_channel_attrs(&args);
        args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
 
-       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0);
+       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 
        if (!status)
                /* Verify the session's negotiated channel_attrs values */
@@ -5194,20 +5202,10 @@ int nfs4_proc_create_session(struct nfs_client *clp)
        int status;
        unsigned *ptr;
        struct nfs4_session *session = clp->cl_session;
-       long timeout = 0;
-       int err;
 
        dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
 
-       do {
-               status = _nfs4_proc_create_session(clp);
-               if (status == -NFS4ERR_DELAY) {
-                       err = nfs4_delay(clp->cl_rpcclient, &timeout);
-                       if (err)
-                               status = err;
-               }
-       } while (status == -NFS4ERR_DELAY);
-
+       status = _nfs4_proc_create_session(clp);
        if (status)
                goto out;
 
@@ -5248,7 +5246,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
        msg.rpc_argp = session;
        msg.rpc_resp = NULL;
        msg.rpc_cred = NULL;
-       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0);
+       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 
        if (status)
                printk(KERN_WARNING
index a6804f704d9d8656868b6492c66232020132fe6d..036f5adc9e1fad417eb13c2b8687e6ea56abb613 100644 (file)
@@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list);
 
 int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
 {
-       struct nfs4_setclientid_res clid;
+       struct nfs4_setclientid_res clid = {
+               .clientid = clp->cl_clientid,
+               .confirm = clp->cl_confirm,
+       };
        unsigned short port;
        int status;
 
+       if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
+               goto do_confirm;
        port = nfs_callback_tcpport;
        if (clp->cl_addr.ss_family == AF_INET6)
                port = nfs_callback_tcpport6;
@@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
        status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
        if (status != 0)
                goto out;
+       clp->cl_clientid = clid.clientid;
+       clp->cl_confirm = clid.confirm;
+       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+do_confirm:
        status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
        if (status != 0)
                goto out;
-       clp->cl_clientid = clid.clientid;
+       clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        nfs4_schedule_state_renewal(clp);
 out:
        return status;
@@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
 {
        int status;
 
+       if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
+               goto do_confirm;
        nfs4_begin_drain_session(clp);
        status = nfs4_proc_exchange_id(clp, cred);
        if (status != 0)
                goto out;
+       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+do_confirm:
        status = nfs4_proc_create_session(clp);
        if (status != 0)
                goto out;
+       clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        nfs41_setup_state_renewal(clp);
        nfs_mark_client_ready(clp, NFS_CS_READY);
 out:
@@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
  */
 static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
 {
-       if (nfs4_has_session(clp)) {
-               switch (status) {
-               case -NFS4ERR_DELAY:
-               case -NFS4ERR_CLID_INUSE:
-               case -EAGAIN:
-                       break;
+       switch (status) {
+       case -NFS4ERR_CLID_INUSE:
+       case -NFS4ERR_STALE_CLIENTID:
+               clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+               break;
+       case -NFS4ERR_DELAY:
+       case -ETIMEDOUT:
+       case -EAGAIN:
+               ssleep(1);
+               break;
 
-               case -EKEYEXPIRED:
-                       nfs4_warn_keyexpired(clp->cl_hostname);
-               case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
-                                        * in nfs4_exchange_id */
-               default:
-                       return;
-               }
+       case -EKEYEXPIRED:
+               nfs4_warn_keyexpired(clp->cl_hostname);
+       case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
+                                * in nfs4_exchange_id */
+       default:
+               return;
        }
        set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
 }
@@ -1607,7 +1624,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
        int status = 0;
 
        /* Ensure exclusive access to NFSv4 state */
-       for(;;) {
+       do {
                if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
                        /* We're going to have to re-establish a clientid */
                        status = nfs4_reclaim_lease(clp);
@@ -1691,7 +1708,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        break;
                if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
                        break;
-       }
+       } while (atomic_read(&clp->cl_count) > 1);
        return;
 out_error:
        printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
index dddfb5795d7b8c67999ebfc819b5cd8021e36cd8..c3ccd2c468344fab9076214fec8d99fc1eee9036 100644 (file)
@@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-       uint32_t attrs[2] = {0, 0};
+       uint32_t attrs[2] = {
+               FATTR4_WORD0_RDATTR_ERROR,
+               FATTR4_WORD1_MOUNTED_ON_FILEID,
+       };
        uint32_t dircount = readdir->count >> 1;
        __be32 *p;
 
        if (readdir->plus) {
                attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
-                       FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
+                       FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
                attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
                        FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
                        FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
                        FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
                dircount >>= 1;
        }
-       attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
-       attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
-       /* Switch to mounted_on_fileid if the server supports it */
-       if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
-               attrs[0] &= ~FATTR4_WORD0_FILEID;
-       else
-               attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+       /* Use mounted_on_fileid only if the server supports it */
+       if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
+               attrs[0] |= FATTR4_WORD0_FILEID;
 
        p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
        *p++ = cpu_to_be32(OP_READDIR);
@@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
                        goto out_overflow;
                xdr_decode_hyper(p, fileid);
                bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
-               ret = NFS_ATTR_FATTR_FILEID;
+               ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
        return ret;
@@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 {
        int status;
        umode_t fmode = 0;
-       uint64_t fileid;
        uint32_t type;
 
        status = decode_attr_type(xdr, bitmap, &type);
@@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
+       status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
        if (status < 0)
                goto xdr_error;
-       if (status != 0 && !(fattr->valid & status)) {
-               fattr->fileid = fileid;
-               fattr->valid |= status;
-       }
+       fattr->valid |= status;
 
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
@@ -4838,17 +4833,21 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
        struct nfs4_secinfo_flavor *sec_flavor;
        int status;
        __be32 *p;
-       int i;
+       int i, num_flavors;
 
        status = decode_op_hdr(xdr, OP_SECINFO);
+       if (status)
+               goto out;
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       res->flavors->num_flavors = be32_to_cpup(p);
 
-       for (i = 0; i < res->flavors->num_flavors; i++) {
+       res->flavors->num_flavors = 0;
+       num_flavors = be32_to_cpup(p);
+
+       for (i = 0; i < num_flavors; i++) {
                sec_flavor = &res->flavors->flavors[i];
-               if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE)
+               if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE)
                        break;
 
                p = xdr_inline_decode(xdr, 4);
@@ -4857,13 +4856,15 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
                sec_flavor->flavor = be32_to_cpup(p);
 
                if (sec_flavor->flavor == RPC_AUTH_GSS) {
-                       if (decode_secinfo_gss(xdr, sec_flavor))
-                               break;
+                       status = decode_secinfo_gss(xdr, sec_flavor);
+                       if (status)
+                               goto out;
                }
+               res->flavors->num_flavors++;
        }
 
-       return 0;
-
+out:
+       return status;
 out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
@@ -6408,7 +6409,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
                                        entry->server, 1) < 0)
                goto out_overflow;
-       if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
+       if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
+               entry->ino = entry->fattr->mounted_on_fileid;
+       else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
                entry->ino = entry->fattr->fileid;
 
        entry->d_type = DT_UNKNOWN;
index d9ab97269ce6e83c2fbd652fddebb789f761a271..ff681ab65d31f54654521e560b9cd5780db8318f 100644 (file)
@@ -1004,6 +1004,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 {
        struct nfs_inode *nfsi = NFS_I(wdata->inode);
        loff_t end_pos = wdata->args.offset + wdata->res.count;
+       bool mark_as_dirty = false;
 
        spin_lock(&nfsi->vfs_inode.i_lock);
        if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
@@ -1011,13 +1012,18 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
                get_lseg(wdata->lseg);
                wdata->lseg->pls_lc_cred =
                        get_rpccred(wdata->args.context->state->owner->so_cred);
-               mark_inode_dirty_sync(wdata->inode);
+               mark_as_dirty = true;
                dprintk("%s: Set layoutcommit for inode %lu ",
                        __func__, wdata->inode->i_ino);
        }
        if (end_pos > wdata->lseg->pls_end_pos)
                wdata->lseg->pls_end_pos = end_pos;
        spin_unlock(&nfsi->vfs_inode.i_lock);
+
+       /* if pnfs_layoutcommit_inode() runs between inode locks, the next one
+        * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
+       if (mark_as_dirty)
+               mark_inode_dirty_sync(wdata->inode);
 }
 EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
 
index 2b8e9a5e366a67a7eb6ce228d14df6ed69f51fb9..e288f06d3fa7de5f6d06e134b1854230aa9b7611 100644 (file)
@@ -1004,6 +1004,7 @@ static int nfs_parse_security_flavors(char *value,
                return 0;
        }
 
+       mnt->flags |= NFS_MOUNT_SECFLAVOUR;
        mnt->auth_flavor_len = 1;
        return 1;
 }
@@ -1976,6 +1977,15 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
        if (error < 0)
                goto out;
 
+       /*
+        * noac is a special case. It implies -o sync, but that's not
+        * necessarily reflected in the mtab options. do_remount_sb
+        * will clear MS_SYNCHRONOUS if -o sync wasn't specified in the
+        * remount options, so we have to explicitly reset it.
+        */
+       if (data->flags & NFS_MOUNT_NOAC)
+               *flags |= MS_SYNCHRONOUS;
+
        /* compare new mount options with old ones */
        error = nfs_compare_remount_data(nfss, data);
 out:
@@ -2235,8 +2245,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs_fill_super(s, data);
-               nfs_fscache_get_super_cookie(
-                       s, data ? data->fscache_uniq : NULL, NULL);
+               nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
        }
 
        mntroot = nfs_get_root(s, mntfh, dev_name);
index af0c6279a4a7c131cd9c2a80e0764ba8ea50a6c9..3bd5d7e80f6cc60fbd7f46a68c8abd60c126eb54 100644 (file)
@@ -542,11 +542,15 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u
        if (!nfs_need_commit(nfsi))
                return 0;
 
+       spin_lock(&inode->i_lock);
        ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
        if (ret > 0)
                nfsi->ncommit -= ret;
+       spin_unlock(&inode->i_lock);
+
        if (nfs_need_commit(NFS_I(inode)))
                __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+
        return ret;
 }
 #else
@@ -676,7 +680,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
        req = nfs_setup_write_request(ctx, page, offset, count);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       nfs_mark_request_dirty(req);
        /* Update file length */
        nfs_grow_file(page, offset, count);
        nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
@@ -1414,8 +1417,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
                                 task->tk_pid, task->tk_status);
 
        /* Call the NFS version-specific code */
-       if (NFS_PROTO(data->inode)->commit_done(task, data) != 0)
-               return;
+       NFS_PROTO(data->inode)->commit_done(task, data);
 }
 
 void nfs_commit_release_pages(struct nfs_write_data *data)
@@ -1483,9 +1485,7 @@ int nfs_commit_inode(struct inode *inode, int how)
        res = nfs_commit_set_lock(NFS_I(inode), may_wait);
        if (res <= 0)
                goto out_mark_dirty;
-       spin_lock(&inode->i_lock);
        res = nfs_scan_commit(inode, &head, 0, 0);
-       spin_unlock(&inode->i_lock);
        if (res) {
                int error;
 
index aa309aa93fe81be66e5e33c4d404ebec4b815f86..4cf04e11c66ca39c80dc6b54b6854842de246826 100644 (file)
@@ -258,6 +258,7 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)
        if (atomic_dec_and_test(&fp->fi_delegees)) {
                vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
                fp->fi_lease = NULL;
+               fput(fp->fi_deleg_file);
                fp->fi_deleg_file = NULL;
        }
 }
@@ -402,8 +403,8 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
        if (stp->st_access_bmap) {
                oflag = nfs4_access_bmap_to_omode(stp);
                nfs4_file_put_access(stp->st_file, oflag);
-               put_nfs4_file(stp->st_file);
        }
+       put_nfs4_file(stp->st_file);
        kmem_cache_free(stateid_slab, stp);
 }
 
index 2e1cebde90df4c69baa21635e959f9d81c9809f1..129f3c9f62d589f44b947fccd04c8f745cdfb485 100644 (file)
@@ -1363,7 +1363,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
                goto out;
        if (!(iap->ia_valid & ATTR_MODE))
                iap->ia_mode = 0;
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
        if (err)
                goto out;
 
@@ -1385,6 +1385,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (IS_ERR(dchild))
                goto out_nfserr;
 
+       /* If file doesn't exist, check for permissions to create one */
+       if (!dchild->d_inode) {
+               err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+               if (err)
+                       goto out;
+       }
+
        err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
        if (err)
                goto out;
index b68f87a8392462933d3ed32e47d52aa8fe0c77ce..938387a10d5d7c2caa65ee5faeb1649d5fbc578d 100644 (file)
@@ -1019,7 +1019,7 @@ struct ocfs2_xattr_entry {
        __le16  xe_name_offset;  /* byte offset from the 1st entry in the
                                    local xattr storage(inode, xattr block or
                                    xattr bucket). */
-       __u8    xe_name_len;     /* xattr name len, does't include prefix. */
+       __u8    xe_name_len;     /* xattr name len, doesn't include prefix. */
        __u8    xe_type;         /* the low 7 bits indicate the name prefix
                                  * type and the highest bit indicates whether
                                  * the EA is stored in the local storage. */
index ac0ccb5026a2d107eb5e5e38c84e4bdfe51682ed..19d6750d1d6ce3b5571e463ee2fb2d768985d644 100644 (file)
@@ -348,6 +348,12 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
                goto fail;
        }
 
+       /* Check that sizeof_partition_entry has the correct value */
+       if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
+               pr_debug("GUID Partitition Entry Size check failed.\n");
+               goto fail;
+       }
+
        if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
                goto fail;
 
index b10e3540d5b711e3077d44b9ad1a5b44f210c19a..ce4f624404255f899e1b10262abf3b862aec6be4 100644 (file)
@@ -1299,6 +1299,11 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
 
        BUG_ON (!data || !frags);
 
+       if (size < 2 * VBLK_SIZE_HEAD) {
+               ldm_error("Value of size is to small.");
+               return false;
+       }
+
        group = get_unaligned_be32(data + 0x08);
        rec   = get_unaligned_be16(data + 0x0C);
        num   = get_unaligned_be16(data + 0x0E);
@@ -1306,6 +1311,10 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
                ldm_error ("A VBLK claims to have %d parts.", num);
                return false;
        }
+       if (rec >= num) {
+               ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
+               return false;
+       }
 
        list_for_each (item, frags) {
                f = list_entry (item, struct frag, list);
@@ -1334,10 +1343,9 @@ found:
 
        f->map |= (1 << rec);
 
-       if (num > 0) {
-               data += VBLK_SIZE_HEAD;
-               size -= VBLK_SIZE_HEAD;
-       }
+       data += VBLK_SIZE_HEAD;
+       size -= VBLK_SIZE_HEAD;
+
        memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
 
        return true;
index dd6628d3ba42e136b4e0f35165798899633332a6..dfa532730e55788a7459095ca9c788dbb58d6af9 100644 (file)
@@ -3124,11 +3124,16 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi
 /* for the /proc/ directory itself, after non-process stuff has been done */
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
-       struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode);
+       unsigned int nr;
+       struct task_struct *reaper;
        struct tgid_iter iter;
        struct pid_namespace *ns;
 
+       if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET)
+               goto out_no_task;
+       nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+
+       reaper = get_proc_task(filp->f_path.dentry->d_inode);
        if (!reaper)
                goto out_no_task;
 
index 2e7addfd9803559ca03a2527aaab161006e3b482..318d8654989bf70479321fb8599b0dcf9ac29365 100644 (file)
@@ -214,7 +214,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
        int flags = vma->vm_flags;
        unsigned long ino = 0;
        unsigned long long pgoff = 0;
-       unsigned long start;
+       unsigned long start, end;
        dev_t dev = 0;
        int len;
 
@@ -227,13 +227,15 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
 
        /* We don't show the stack guard page in /proc/maps */
        start = vma->vm_start;
-       if (vma->vm_flags & VM_GROWSDOWN)
-               if (!vma_stack_continue(vma->vm_prev, vma->vm_start))
-                       start += PAGE_SIZE;
+       if (stack_guard_page_start(vma, start))
+               start += PAGE_SIZE;
+       end = vma->vm_end;
+       if (stack_guard_page_end(vma, end))
+               end -= PAGE_SIZE;
 
        seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
                        start,
-                       vma->vm_end,
+                       end,
                        flags & VM_READ ? 'r' : '-',
                        flags & VM_WRITE ? 'w' : '-',
                        flags & VM_EXEC ? 'x' : '-',
index 9eead2c796b7f5a77d242e0e7eda702f16ec297a..fbb0b478a346fbc77c854696c5e0e508760125ad 100644 (file)
@@ -112,6 +112,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
                SetPageDirty(page);
 
                unlock_page(page);
+               put_page(page);
        }
 
        return 0;
index 919f0de29d8f378cee69bb3c035d53eea6ddb312..e6493cac193d60d92c6e3e72d743d03f46a5796d 100644 (file)
 #ifndef __UBIFS_DEBUG_H__
 #define __UBIFS_DEBUG_H__
 
+/* Checking helper functions */
+typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
+                                struct ubifs_zbranch *zbr, void *priv);
+typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+                                 struct ubifs_znode *znode, void *priv);
+
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
 /**
@@ -270,11 +276,6 @@ void dbg_dump_tnc(struct ubifs_info *c);
 void dbg_dump_index(struct ubifs_info *c);
 void dbg_dump_lpt_lebs(const struct ubifs_info *c);
 
-/* Checking helper functions */
-typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
-                                struct ubifs_zbranch *zbr, void *priv);
-typedef int (*dbg_znode_callback)(struct ubifs_info *c,
-                                 struct ubifs_znode *znode, void *priv);
 int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
                   dbg_znode_callback znode_cb, void *priv);
 
@@ -295,7 +296,6 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
 int dbg_check_filesystem(struct ubifs_info *c);
 void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
                    int add_pos);
-int dbg_check_lprops(struct ubifs_info *c);
 int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
                        int row, int col);
 int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
@@ -401,58 +401,94 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
 #define DBGKEY(key)  ((char *)(key))
 #define DBGKEY1(key) ((char *)(key))
 
-#define ubifs_debugging_init(c)                0
-#define ubifs_debugging_exit(c)                ({})
-
-#define dbg_ntype(type)                        ""
-#define dbg_cstate(cmt_state)                  ""
-#define dbg_jhead(jhead)                       ""
-#define dbg_get_key_dump(c, key)               ({})
-#define dbg_dump_inode(c, inode)               ({})
-#define dbg_dump_node(c, node)                 ({})
-#define dbg_dump_lpt_node(c, node, lnum, offs) ({})
-#define dbg_dump_budget_req(req)               ({})
-#define dbg_dump_lstats(lst)                   ({})
-#define dbg_dump_budg(c)                       ({})
-#define dbg_dump_lprop(c, lp)                  ({})
-#define dbg_dump_lprops(c)                     ({})
-#define dbg_dump_lpt_info(c)                   ({})
-#define dbg_dump_leb(c, lnum)                  ({})
-#define dbg_dump_znode(c, znode)               ({})
-#define dbg_dump_heap(c, heap, cat)            ({})
-#define dbg_dump_pnode(c, pnode, parent, iip)  ({})
-#define dbg_dump_tnc(c)                        ({})
-#define dbg_dump_index(c)                      ({})
-#define dbg_dump_lpt_lebs(c)                   ({})
-
-#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
-#define dbg_old_index_check_init(c, zroot)         0
-#define dbg_save_space_info(c)                     ({})
-#define dbg_check_space_info(c)                    0
-#define dbg_check_old_index(c, zroot)              0
-#define dbg_check_cats(c)                          0
-#define dbg_check_ltab(c)                          0
-#define dbg_chk_lpt_free_spc(c)                    0
-#define dbg_chk_lpt_sz(c, action, len)             0
-#define dbg_check_synced_i_size(inode)             0
-#define dbg_check_dir_size(c, dir)                 0
-#define dbg_check_tnc(c, x)                        0
-#define dbg_check_idx_size(c, idx_size)            0
-#define dbg_check_filesystem(c)                    0
-#define dbg_check_heap(c, heap, cat, add_pos)      ({})
-#define dbg_check_lprops(c)                        0
-#define dbg_check_lpt_nodes(c, cnode, row, col)    0
-#define dbg_check_inode_size(c, inode, size)       0
-#define dbg_check_data_nodes_order(c, head)        0
-#define dbg_check_nondata_nodes_order(c, head)     0
-#define dbg_force_in_the_gaps_enabled              0
-#define dbg_force_in_the_gaps()                    0
-#define dbg_failure_mode                           0
-
-#define dbg_debugfs_init()                         0
-#define dbg_debugfs_exit()
-#define dbg_debugfs_init_fs(c)                     0
-#define dbg_debugfs_exit_fs(c)                     0
+static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
+static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
+static inline const char *dbg_ntype(int type)                     { return ""; }
+static inline const char *dbg_cstate(int cmt_state)               { return ""; }
+static inline const char *dbg_jhead(int jhead)                    { return ""; }
+static inline const char *
+dbg_get_key_dump(const struct ubifs_info *c,
+                const union ubifs_key *key)                      { return ""; }
+static inline void dbg_dump_inode(const struct ubifs_info *c,
+                                 const struct inode *inode)      { return; }
+static inline void dbg_dump_node(const struct ubifs_info *c,
+                                const void *node)                { return; }
+static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
+                                    void *node, int lnum,
+                                    int offs)                    { return; }
+static inline void
+dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
+static inline void
+dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
+static inline void dbg_dump_budg(struct ubifs_info *c)            { return; }
+static inline void dbg_dump_lprop(const struct ubifs_info *c,
+                                 const struct ubifs_lprops *lp)  { return; }
+static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
+static inline void dbg_dump_lpt_info(struct ubifs_info *c)        { return; }
+static inline void dbg_dump_leb(const struct ubifs_info *c,
+                               int lnum)                         { return; }
+static inline void
+dbg_dump_znode(const struct ubifs_info *c,
+              const struct ubifs_znode *znode)                   { return; }
+static inline void dbg_dump_heap(struct ubifs_info *c,
+                                struct ubifs_lpt_heap *heap,
+                                int cat)                         { return; }
+static inline void dbg_dump_pnode(struct ubifs_info *c,
+                                 struct ubifs_pnode *pnode,
+                                 struct ubifs_nnode *parent,
+                                 int iip)                        { return; }
+static inline void dbg_dump_tnc(struct ubifs_info *c)             { return; }
+static inline void dbg_dump_index(struct ubifs_info *c)           { return; }
+static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c)  { return; }
+
+static inline int dbg_walk_index(struct ubifs_info *c,
+                                dbg_leaf_callback leaf_cb,
+                                dbg_znode_callback znode_cb,
+                                void *priv)                      { return 0; }
+static inline void dbg_save_space_info(struct ubifs_info *c)      { return; }
+static inline int dbg_check_space_info(struct ubifs_info *c)      { return 0; }
+static inline int dbg_check_lprops(struct ubifs_info *c)          { return 0; }
+static inline int
+dbg_old_index_check_init(struct ubifs_info *c,
+                        struct ubifs_zbranch *zroot)             { return 0; }
+static inline int
+dbg_check_old_index(struct ubifs_info *c,
+                   struct ubifs_zbranch *zroot)                  { return 0; }
+static inline int dbg_check_cats(struct ubifs_info *c)            { return 0; }
+static inline int dbg_check_ltab(struct ubifs_info *c)            { return 0; }
+static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)      { return 0; }
+static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
+                                int action, int len)             { return 0; }
+static inline int dbg_check_synced_i_size(struct inode *inode)    { return 0; }
+static inline int dbg_check_dir_size(struct ubifs_info *c,
+                                    const struct inode *dir)     { return 0; }
+static inline int dbg_check_tnc(struct ubifs_info *c, int extra)  { return 0; }
+static inline int dbg_check_idx_size(struct ubifs_info *c,
+                                    long long idx_size)          { return 0; }
+static inline int dbg_check_filesystem(struct ubifs_info *c)      { return 0; }
+static inline void dbg_check_heap(struct ubifs_info *c,
+                                 struct ubifs_lpt_heap *heap,
+                                 int cat, int add_pos)           { return; }
+static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
+       struct ubifs_cnode *cnode, int row, int col)              { return 0; }
+static inline int dbg_check_inode_size(struct ubifs_info *c,
+                                      const struct inode *inode,
+                                      loff_t size)               { return 0; }
+static inline int
+dbg_check_data_nodes_order(struct ubifs_info *c,
+                          struct list_head *head)                { return 0; }
+static inline int
+dbg_check_nondata_nodes_order(struct ubifs_info *c,
+                             struct list_head *head)             { return 0; }
+
+static inline int dbg_force_in_the_gaps(void)                     { return 0; }
+#define dbg_force_in_the_gaps_enabled 0
+#define dbg_failure_mode              0
+
+static inline int dbg_debugfs_init(void)                          { return 0; }
+static inline void dbg_debugfs_exit(void)                         { return; }
+static inline int dbg_debugfs_init_fs(struct ubifs_info *c)       { return 0; }
+static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)       { return 0; }
 
 #endif /* !CONFIG_UBIFS_FS_DEBUG */
 #endif /* !__UBIFS_DEBUG_H__ */
index 28be1e6a65e8c1af71fc754cb3ecf7dd6eaf2ca2..b286db79c686597bb593208ff577905d2663f7bf 100644 (file)
@@ -1312,6 +1312,9 @@ int ubifs_fsync(struct file *file, int datasync)
 
        dbg_gen("syncing inode %lu", inode->i_ino);
 
+       if (inode->i_sb->s_flags & MS_RDONLY)
+               return 0;
+
        /*
         * VFS has already synchronized dirty pages for this inode. Synchronize
         * the inode unless this is a 'datasync()' call.
index 4d0cb1241460fbc2eacd709188293d5782b1dd3b..40fa780ebea7d6280cc83f30ca4db9b0a0052b98 100644 (file)
@@ -174,26 +174,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
        spin_unlock(&c->buds_lock);
 }
 
-/**
- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
- * @c: UBIFS file-system description object
- */
-void ubifs_create_buds_lists(struct ubifs_info *c)
-{
-       struct rb_node *p;
-
-       spin_lock(&c->buds_lock);
-       p = rb_first(&c->buds);
-       while (p) {
-               struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
-               struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
-
-               list_add_tail(&bud->list, &jhead->buds_list);
-               p = rb_next(p);
-       }
-       spin_unlock(&c->buds_lock);
-}
-
 /**
  * ubifs_add_bud_to_log - add a new bud to the log.
  * @c: UBIFS file-system description object
index 936f2cbfe6b672437aec08219ad017f0fc6f3074..3dbad6fbd1eba528661e458ae56e97c03c43b609 100644 (file)
@@ -317,6 +317,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
                        goto out_free;
                }
                memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
+
+               /*
+                * We had to recover the master node, which means there was an
+                * unclean reboot. However, it is possible that the master node
+                * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
+                * E.g., consider the following chain of events:
+                *
+                * 1. UBIFS was cleanly unmounted, so the master node is clean
+                * 2. UBIFS is being mounted R/W and starts changing the master
+                *    node in the first (%UBIFS_MST_LNUM). A power cut happens,
+                *    so this LEB ends up with some amount of garbage at the
+                *    end.
+                * 3. UBIFS is being mounted R/O. We reach this place and
+                *    recover the master node from the second LEB
+                *    (%UBIFS_MST_LNUM + 1). But we cannot update the media
+                *    because we are being mounted R/O. We have to defer the
+                *    operation.
+                * 4. However, this master node (@c->mst_node) is marked as
+                *    clean (since the step 1). And if we just return, the
+                *    mount code will be confused and won't recover the master
+                *    node when it is re-mounter R/W later.
+                *
+                *    Thus, to force the recovery by marking the master node as
+                *    dirty.
+                */
+               c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
        } else {
                /* Write the recovered master node */
                c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
index eed0fcff8d731710dc7723d25b1adb10ecbe6805..d3d6d365bfc11345d49e3a6bbdc33dd97c476ea9 100644 (file)
@@ -59,6 +59,7 @@ enum {
  * @new_size: truncation new size
  * @free: amount of free space in a bud
  * @dirty: amount of dirty space in a bud from padding and deletion nodes
+ * @jhead: journal head number of the bud
  *
  * UBIFS journal replay must compare node sequence numbers, which means it must
  * build a tree of node information to insert into the TNC.
@@ -80,6 +81,7 @@ struct replay_entry {
                struct {
                        int free;
                        int dirty;
+                       int jhead;
                };
        };
 };
@@ -159,6 +161,11 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
                err = PTR_ERR(lp);
                goto out;
        }
+
+       /* Make sure the journal head points to the latest bud */
+       err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum,
+                                    c->leb_size - r->free, UBI_SHORTTERM);
+
 out:
        ubifs_release_lprops(c);
        return err;
@@ -627,10 +634,6 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
        ubifs_assert(sleb->endpt - offs >= used);
        ubifs_assert(sleb->endpt % c->min_io_size == 0);
 
-       if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount)
-               err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
-                                            sleb->endpt, UBI_SHORTTERM);
-
        *dirty = sleb->endpt - offs - used;
        *free = c->leb_size - sleb->endpt;
 
@@ -653,12 +656,14 @@ out_dump:
  * @sqnum: sequence number
  * @free: amount of free space in bud
  * @dirty: amount of dirty space from padding and deletion nodes
+ * @jhead: journal head number for the bud
  *
  * This function inserts a reference node to the replay tree and returns zero
  * in case of success or a negative error code in case of failure.
  */
 static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
-                          unsigned long long sqnum, int free, int dirty)
+                          unsigned long long sqnum, int free, int dirty,
+                          int jhead)
 {
        struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
        struct replay_entry *r;
@@ -688,6 +693,7 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
        r->flags = REPLAY_REF;
        r->free = free;
        r->dirty = dirty;
+       r->jhead = jhead;
 
        rb_link_node(&r->rb, parent, p);
        rb_insert_color(&r->rb, &c->replay_tree);
@@ -712,7 +718,7 @@ static int replay_buds(struct ubifs_info *c)
                if (err)
                        return err;
                err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
-                                     free, dirty);
+                                     free, dirty, b->bud->jhead);
                if (err)
                        return err;
        }
index c75f6133206cf5edfbf88d1162a81d5001953cb1..04ad07f4fcc3da11b05e868442ed6f3bc7ad7729 100644 (file)
@@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c)
                goto out_free;
        }
 
+       err = alloc_wbufs(c);
+       if (err)
+               goto out_cbuf;
+
        sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
        if (!c->ro_mount) {
-               err = alloc_wbufs(c);
-               if (err)
-                       goto out_cbuf;
-
                /* Create background thread */
                c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
                if (IS_ERR(c->bgt)) {
@@ -1631,12 +1631,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        if (err)
                goto out;
 
-       err = alloc_wbufs(c);
-       if (err)
-               goto out;
-
-       ubifs_create_buds_lists(c);
-
        /* Create background thread */
        c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
        if (IS_ERR(c->bgt)) {
@@ -1671,14 +1665,25 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        if (err)
                goto out;
 
+       dbg_gen("re-mounted read-write");
+       c->remounting_rw = 0;
+
        if (c->need_recovery) {
                c->need_recovery = 0;
                ubifs_msg("deferred recovery completed");
+       } else {
+               /*
+                * Do not run the debugging space check if the were doing
+                * recovery, because when we saved the information we had the
+                * file-system in a state where the TNC and lprops has been
+                * modified in memory, but all the I/O operations (including a
+                * commit) were deferred. So the file-system was in
+                * "non-committed" state. Now the file-system is in committed
+                * state, and of course the amount of free space will change
+                * because, for example, the old index size was imprecise.
+                */
+               err = dbg_check_space_info(c);
        }
-
-       dbg_gen("re-mounted read-write");
-       c->remounting_rw = 0;
-       err = dbg_check_space_info(c);
        mutex_unlock(&c->umount_mutex);
        return err;
 
@@ -1733,7 +1738,6 @@ static void ubifs_remount_ro(struct ubifs_info *c)
        if (err)
                ubifs_ro_mode(c, err);
 
-       free_wbufs(c);
        vfree(c->orph_buf);
        c->orph_buf = NULL;
        kfree(c->write_reserve_buf);
@@ -1761,10 +1765,12 @@ static void ubifs_put_super(struct super_block *sb)
         * of the media. For example, there will be dirty inodes if we failed
         * to write them back because of I/O errors.
         */
-       ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
-       ubifs_assert(c->budg_idx_growth == 0);
-       ubifs_assert(c->budg_dd_growth == 0);
-       ubifs_assert(c->budg_data_growth == 0);
+       if (!c->ro_error) {
+               ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
+               ubifs_assert(c->budg_idx_growth == 0);
+               ubifs_assert(c->budg_dd_growth == 0);
+               ubifs_assert(c->budg_data_growth == 0);
+       }
 
        /*
         * The 'c->umount_lock' prevents races between UBIFS memory shrinker
index a19acdb81cd1270c174711c851b17013edb9ca80..f1ef94974dea12f10beceff4a12899851ba7aeab 100644 (file)
@@ -666,7 +666,7 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz
        handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
        if (!handler)
                return -EOPNOTSUPP;
-       return handler->set(dentry, name, value, size, 0, handler->flags);
+       return handler->set(dentry, name, value, size, flags, handler->flags);
 }
 
 /*
index 3ca795609113c259483099d0bbdaae9815b2cc0e..9f76cceb678d8aec6db86a53863c7c6fc0f36c19 100644 (file)
@@ -34,8 +34,10 @@ __xfs_printk(
        const struct xfs_mount  *mp,
        struct va_format        *vaf)
 {
-       if (mp && mp->m_fsname)
+       if (mp && mp->m_fsname) {
                printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf);
+               return;
+       }
        printk("%sXFS: %pV\n", level, vaf);
 }
 
index f22e7fe4b6dbf25815580ad3625fd09f5aed3946..ade09d7b427100da6057cb04c7e43d484c84ac25 100644 (file)
@@ -118,6 +118,7 @@ int drm_fb_helper_setcolreg(unsigned regno,
                            unsigned transp,
                            struct fb_info *info);
 
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper);
 void drm_fb_helper_restore(void);
 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
                            uint32_t fb_width, uint32_t fb_height);
index c2f93a8ae2e14b414bc6976c811f92406f7c4557..564b14aa7e165e70e45d741f1f2b88dd26992a65 100644 (file)
@@ -86,7 +86,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
 }
 #define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \
                                                &(mm)->head_node.node_list, \
-                                               node_list);
+                                               node_list)
 #define drm_mm_for_each_scanned_node_reverse(entry, n, mm) \
        for (entry = (mm)->prev_scanned_node, \
                next = entry ? list_entry(entry->node_list.next, \
index 816e30cbd9689ac59fbea5d92ca06c16d1558384..f04b2a3b0f49b7117cb74163af0997a7a6fd4742 100644 (file)
        {0x1002, 0x6719, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x671c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x671d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x671f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6721, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6722, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6729, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6739, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x673e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6741, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x689b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x689d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x689e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x68ba, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x68bf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 3bce1a4fc305b48f35667183f21b32f9a325fead..787f7b6fd62237683eb5dad3ecbd77958128f3f1 100644 (file)
@@ -909,6 +909,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_WANT_CMASK         0x08 /* get access to CMASK on r300 */
 #define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */
 #define RADEON_INFO_NUM_BACKENDS       0x0a /* DB/backends for r600+ - need for OQ */
+#define RADEON_INFO_NUM_TILE_PIPES     0x0b /* tile pipes for r600+ */
+#define RADEON_INFO_FUSION_GART_WORKING        0x0c /* fusion writes to GTT were broken before this */
 
 struct drm_radeon_info {
        uint32_t                request;
index e612575a259683c2429cd2d1b46a1cc9671d8141..b4326bfa684f24c3ad147de3cb7d63a9f066da80 100644 (file)
@@ -23,11 +23,11 @@ static inline void bit_spin_lock(int bitnum, unsigned long *addr)
        preempt_disable();
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
        while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
-               while (test_bit(bitnum, addr)) {
-                       preempt_enable();
+               preempt_enable();
+               do {
                        cpu_relax();
-                       preempt_disable();
-               }
+               } while (test_bit(bitnum, addr));
+               preempt_disable();
        }
 #endif
        __acquire(bitlock);
index 32176cc8e715e450a40e7ba24d39010603cf75f3..2ad95fa1d130f8c8f5cfd68e5fe7a0108aec31d9 100644 (file)
@@ -388,20 +388,19 @@ struct request_queue
 #define        QUEUE_FLAG_SYNCFULL     3       /* read queue has been filled */
 #define QUEUE_FLAG_ASYNCFULL   4       /* write queue has been filled */
 #define QUEUE_FLAG_DEAD                5       /* queue being torn down */
-#define QUEUE_FLAG_REENTER     6       /* Re-entrancy avoidance */
-#define QUEUE_FLAG_ELVSWITCH   7       /* don't use elevator, just do FIFO */
-#define QUEUE_FLAG_BIDI                8       /* queue supports bidi requests */
-#define QUEUE_FLAG_NOMERGES     9      /* disable merge attempts */
-#define QUEUE_FLAG_SAME_COMP   10      /* force complete on same CPU */
-#define QUEUE_FLAG_FAIL_IO     11      /* fake timeout */
-#define QUEUE_FLAG_STACKABLE   12      /* supports request stacking */
-#define QUEUE_FLAG_NONROT      13      /* non-rotational device (SSD) */
+#define QUEUE_FLAG_ELVSWITCH   6       /* don't use elevator, just do FIFO */
+#define QUEUE_FLAG_BIDI                7       /* queue supports bidi requests */
+#define QUEUE_FLAG_NOMERGES     8      /* disable merge attempts */
+#define QUEUE_FLAG_SAME_COMP   9       /* force complete on same CPU */
+#define QUEUE_FLAG_FAIL_IO     10      /* fake timeout */
+#define QUEUE_FLAG_STACKABLE   11      /* supports request stacking */
+#define QUEUE_FLAG_NONROT      12      /* non-rotational device (SSD) */
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
-#define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
-#define QUEUE_FLAG_DISCARD     16      /* supports DISCARD */
-#define QUEUE_FLAG_NOXMERGES   17      /* No extended merges */
-#define QUEUE_FLAG_ADD_RANDOM  18      /* Contributes to random pool */
-#define QUEUE_FLAG_SECDISCARD  19      /* supports SECDISCARD */
+#define QUEUE_FLAG_IO_STAT     13      /* do IO stats */
+#define QUEUE_FLAG_DISCARD     14      /* supports DISCARD */
+#define QUEUE_FLAG_NOXMERGES   15      /* No extended merges */
+#define QUEUE_FLAG_ADD_RANDOM  16      /* Contributes to random pool */
+#define QUEUE_FLAG_SECDISCARD  17      /* supports SECDISCARD */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_STACKABLE)    |       \
@@ -697,8 +696,9 @@ extern void blk_start_queue(struct request_queue *q);
 extern void blk_stop_queue(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
-extern void __blk_run_queue(struct request_queue *q, bool force_kblockd);
+extern void __blk_run_queue(struct request_queue *q);
 extern void blk_run_queue(struct request_queue *);
+extern void blk_run_queue_async(struct request_queue *q);
 extern int blk_rq_map_user(struct request_queue *, struct request *,
                           struct rq_map_data *, void __user *, unsigned long,
                           gfp_t);
@@ -857,26 +857,39 @@ extern void blk_put_queue(struct request_queue *);
 struct blk_plug {
        unsigned long magic;
        struct list_head list;
+       struct list_head cb_list;
        unsigned int should_sort;
 };
+struct blk_plug_cb {
+       struct list_head list;
+       void (*callback)(struct blk_plug_cb *);
+};
 
 extern void blk_start_plug(struct blk_plug *);
 extern void blk_finish_plug(struct blk_plug *);
-extern void __blk_flush_plug(struct task_struct *, struct blk_plug *);
+extern void blk_flush_plug_list(struct blk_plug *, bool);
 
 static inline void blk_flush_plug(struct task_struct *tsk)
 {
        struct blk_plug *plug = tsk->plug;
 
-       if (unlikely(plug))
-               __blk_flush_plug(tsk, plug);
+       if (plug)
+               blk_flush_plug_list(plug, false);
+}
+
+static inline void blk_schedule_flush_plug(struct task_struct *tsk)
+{
+       struct blk_plug *plug = tsk->plug;
+
+       if (plug)
+               blk_flush_plug_list(plug, true);
 }
 
 static inline bool blk_needs_flush_plug(struct task_struct *tsk)
 {
        struct blk_plug *plug = tsk->plug;
 
-       return plug && !list_empty(&plug->list);
+       return plug && (!list_empty(&plug->list) || !list_empty(&plug->cb_list));
 }
 
 /*
@@ -1314,6 +1327,11 @@ static inline void blk_flush_plug(struct task_struct *task)
 {
 }
 
+static inline void blk_schedule_flush_plug(struct task_struct *task)
+{
+}
+
+
 static inline bool blk_needs_flush_plug(struct task_struct *tsk)
 {
        return false;
index f2afed4fa9454776c79611d52755121dff749342..19d90a55541d99c37ea6d6c78040b9979dc38116 100644 (file)
@@ -197,7 +197,7 @@ struct dentry_operations {
       * typically using d_splice_alias. */
 
 #define DCACHE_REFERENCED      0x0008  /* Recently used, don't discard. */
-#define DCACHE_UNHASHED                0x0010  
+#define DCACHE_RCUACCESS       0x0010  /* Entry has ever been RCU-visible */
 #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020
      /* Parent inode is watched by inotify */
 
@@ -384,7 +384,7 @@ extern struct dentry *dget_parent(struct dentry *dentry);
  
 static inline int d_unhashed(struct dentry *dentry)
 {
-       return (dentry->d_flags & DCACHE_UNHASHED);
+       return hlist_bl_unhashed(&dentry->d_hash);
 }
 
 static inline int d_unlinked(struct dentry *dentry)
index e2768834f39775f4baeae6e5e9316b64184a823c..32a4423710f51e54045413415a53b6b8cd0afd56 100644 (file)
@@ -197,7 +197,6 @@ struct dm_target {
 struct dm_target_callbacks {
        struct list_head list;
        int (*congested_fn) (struct dm_target_callbacks *, int);
-       void (*unplug_fn)(struct dm_target_callbacks *);
 };
 
 int dm_register_target(struct target_type *t);
index 70e4efabe0fb6983ed9524f4ade4e5d91e2ce2d0..ebeb2f3ad068db1ec6d8cee92a1bcfb6cd097630 100644 (file)
@@ -61,7 +61,7 @@ struct flex_array {
 struct flex_array *flex_array_alloc(int element_size, unsigned int total,
                gfp_t flags);
 int flex_array_prealloc(struct flex_array *fa, unsigned int start,
-               unsigned int end, gfp_t flags);
+               unsigned int nr_elements, gfp_t flags);
 void flex_array_free(struct flex_array *fa);
 void flex_array_free_parts(struct flex_array *fa);
 int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
index 22b32af1b5ec3d1aa81ddebbc2de1ace29c17cc6..b5a550a39a70ddd0a119479ce4a528892c6a7aa9 100644 (file)
@@ -37,6 +37,7 @@ struct trace_entry {
        unsigned char           flags;
        unsigned char           preempt_count;
        int                     pid;
+       int                     padding;
 };
 
 #define FTRACE_MAX_EVENT                                               \
index df29c8fde36be8b7b9e0e13771d8ad4bb1fd6444..8847c8c29791c8c078dedaf0db9ff6dce85faa23 100644 (file)
@@ -117,7 +117,7 @@ static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
                                         unsigned long end,
                                         long adjust_next)
 {
-       if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
+       if (!vma->anon_vma || vma->vm_ops)
                return;
        __vma_adjust_trans_huge(vma, start, end, adjust_next);
 }
index f3a7794a18c4d6de24065f797baf4ba97c34694b..771d6d85667d68a17c24c452979f8d37cc628082 100644 (file)
@@ -167,6 +167,7 @@ struct input_keymap_entry {
 #define SYN_REPORT             0
 #define SYN_CONFIG             1
 #define SYN_MT_REPORT          2
+#define SYN_DROPPED            3
 
 /*
  * Keys and buttons
@@ -553,8 +554,8 @@ struct input_keymap_entry {
 #define KEY_DVD                        0x185   /* Media Select DVD */
 #define KEY_AUX                        0x186
 #define KEY_MP3                        0x187
-#define KEY_AUDIO              0x188
-#define KEY_VIDEO              0x189
+#define KEY_AUDIO              0x188   /* AL Audio Browser */
+#define KEY_VIDEO              0x189   /* AL Movie Browser */
 #define KEY_DIRECTORY          0x18a
 #define KEY_LIST               0x18b
 #define KEY_MEMO               0x18c   /* Media Select Messages */
@@ -603,8 +604,9 @@ struct input_keymap_entry {
 #define KEY_FRAMEFORWARD       0x1b5
 #define KEY_CONTEXT_MENU       0x1b6   /* GenDesc - system context menu */
 #define KEY_MEDIA_REPEAT       0x1b7   /* Consumer - transport control */
-#define KEY_10CHANNELSUP        0x1b8   /* 10 channels up (10+) */
-#define KEY_10CHANNELSDOWN      0x1b9   /* 10 channels down (10-) */
+#define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
+#define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
+#define KEY_IMAGES             0x1ba   /* AL Image Browser */
 
 #define KEY_DEL_EOL            0x1c0
 #define KEY_DEL_EOS            0x1c1
index b3ac06a4435d1114fde8fad1bbd548874641915b..318bb82325a6fa59e4b3d9a13a17a99152dc5674 100644 (file)
@@ -48,6 +48,12 @@ static inline void input_mt_slot(struct input_dev *dev, int slot)
        input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
 }
 
+static inline bool input_is_mt_axis(int axis)
+{
+       return axis == ABS_MT_SLOT ||
+               (axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST);
+}
+
 void input_mt_report_slot_state(struct input_dev *dev,
                                unsigned int tool_type, bool active);
 
index 7f675aa81d877795b12e48c78a13f6ae144af606..04f32a3eb26b85dd9ea0b0e786f282c0c799f30d 100644 (file)
@@ -137,8 +137,6 @@ enum {
        ATA_DFLAG_ACPI_PENDING  = (1 << 5), /* ACPI resume action pending */
        ATA_DFLAG_ACPI_FAILED   = (1 << 6), /* ACPI on devcfg has failed */
        ATA_DFLAG_AN            = (1 << 7), /* AN configured */
-       ATA_DFLAG_HIPM          = (1 << 8), /* device supports HIPM */
-       ATA_DFLAG_DIPM          = (1 << 9), /* device supports DIPM */
        ATA_DFLAG_DMADIR        = (1 << 10), /* device requires DMADIR */
        ATA_DFLAG_CFG_MASK      = (1 << 12) - 1,
 
@@ -198,6 +196,7 @@ enum {
                                              * management */
        ATA_FLAG_SW_ACTIVITY    = (1 << 22), /* driver supports sw activity
                                              * led */
+       ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
index 5bad17d1acdec6d386f6bf3d236c6900abb15ce8..31f9d75adc5bfaf4489d94473500cc01f74b2973 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_LIST_BL_H
 
 #include <linux/list.h>
+#include <linux/bit_spinlock.h>
 
 /*
  * Special version of lists, where head of the list has a lock in the lowest
@@ -114,6 +115,16 @@ static inline void hlist_bl_del_init(struct hlist_bl_node *n)
        }
 }
 
+static inline void hlist_bl_lock(struct hlist_bl_head *b)
+{
+       bit_spin_lock(0, (unsigned long *)b);
+}
+
+static inline void hlist_bl_unlock(struct hlist_bl_head *b)
+{
+       __bit_spin_unlock(0, (unsigned long *)b);
+}
+
 /**
  * hlist_bl_for_each_entry     - iterate over list of given type
  * @tpos:      the type * to use as a loop cursor.
index 5a5ce7055839b607ed688ba4c19c595b4686f875..5e9840f509804df5e49224a12bbbd079177ee4f6 100644 (file)
@@ -216,7 +216,7 @@ static inline void mem_cgroup_del_lru_list(struct page *page, int lru)
        return ;
 }
 
-static inline inline void mem_cgroup_rotate_reclaimable_page(struct page *page)
+static inline void mem_cgroup_rotate_reclaimable_page(struct page *page)
 {
        return ;
 }
index ad1b19aa6508eb58af14a64535dcdcd05d454eb9..aef23309a742334d9f3fb33d3f3b5af38b7f024d 100644 (file)
@@ -86,16 +86,25 @@ extern int mfd_clone_cell(const char *cell, const char **clones,
  */
 static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
 {
-       return pdev->dev.platform_data;
+       return pdev->mfd_cell;
 }
 
 /*
  * Given a platform device that's been created by mfd_add_devices(), fetch
  * the .mfd_data entry from the mfd_cell that created it.
+ * Otherwise just return the platform_data pointer.
+ * This maintains compatibility with platform drivers whose devices aren't
+ * created by the mfd layer, and expect platform_data to contain what would've
+ * otherwise been in mfd_data.
  */
 static inline void *mfd_get_data(struct platform_device *pdev)
 {
-       return mfd_get_cell(pdev)->mfd_data;
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+
+       if (cell)
+               return cell->mfd_data;
+       else
+               return pdev->dev.platform_data;
 }
 
 extern int mfd_add_devices(struct device *parent, int id,
index afe4db49402d142036761855cd9c9b6714bfec8d..632d1567a1b676f4c74dfeec798951081fed108c 100644 (file)
@@ -81,7 +81,9 @@ struct wm831x_touch_pdata {
        int rpu;               /** Pen down sensitivity resistor divider */
        int pressure;          /** Report pressure (boolean) */
        unsigned int data_irq; /** Touch data ready IRQ */
+       int data_irqf;         /** IRQ flags for data ready IRQ */
        unsigned int pd_irq;   /** Touch pendown detect IRQ */
+       int pd_irqf;           /** IRQ flags for pen down IRQ */
 };
 
 enum wm831x_watchdog_action {
index 466b1c777aff09033d449b92f6244bd701ff52f9..d12f8d635a8159b8ce54a144dbf9eda1d90e29d8 100644 (file)
@@ -32,6 +32,10 @@ struct wm8994_ldo_pdata {
 #define WM8994_EQ_REGS  20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_COEFF_REGS  48
+#define WM8958_MBC_COMBINED_REGS 56
+#define WM8958_VSS_HPF_REGS 2
+#define WM8958_VSS_REGS 148
+#define WM8958_ENH_EQ_REGS 32
 
 /**
  * DRC configurations are specified with a label and a set of register
@@ -71,6 +75,42 @@ struct wm8958_mbc_cfg {
        const char *name;
        u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
        u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+
+       /* Coefficient layout when using MBC+VSS firmware */
+       u16 combined_regs[WM8958_MBC_COMBINED_REGS];
+};
+
+/**
+ * VSS HPF configurations are specified with a label and two values to
+ * write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_hpf_cfg {
+       const char *name;
+       u16 regs[WM8958_VSS_HPF_REGS];
+};
+
+/**
+ * VSS configurations are specified with a label and array of values
+ * to write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_cfg {
+       const char *name;
+       u16 regs[WM8958_VSS_REGS];
+};
+
+/**
+ * Enhanced EQ configurations are specified with a label and array of
+ * values to write.  Configurations are expected to be generated using
+ * the multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_enh_eq_cfg {
+       const char *name;
+       u16 regs[WM8958_ENH_EQ_REGS];
 };
 
 struct wm8994_pdata {
@@ -95,6 +135,15 @@ struct wm8994_pdata {
        int num_mbc_cfgs;
        struct wm8958_mbc_cfg *mbc_cfgs;
 
+       int num_vss_cfgs;
+       struct wm8958_vss_cfg *vss_cfgs;
+
+       int num_vss_hpf_cfgs;
+       struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
+
+       int num_enh_eq_cfgs;
+       struct wm8958_enh_eq_cfg *enh_eq_cfgs;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
index 692dbae6ffa76997058792ad3441f551bf303473..6507dde38b16602a1b819492088f6ce5ea8fba40 100644 (file)
@@ -137,7 +137,8 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_RandomReadHint(v)           ((v)->vm_flags & VM_RAND_READ)
 
 /*
- * special vmas that are non-mergable, non-mlock()able
+ * Special vmas that are non-mergable, non-mlock()able.
+ * Note: mm/huge_memory.c VM_NO_THP depends on this definition.
  */
 #define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_RESERVED | VM_PFNMAP)
 
@@ -1010,11 +1011,33 @@ int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
 
 /* Is the vma a continuation of the stack vma above it? */
-static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr)
+static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
 {
        return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN);
 }
 
+static inline int stack_guard_page_start(struct vm_area_struct *vma,
+                                            unsigned long addr)
+{
+       return (vma->vm_flags & VM_GROWSDOWN) &&
+               (vma->vm_start == addr) &&
+               !vma_growsdown(vma->vm_prev, addr);
+}
+
+/* Is the vma a continuation of the stack vma below it? */
+static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr)
+{
+       return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP);
+}
+
+static inline int stack_guard_page_end(struct vm_area_struct *vma,
+                                          unsigned long addr)
+{
+       return (vma->vm_flags & VM_GROWSUP) &&
+               (vma->vm_end == addr) &&
+               !vma_growsup(vma->vm_next, addr);
+}
+
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
                unsigned long new_addr, unsigned long len);
index bcb793ec7374f61d2552cca43f573bdd1f100ece..eb792cb6d745a9bdc0069eba1139e1f20d33e5d6 100644 (file)
@@ -183,7 +183,6 @@ struct mmc_host {
        struct work_struct      clk_gate_work; /* delayed clock gate */
        unsigned int            clk_old;        /* old clock value cache */
        spinlock_t              clk_lock;       /* lock for clk fields */
-       struct mutex            clk_gate_mutex; /* mutex for clock gating */
 #endif
 
        /* host specific block data */
index 216cea5db0aafbba934a9d55541c09788e10dbef..87694ca86914e379a098096fdd6989df71732a8f 100644 (file)
@@ -47,6 +47,7 @@ struct nfs_client {
 
 #ifdef CONFIG_NFS_V4
        u64                     cl_clientid;    /* constant */
+       nfs4_verifier           cl_confirm;     /* Clientid verifier */
        unsigned long           cl_state;
 
        spinlock_t              cl_lock;
index 78b101e487eac78113ea001974d7e50ebf6b6e8b..890dce2426392d632ae439e15764169276ab3611 100644 (file)
@@ -50,6 +50,7 @@ struct nfs_fattr {
        } du;
        struct nfs_fsid         fsid;
        __u64                   fileid;
+       __u64                   mounted_on_fileid;
        struct timespec         atime;
        struct timespec         mtime;
        struct timespec         ctime;
@@ -83,6 +84,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_PRECHANGE       (1U << 18)
 #define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
 #define NFS_ATTR_FATTR_MOUNTPOINT      (1U << 20)      /* Treat as mountpoint */
+#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID               (1U << 21)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
                | NFS_ATTR_FATTR_MODE \
index 4e2c9150a78525859455ffb1e06551d4b3781b33..8abe8d78c4bfad95d409b8ef74e19d9e6fad11d0 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82840_HB   0x1a21
 #define PCI_DEVICE_ID_INTEL_82845_HB   0x1a30
 #define PCI_DEVICE_ID_INTEL_IOAT       0x1a38
-#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN        0x1c41
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0     0x1d40
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1     0x1d41
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN   0x2310
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX   0x231f
-#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS     0x2330
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1  0x2411
 #define PCI_DEVICE_ID_INTEL_82801AA_3  0x2413
 #define PCI_DEVICE_ID_INTEL_ICH10_5    0x3a60
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN      0x3b00
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX      0x3b1f
-#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_21    0x65f5
index 3a5c4449fd36050f667ee13553924bdf44d9a3f8..8b97308e65df3ccf094d79af23266e2da5fc73af 100644 (file)
@@ -948,7 +948,7 @@ do {                                                                        \
        irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
 # endif
 # define irqsafe_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)    \
-       __pcpu_double_call_return_int(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2))
+       __pcpu_double_call_return_bool(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2))
 #endif
 
 #endif /* __LINUX_PERCPU_H */
index 31afb7ecbe1f12b2bc97f9d251ef9fff9df785bf..cdced84261d79d125a8d6031c76638b72d259c20 100644 (file)
@@ -117,7 +117,7 @@ extern struct pid *find_vpid(int nr);
  */
 extern struct pid *find_get_pid(int nr);
 extern struct pid *find_ge_pid(int nr, struct pid_namespace *);
-int next_pidmap(struct pid_namespace *pid_ns, int last);
+int next_pidmap(struct pid_namespace *pid_ns, unsigned int last);
 
 extern struct pid *alloc_pid(struct pid_namespace *ns);
 extern void free_pid(struct pid *pid);
index d96db98257086cb51341af56d6f9db8615e0d462..744942c95fec478ff9b0e687e9496b9ff76a84bd 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 
+struct mfd_cell;
+
 struct platform_device {
        const char      * name;
        int             id;
@@ -23,6 +25,9 @@ struct platform_device {
 
        const struct platform_device_id *id_entry;
 
+       /* MFD cell pointer */
+       struct mfd_cell *mfd_cell;
+
        /* arch specific additions */
        struct pdev_archdata    archdata;
 };
index 369e19d3750ba9ac4365cf8e778d61f6a9e239a5..7f1183dcd119e0e25dfd959827364e30f7ee291c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/posix-timers.h>
+#include <linux/rwsem.h>
 
 struct posix_clock;
 
@@ -104,7 +105,7 @@ struct posix_clock_operations {
  * @ops:     Functional interface to the clock
  * @cdev:    Character device instance for this clock
  * @kref:    Reference count.
- * @mutex:   Protects the 'zombie' field from concurrent access.
+ * @rwsem:   Protects the 'zombie' field from concurrent access.
  * @zombie:  If 'zombie' is true, then the hardware has disappeared.
  * @release: A function to free the structure when the reference count reaches
  *           zero. May be NULL if structure is statically allocated.
@@ -117,7 +118,7 @@ struct posix_clock {
        struct posix_clock_operations ops;
        struct cdev cdev;
        struct kref kref;
-       struct mutex mutex;
+       struct rw_semaphore rwsem;
        bool zombie;
        void (*release)(struct posix_clock *clk);
 };
index a1147e5dd245e8d7d262598b3c920ceb796efd00..9178d5cc0b0143a0e81336e6dea09e1cbedab86e 100644 (file)
@@ -189,6 +189,10 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
                child->ptrace = current->ptrace;
                __ptrace_link(child, current->parent);
        }
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       atomic_set(&child->ptrace_bp_refcnt, 1);
+#endif
 }
 
 /**
@@ -350,6 +354,13 @@ extern int task_current_syscall(struct task_struct *target, long *callno,
                                unsigned long args[6], unsigned int maxargs,
                                unsigned long *sp, unsigned long *pc);
 
-#endif
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+extern int ptrace_get_breakpoints(struct task_struct *tsk);
+extern void ptrace_put_breakpoints(struct task_struct *tsk);
+#else
+static inline void ptrace_put_breakpoints(struct task_struct *tsk) { }
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+#endif /* __KERNEL */
 
 #endif
index 4e37a7cfa726f07dd65114c37a5ae3bc798904ab..4d50611112ba118e69df87888a81f764aee4c346 100644 (file)
@@ -396,7 +396,7 @@ union rio_pw_msg {
 };
 
 /* Architecture and hardware-specific functions */
-extern void rio_register_mport(struct rio_mport *);
+extern int rio_register_mport(struct rio_mport *);
 extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int);
 extern void rio_close_inb_mbox(struct rio_mport *, int);
 extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int);
index 7410d3365e2ad5472f28631e90397501d3fed6a4..0cee0152aca9a17c07658612f85ceec9f9986101 100644 (file)
@@ -35,6 +35,7 @@
 #define RIO_DID_IDTCPS6Q               0x035f
 #define RIO_DID_IDTCPS10Q              0x035e
 #define RIO_DID_IDTCPS1848             0x0374
+#define RIO_DID_IDTCPS1432             0x0375
 #define RIO_DID_IDTCPS1616             0x0379
 #define RIO_DID_IDTVPS1616             0x0377
 #define RIO_DID_IDTSPS1616             0x0378
index 2ca7e8a78060f24057d1c2290e05289393092e27..877ece45426f6c3eb0fa3850f0c93db0ee84468a 100644 (file)
@@ -228,6 +228,8 @@ extern int rtc_read_alarm(struct rtc_device *rtc,
                        struct rtc_wkalrm *alrm);
 extern int rtc_set_alarm(struct rtc_device *rtc,
                                struct rtc_wkalrm *alrm);
+extern int rtc_initialize_alarm(struct rtc_device *rtc,
+                               struct rtc_wkalrm *alrm);
 extern void rtc_update_irq(struct rtc_device *rtc,
                        unsigned long num, unsigned long events);
 
index 4ec2c027e92c969e04154677fbfe5813772aa422..781abd13767302cce2ba08db01a211e3178de0d9 100644 (file)
@@ -1254,6 +1254,9 @@ struct task_struct {
 #endif
 
        struct mm_struct *mm, *active_mm;
+#ifdef CONFIG_COMPAT_BRK
+       unsigned brk_randomized:1;
+#endif
 #if defined(SPLIT_RSS_COUNTING)
        struct task_rss_stat    rss_stat;
 #endif
@@ -1534,6 +1537,9 @@ struct task_struct {
                unsigned long memsw_nr_pages; /* uncharged mem+swap usage */
        } memcg_batch;
 #endif
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       atomic_t ptrace_bp_refcnt;
+#endif
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
index ca02f1716736906c0bc98227a6b11be7975af2ff..8ce59ef3e5afbec48b903e5f8d3cd4318096f709 100644 (file)
@@ -1456,7 +1456,7 @@ struct security_operations {
                             struct inode *new_dir, struct dentry *new_dentry);
        int (*inode_readlink) (struct dentry *dentry);
        int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
-       int (*inode_permission) (struct inode *inode, int mask);
+       int (*inode_permission) (struct inode *inode, int mask, unsigned flags);
        int (*inode_setattr)    (struct dentry *dentry, struct iattr *attr);
        int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
        int (*inode_setxattr) (struct dentry *dentry, const char *name,
index d81db8012c63b658158228469f89643426d9e435..f73c482ec9c6080cc5201c047546928c53c8b723 100644 (file)
@@ -127,13 +127,16 @@ struct rpc_task_setup {
 #define RPC_TASK_KILLED                0x0100          /* task was killed */
 #define RPC_TASK_SOFT          0x0200          /* Use soft timeouts */
 #define RPC_TASK_SOFTCONN      0x0400          /* Fail if can't connect */
+#define RPC_TASK_SENT          0x0800          /* message was sent */
+#define RPC_TASK_TIMEOUT       0x1000          /* fail with ETIMEDOUT on timeout */
 
 #define RPC_IS_ASYNC(t)                ((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SWAPPER(t)      ((t)->tk_flags & RPC_TASK_SWAPPER)
 #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
 #define RPC_ASSASSINATED(t)    ((t)->tk_flags & RPC_TASK_KILLED)
-#define RPC_IS_SOFT(t)         ((t)->tk_flags & RPC_TASK_SOFT)
+#define RPC_IS_SOFT(t)         ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT))
 #define RPC_IS_SOFTCONN(t)     ((t)->tk_flags & RPC_TASK_SOFTCONN)
+#define RPC_WAS_SENT(t)                ((t)->tk_flags & RPC_TASK_SENT)
 
 #define RPC_TASK_RUNNING       0
 #define RPC_TASK_QUEUED                1
index 5a89e3612875b017760d365c99113a5e76c0d61f..083ffea7ba183de0251224928c67077a0c17d79f 100644 (file)
@@ -249,6 +249,8 @@ extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern int hibernate(void);
 extern bool system_entering_hibernation(void);
 #else /* CONFIG_HIBERNATION */
+static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
@@ -297,14 +299,7 @@ static inline bool pm_wakeup_pending(void) { return false; }
 
 extern struct mutex pm_mutex;
 
-#ifndef CONFIG_HIBERNATION
-static inline void register_nosave_region(unsigned long b, unsigned long e)
-{
-}
-static inline void register_nosave_region_late(unsigned long b, unsigned long e)
-{
-}
-
+#ifndef CONFIG_HIBERNATE_CALLBACKS
 static inline void lock_system_sleep(void) {}
 static inline void unlock_system_sleep(void) {}
 
index 3c7329b8ea0e466a11fef6a176570138de116424..605b0aa8d852f63d4d0c7a3cf18add1f518e2acd 100644 (file)
@@ -68,6 +68,7 @@ struct usbnet {
 #              define EVENT_RX_PAUSED  5
 #              define EVENT_DEV_WAKING 6
 #              define EVENT_DEV_ASLEEP 7
+#              define EVENT_DEV_OPEN   8
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -103,8 +104,8 @@ struct driver_info {
  * Indicates to usbnet, that USB driver accumulates multiple IP packets.
  * Affects statistic (counters) and short packet handling.
  */
-#define FLAG_MULTI_PACKET      0x1000
-#define FLAG_RX_ASSEMBLE       0x2000  /* rx packets may span >1 frames */
+#define FLAG_MULTI_PACKET      0x2000
+#define FLAG_RX_ASSEMBLE       0x4000  /* rx packets may span >1 frames */
 
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
index 7054a7a8065ec20689853e85f784efda5b857e27..de5c159210251ffae3deed5ad984be239221aca9 100644 (file)
@@ -47,7 +47,7 @@ enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
        V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
 
-       /* YUV (including grey) - next is 0x2013 */
+       /* YUV (including grey) - next is 0x2014 */
        V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
        V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
        V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
@@ -60,6 +60,7 @@ enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
        V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
        V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
+       V4L2_MBUS_FMT_Y12_1X12 = 0x2013,
        V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f,
        V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
        V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
@@ -67,9 +68,11 @@ enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
        V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
 
-       /* Bayer - next is 0x3013 */
+       /* Bayer - next is 0x3015 */
        V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+       V4L2_MBUS_FMT_SGBRG8_1X8 = 0x3013,
        V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+       V4L2_MBUS_FMT_SRGGB8_1X8 = 0x3014,
        V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
        V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c,
        V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
index aa6c393b7ae991cd2f02242627fca08d0f0b713b..be82c8ead1af011ac7389e0ac2cbe94467df8583 100644 (file)
@@ -308,6 +308,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_Y4      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
 #define V4L2_PIX_FMT_Y6      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
 #define V4L2_PIX_FMT_Y10     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
+#define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
 /* Palette formats */
index 461c0119664ff88d2bf8797f2541ccae74ce0698..2b3831b58aa4312a754c41b2608431db85e31887 100644 (file)
@@ -58,6 +58,13 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                UNEVICTABLE_PGCLEARED,  /* on COW, page truncate */
                UNEVICTABLE_PGSTRANDED, /* unable to isolate on unlock */
                UNEVICTABLE_MLOCKFREED,
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+               THP_FAULT_ALLOC,
+               THP_FAULT_FALLBACK,
+               THP_COLLAPSE_ALLOC,
+               THP_COLLAPSE_ALLOC_FAILED,
+               THP_SPLIT,
+#endif
                NR_VM_EVENT_ITEMS
 };
 
index bd102cf509ac28ee9a0c5e70fcc9c4916ea50910..d61febfb1668549caa6b5610af09e3144aa3226e 100644 (file)
@@ -163,7 +163,7 @@ v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev);
 ({                                                                     \
        struct v4l2_subdev *__sd;                                       \
        __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, cond, o, \
-                                               f, args...);            \
+                                               f , ##args);            \
 })
 
 /* Call the specified callback for all subdevs matching grp_id (if 0, then
index cdf2e8ac4309576631abea0e05767d7edf5af027..d2df55b0c2134a35044a583429ac34e01b37f065 100644 (file)
@@ -139,8 +139,6 @@ do { \
  */
 
 enum p9_msg_t {
-       P9_TSYNCFS = 0,
-       P9_RSYNCFS,
        P9_TLERROR = 6,
        P9_RLERROR,
        P9_TSTATFS = 8,
index 85c1413f054d773ee79005cb01e6affc55f4adf1..051a99f79769a59021fdcb958a6f850e1f2ddc71 100644 (file)
@@ -218,8 +218,8 @@ void p9_client_disconnect(struct p9_client *clnt);
 void p9_client_begin_disconnect(struct p9_client *clnt);
 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
                                        char *uname, u32 n_uname, char *aname);
-struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
-                                                               int clone);
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
+               char **wnames, int clone);
 int p9_client_open(struct p9_fid *fid, int mode);
 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
                                                        char *extension);
@@ -230,7 +230,6 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
                gid_t gid, struct p9_qid *qid);
 int p9_client_clunk(struct p9_fid *fid);
 int p9_client_fsync(struct p9_fid *fid, int datasync);
-int p9_client_sync_fs(struct p9_fid *fid);
 int p9_client_remove(struct p9_fid *fid);
 int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
                                                        u64 offset, u32 count);
diff --git a/include/sound/ak4641.h b/include/sound/ak4641.h
new file mode 100644 (file)
index 0000000..96d1991
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * AK4641 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * 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 __AK4641_H
+#define __AK4641_H
+
+/**
+ * struct ak4641_platform_data - platform specific AK4641 configuration
+ * @gpio_power:        GPIO to control external power to AK4641
+ * @gpio_npdn: GPIO connected to AK4641 nPDN pin
+ *
+ * Both GPIO parameters are optional.
+ */
+struct ak4641_platform_data {
+       int gpio_power;
+       int gpio_npdn;
+};
+
+#endif /* __AK4641_H */
index 404acb859cee6a560235671f7c3b808dcec3e0b1..1a94a216ed99b72c1cca625d4bb637547fd61c85 100644 (file)
@@ -113,6 +113,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, v
 void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
 int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
 int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
 int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
 int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
diff --git a/include/sound/max98095.h b/include/sound/max98095.h
new file mode 100644 (file)
index 0000000..7513a42
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Platform data for MAX98095
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the 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 __SOUND_MAX98095_PDATA_H__
+#define __SOUND_MAX98095_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98095_eq_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+       u16 band3[5];
+       u16 band4[5];
+       u16 band5[5];
+};
+
+/* Biquad filter response configuration */
+struct max98095_biquad_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+};
+
+/* codec platform data */
+struct max98095_pdata {
+
+       /* Equalizers for DAI1 and DAI2 */
+       struct max98095_eq_cfg *eq_cfg;
+       unsigned int eq_cfgcnt;
+
+       /* Biquad filter for DAI1 and DAI2 */
+       struct max98095_biquad_cfg *bq_cfg;
+       unsigned int bq_cfgcnt;
+
+       /* Analog/digital microphone configuration:
+        * 0 = analog microphone input (normal setting)
+        * 1 = digital microphone input
+        */
+       unsigned int digmic_left_mode:1;
+       unsigned int digmic_right_mode:1;
+};
+
+#endif
index f72c1039a6fb6ef91fc454119eab21eff32e39a3..c46e7d89561dad6597898822208ac5af5180115f 100644 (file)
@@ -24,7 +24,7 @@
  * SoC dynamic audio power management
  *
  * We can have up to 4 power domains
- *     1. Codec domain - VREF, VMID
+ *  1. Codec domain - VREF, VMID
  *     Usually controlled at codec probe/remove, although can be set
  *     at stream time if power is not needed for sidetone, etc.
  *  2. Platform/Machine domain - physically connected inputs and outputs
 
 /* codec domain */
 #define SND_SOC_DAPM_VMID(wname) \
-{      .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0}
 
 /* platform domain */
 #define SND_SOC_DAPM_INPUT(wname) \
-{      .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_OUTPUT(wname) \
-{      .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_MIC(wname, wevent) \
-{      .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_HP(wname, wevent) \
-{      .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_SPK(wname, wevent) \
-{      .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_LINE(wname, wevent) \
-{      .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
 {      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+       .invert = winvert, .kcontrol_news = 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, \
+       .shift = wshift, .invert = winvert, .kcontrol_news = 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}
+       .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
        .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
         wcontrols) \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
        .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
 {      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_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, \
+       .invert = winvert, .kcontrol_news = 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, \
+       .invert = winvert, .kcontrol_news = 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, \
+       .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 
 /* additional sequencing control within an event type */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
        wcontrols, wevent, wflags) \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrols = wcontrols, \
+       .invert = winvert, .kcontrol_news = wcontrols, \
        .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
-{      .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_POST(wname, wevent) \
-{      .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+{      .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 
 
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
-{      .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
+{      .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
        .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
        .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
@@ -356,7 +356,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+                               struct dentry *parent);
 
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
@@ -472,7 +473,8 @@ struct snd_soc_dapm_widget {
 
        /* kcontrols that relate to this widget */
        int num_kcontrols;
-       const struct snd_kcontrol_new *kcontrols;
+       const struct snd_kcontrol_new *kcontrol_news;
+       struct snd_kcontrol **kcontrols;
 
        /* widget input and outputs */
        struct list_head sources;
@@ -516,4 +518,10 @@ struct snd_soc_dapm_context {
 #endif
 };
 
+/* A list of widgets associated with an object, typically a snd_kcontrol */
+struct snd_soc_dapm_widget_list {
+       int num_widgets;
+       struct snd_soc_dapm_widget *widgets[0];
+};
+
 #endif
index bfa4836ea107bfc50daba2fe4bdb640c26049927..f1de3e0c75bcad1da0cbed760272fe5e190bccdc 100644 (file)
@@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
 enum snd_soc_control_type {
-       SND_SOC_CUSTOM,
+       SND_SOC_CUSTOM = 1,
        SND_SOC_I2C,
        SND_SOC_SPI,
 };
@@ -278,6 +278,10 @@ int snd_soc_register_codec(struct device *dev,
 void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
                                    unsigned int reg);
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg);
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                               int addr_bits, int data_bits,
                               enum snd_soc_control_type control);
@@ -292,6 +296,8 @@ int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+                                     unsigned int reg);
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -523,6 +529,7 @@ struct snd_soc_codec {
        size_t reg_size;        /* reg_cache_size * reg_word_size */
        int (*volatile_register)(struct snd_soc_codec *, unsigned int);
        int (*readable_register)(struct snd_soc_codec *, unsigned int);
+       int (*writable_register)(struct snd_soc_codec *, unsigned int);
 
        /* runtime */
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
@@ -539,10 +546,12 @@ struct snd_soc_codec {
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
+       enum snd_soc_control_type control_type;
        hw_write_t hw_write;
        unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+       int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
        void *reg_cache;
        const void *reg_def_copy;
        const struct snd_soc_cache_ops *cache_ops;
@@ -568,7 +577,9 @@ struct snd_soc_codec_driver {
                        pm_message_t state);
        int (*resume)(struct snd_soc_codec *);
 
-       /* Default DAPM setup, added after probe() is run */
+       /* Default control and setup, added after probe() is run */
+       const struct snd_kcontrol_new *controls;
+       int num_controls;
        const struct snd_soc_dapm_widget *dapm_widgets;
        int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
@@ -587,6 +598,7 @@ struct snd_soc_codec_driver {
                                size_t, unsigned int);
        int (*volatile_register)(struct snd_soc_codec *, unsigned int);
        int (*readable_register)(struct snd_soc_codec *, unsigned int);
+       int (*writable_register)(struct snd_soc_codec *, unsigned int);
        short reg_cache_size;
        short reg_cache_step;
        short reg_word_size;
@@ -690,6 +702,8 @@ struct snd_soc_aux_dev {
 /* SoC card */
 struct snd_soc_card {
        const char *name;
+       const char *long_name;
+       const char *driver_name;
        struct device *dev;
        struct snd_card *snd_card;
        struct module *owner;
@@ -737,12 +751,15 @@ struct snd_soc_card {
        struct snd_soc_pcm_runtime *rtd_aux;
        int num_aux_rtd;
 
+       const struct snd_kcontrol_new *controls;
+       int num_controls;
+
        /*
         * Card-specific routes and widgets.
         */
-       struct snd_soc_dapm_widget *dapm_widgets;
+       const struct snd_soc_dapm_widget *dapm_widgets;
        int num_dapm_widgets;
-       struct snd_soc_dapm_route *dapm_routes;
+       const struct snd_soc_dapm_route *dapm_routes;
        int num_dapm_routes;
 
        struct work_struct deferred_resume_work;
@@ -805,7 +822,7 @@ struct soc_enum {
        unsigned char shift_r;
        unsigned int max;
        unsigned int mask;
-       const char **texts;
+       const char * const *texts;
        const unsigned int *values;
        void *dapm;
 };
@@ -814,6 +831,8 @@ struct soc_enum {
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
                           unsigned int reg, unsigned int val);
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+                                   unsigned int reg, const void *data, size_t len);
 
 /* device driver data */
 
@@ -871,6 +890,9 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
        INIT_LIST_HEAD(&card->dapm_list);
 }
 
+int snd_soc_util_init(void);
+void snd_soc_util_exit(void);
+
 #include <sound/soc-dai.h>
 
 #ifdef CONFIG_DEBUG_FS
index 5718a02d3afbea1eb993be1e9d1c81c65ea6c9f6..d2ea112fc20f0615a156c7a7c9909da6611ef786 100644 (file)
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 
+#define TEA575X_FMIF   10700
+
+#define TEA575X_DATA   (1 << 0)
+#define TEA575X_CLK    (1 << 1)
+#define TEA575X_WREN   (1 << 2)
+#define TEA575X_MOST   (1 << 3)
+
 struct snd_tea575x;
 
 struct snd_tea575x_ops {
-       void (*write)(struct snd_tea575x *tea, unsigned int val);
-       unsigned int (*read)(struct snd_tea575x *tea);
-       void (*mute)(struct snd_tea575x *tea, unsigned int mute);
+       void (*set_pins)(struct snd_tea575x *tea, u8 pins);
+       u8 (*get_pins)(struct snd_tea575x *tea);
+       void (*set_direction)(struct snd_tea575x *tea, bool output);
 };
 
 struct snd_tea575x {
-       struct snd_card *card;
        struct video_device *vd;        /* video device */
-       int dev_nr;                     /* requested device number + 1 */
-       int tea5759;                    /* 5759 chip is present */
-       int mute;                       /* Device is muted? */
-       unsigned int freq_fixup;        /* crystal onboard */
+       bool tea5759;                   /* 5759 chip is present */
+       bool mute;                      /* Device is muted? */
+       bool stereo;                    /* receiving stereo */
+       bool tuned;                     /* tuned to a station */
        unsigned int val;               /* hw value */
        unsigned long freq;             /* frequency */
        unsigned long in_use;           /* set if the device is in use */
        struct snd_tea575x_ops *ops;
        void *private_data;
+       u8 card[32];
+       u8 bus_info[32];
 };
 
-void snd_tea575x_init(struct snd_tea575x *tea);
+int snd_tea575x_init(struct snd_tea575x *tea);
 void snd_tea575x_exit(struct snd_tea575x *tea);
 
 #endif /* __SOUND_TEA575X_TUNER_H */
index 6c664965679832b871443db2627fd33dd998c77a..0b94192a8cdf44e60c67d0f29b9a01956e1c77b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Platform header for Texas Instruments TLV320DAC33 codec driver
  *
- * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
index e29fde6b5cbe5214edeecbdc522c98afefd8a977..89beccb57edd578bfdf2f8d460204f71e4ea80b4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Nokia Corporation
  *
- * Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/include/sound/wm8915.h b/include/sound/wm8915.h
new file mode 100644 (file)
index 0000000..5817d76
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * linux/sound/wm8915.h -- Platform data for WM8915
+ *
+ * Copyright 2011 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM8903_H
+#define __LINUX_SND_WM8903_H
+
+enum wm8915_inmode {
+       WM8915_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
+       WM8915_INVERTING = 1,         /* IN1xN */
+       WM8915_NON_INVERTING = 2,     /* IN1xP */
+       WM8915_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
+};
+
+/**
+ * ReTune Mobile configurations are specified with a label, sample
+ * rate and set of values to write (the enable bits will be ignored).
+ *
+ * Configurations are expected to be generated using the ReTune Mobile
+ * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8915_retune_mobile_config {
+       const char *name;
+       int rate;
+       u16 regs[20];
+};
+
+#define WM8915_SET_DEFAULT 0x10000
+
+struct wm8915_pdata {
+       int irq_flags;  /** Set IRQ trigger flags; default active low */
+
+       int ldo_ena;  /** GPIO for LDO1; -1 for none */
+
+       int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
+
+       enum wm8915_inmode inl_mode;
+       enum wm8915_inmode inr_mode;
+
+       u32 spkmute_seq;  /** Value for register 0x802 */
+
+       int gpio_base;
+       u32 gpio_default[5];
+
+       int num_retune_mobile_cfgs;
+       struct wm8915_retune_mobile_config *retune_mobile_cfgs;
+};
+
+#endif
index 2b5306c503fbc66e97c22dd07bb089b27c9aad71..1750bed7c2f6ed66d92152c089e810e0332b1251 100644 (file)
 /* Use to set GPIO default values to zero */
 #define WM8962_GPIO_SET 0x10000
 
+#define WM8962_GPIO_FN_CLKOUT           0
+#define WM8962_GPIO_FN_LOGIC            1
+#define WM8962_GPIO_FN_SDOUT            2
+#define WM8962_GPIO_FN_IRQ              3
+#define WM8962_GPIO_FN_THERMAL          4
+#define WM8962_GPIO_FN_PLL2_LOCK        6
+#define WM8962_GPIO_FN_PLL3_LOCK        7
+#define WM8962_GPIO_FN_FLL_LOCK         9
+#define WM8962_GPIO_FN_DRC_ACT         10
+#define WM8962_GPIO_FN_WSEQ_DONE       11
+#define WM8962_GPIO_FN_ALC_NG_ACT      12
+#define WM8962_GPIO_FN_ALC_PEAK_LIMIT  13
+#define WM8962_GPIO_FN_ALC_SATURATION  14
+#define WM8962_GPIO_FN_ALC_LEVEL_THR   15
+#define WM8962_GPIO_FN_ALC_LEVEL_LOCK  16
+#define WM8962_GPIO_FN_FIFO_ERR        17
+#define WM8962_GPIO_FN_OPCLK           18
+#define WM8962_GPIO_FN_DMICCLK         19
+#define WM8962_GPIO_FN_DMICDAT         20
+#define WM8962_GPIO_FN_MICD            21
+#define WM8962_GPIO_FN_MICSCD          22
+
 struct wm8962_pdata {
        int gpio_base;
        u32 gpio_init[WM8962_MAX_GPIO];
index 78f18adb49c88fee50ef7a6e2bf3dabf23f851a2..bf366547da252077cf168522a1ff22735a10d3a5 100644 (file)
@@ -401,9 +401,9 @@ TRACE_EVENT(block_plug,
 
 DECLARE_EVENT_CLASS(block_unplug,
 
-       TP_PROTO(struct request_queue *q),
+       TP_PROTO(struct request_queue *q, unsigned int depth, bool explicit),
 
-       TP_ARGS(q),
+       TP_ARGS(q, depth, explicit),
 
        TP_STRUCT__entry(
                __field( int,           nr_rq                   )
@@ -411,7 +411,7 @@ DECLARE_EVENT_CLASS(block_unplug,
        ),
 
        TP_fast_assign(
-               __entry->nr_rq  = q->rq.count[READ] + q->rq.count[WRITE];
+               __entry->nr_rq = depth;
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
@@ -419,31 +419,19 @@ DECLARE_EVENT_CLASS(block_unplug,
 );
 
 /**
- * block_unplug_timer - timed release of operations requests in queue to device driver
- * @q: request queue to unplug
- *
- * Unplug the request queue @q because a timer expired and allow block
- * operation requests to be sent to the device driver.
- */
-DEFINE_EVENT(block_unplug, block_unplug_timer,
-
-       TP_PROTO(struct request_queue *q),
-
-       TP_ARGS(q)
-);
-
-/**
- * block_unplug_io - release of operations requests in request queue
+ * block_unplug - release of operations requests in request queue
  * @q: request queue to unplug
+ * @depth: number of requests just added to the queue
+ * @explicit: whether this was an explicit unplug, or one from schedule()
  *
  * Unplug request queue @q because device driver is scheduled to work
  * on elements in the request queue.
  */
-DEFINE_EVENT(block_unplug, block_unplug_io,
+DEFINE_EVENT(block_unplug, block_unplug,
 
-       TP_PROTO(struct request_queue *q),
+       TP_PROTO(struct request_queue *q, unsigned int depth, bool explicit),
 
-       TP_ARGS(q)
+       TP_ARGS(q, depth, explicit)
 );
 
 /**
index 56240e724d9a31dc4ef43647afcf354b8a70f108..d886b1e9278e32e2fcffd5fb4005ee16a7061a33 100644 (file)
@@ -924,14 +924,6 @@ menuconfig EXPERT
           environments which can tolerate a "non-standard" kernel.
           Only use this if you really know what you are doing.
 
-config EMBEDDED
-       bool "Embedded system"
-       select EXPERT
-       help
-         This option should be enabled if compiling the kernel for
-         an embedded system so certain expert options are available
-         for configuration.
-
 config UID16
        bool "Enable 16-bit UID system calls" if EXPERT
        depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION)
@@ -1104,6 +1096,14 @@ config AIO
           by some high performance threaded applications. Disabling
           this option saves about 7k.
 
+config EMBEDDED
+       bool "Embedded system"
+       select EXPERT
+       help
+         This option should be enabled if compiling the kernel for
+         an embedded system so certain expert options are available
+         for configuration.
+
 config HAVE_PERF_EVENTS
        bool
        help
@@ -1226,6 +1226,7 @@ config SLAB
          per cpu and per node queues.
 
 config SLUB
+       depends on BROKEN || NUMA || !DISCONTIGMEM
        bool "SLUB (Unqueued Allocator)"
        help
           SLUB is a slab allocator that minimizes cache line usage
index f5d2f63bae0b70b2818edd92e06040906f115216..8dd87418154205940341f98641191fe1c1d6ea70 100644 (file)
@@ -1016,7 +1016,7 @@ NORET_TYPE void do_exit(long code)
        /*
         * FIXME: do that only when needed, using sched_exit tracepoint
         */
-       flush_ptrace_hw_breakpoint(tsk);
+       ptrace_put_breakpoints(tsk);
 
        exit_notify(tsk, group_dead);
 #ifdef CONFIG_NUMA
index dfb924ffe65ba758627864ac45c55bb9bda290bc..fe28dc282eae43af920d2937e8f9c5dc631ffa43 100644 (file)
@@ -1886,7 +1886,7 @@ retry:
        restart->futex.val = val;
        restart->futex.time = abs_time->tv64;
        restart->futex.bitset = bitset;
-       restart->futex.flags = flags;
+       restart->futex.flags = flags | FLAGS_HAS_TIMEOUT;
 
        ret = -ERESTART_RESTARTBLOCK;
 
index 9017478c5d4c3f224cde995518976ed8d88d79d5..87fdb3f8db14c50e6238a68267834169ce6b6300 100644 (file)
@@ -81,7 +81,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
        }
 };
 
-static int hrtimer_clock_to_base_table[MAX_CLOCKS];
+static int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
+       [CLOCK_REALTIME]        = HRTIMER_BASE_REALTIME,
+       [CLOCK_MONOTONIC]       = HRTIMER_BASE_MONOTONIC,
+       [CLOCK_BOOTTIME]        = HRTIMER_BASE_BOOTTIME,
+};
 
 static inline int hrtimer_clockid_to_base(clockid_t clock_id)
 {
@@ -1722,10 +1726,6 @@ static struct notifier_block __cpuinitdata hrtimers_nb = {
 
 void __init hrtimers_init(void)
 {
-       hrtimer_clock_to_base_table[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME;
-       hrtimer_clock_to_base_table[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC;
-       hrtimer_clock_to_base_table[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME;
-
        hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
                          (void *)(long)smp_processor_id());
        register_cpu_notifier(&hrtimers_nb);
index dd201bd35103e221fc14debc1d09419529bf6f3d..834899f2500fc550d3da66306d31386eb80baf91 100644 (file)
@@ -419,7 +419,7 @@ int show_interrupts(struct seq_file *p, void *v)
        } else {
                seq_printf(p, " %8s", "None");
        }
-#ifdef CONFIG_GENIRC_IRQ_SHOW_LEVEL
+#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
        seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
 #endif
        if (desc->name)
index 55936f9cb251b9eb114d9b827ee478e18a3448b7..87b77de03dd33942b29953909aaf5727bb5e2bdd 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
 #include <linux/kmsg_dump.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -1532,6 +1533,11 @@ int kernel_kexec(void)
                local_irq_disable();
                /* Suspend system devices */
                error = sysdev_suspend(PMSG_FREEZE);
+               if (!error) {
+                       error = syscore_suspend();
+                       if (error)
+                               sysdev_resume();
+               }
                if (error)
                        goto Enable_irqs;
        } else
@@ -1546,6 +1552,7 @@ int kernel_kexec(void)
 
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
+               syscore_resume();
                sysdev_resume();
  Enable_irqs:
                local_irq_enable();
index 27960f114efd73f9fb6ebec3d90952a643cd4284..8e81a9860a0d543c436716345b2ce0871229915b 100644 (file)
@@ -364,6 +364,7 @@ void perf_cgroup_switch(struct task_struct *task, int mode)
                        }
 
                        if (mode & PERF_CGROUP_SWIN) {
+                               WARN_ON_ONCE(cpuctx->cgrp);
                                /* set cgrp before ctxsw in to
                                 * allow event_filter_match() to not
                                 * have to pass task around
@@ -2423,6 +2424,14 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
        if (!ctx || !ctx->nr_events)
                goto out;
 
+       /*
+        * We must ctxsw out cgroup events to avoid conflict
+        * when invoking perf_task_event_sched_in() later on
+        * in this function. Otherwise we end up trying to
+        * ctxswin cgroup events which are already scheduled
+        * in.
+        */
+       perf_cgroup_sched_out(current);
        task_ctx_sched_out(ctx, EVENT_ALL);
 
        raw_spin_lock(&ctx->lock);
@@ -2447,6 +2456,9 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
 
        raw_spin_unlock(&ctx->lock);
 
+       /*
+        * Also calls ctxswin for cgroup events, if any:
+        */
        perf_event_context_sched_in(ctx, ctx->task);
 out:
        local_irq_restore(flags);
index 02f221274265ead8f24d98be78d669d5888e62fe..57a8346a270e07702e21d7bab15303427bf2fce0 100644 (file)
@@ -217,11 +217,14 @@ static int alloc_pidmap(struct pid_namespace *pid_ns)
        return -1;
 }
 
-int next_pidmap(struct pid_namespace *pid_ns, int last)
+int next_pidmap(struct pid_namespace *pid_ns, unsigned int last)
 {
        int offset;
        struct pidmap *map, *end;
 
+       if (last >= PID_MAX_LIMIT)
+               return -1;
+
        offset = (last + 1) & BITS_PER_PAGE_MASK;
        map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
        end = &pid_ns->pidmap[PIDMAP_ENTRIES];
index 4603f08dc47b1e7687b09ca51e31b3e7c48b4c55..6de9a8fc34179448c0768a1c4a12ad4849cb1ce6 100644 (file)
@@ -18,9 +18,13 @@ config SUSPEND_FREEZER
 
          Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
+config HIBERNATE_CALLBACKS
+       bool
+
 config HIBERNATION
        bool "Hibernation (aka 'suspend to disk')"
        depends on SWAP && ARCH_HIBERNATION_POSSIBLE
+       select HIBERNATE_CALLBACKS
        select LZO_COMPRESS
        select LZO_DECOMPRESS
        ---help---
@@ -85,7 +89,7 @@ config PM_STD_PARTITION
 
 config PM_SLEEP
        def_bool y
-       depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
+       depends on SUSPEND || HIBERNATE_CALLBACKS
 
 config PM_SLEEP_SMP
        def_bool y
index aeabd26e3342788e4330cfb4e8e2a5ba40b348d0..50aae660174d6bd0b0697b6a70e4e31b2e1535f3 100644 (file)
@@ -273,8 +273,11 @@ static int create_image(int platform_mode)
        local_irq_disable();
 
        error = sysdev_suspend(PMSG_FREEZE);
-       if (!error)
+       if (!error) {
                error = syscore_suspend();
+               if (error)
+                       sysdev_resume();
+       }
        if (error) {
                printk(KERN_ERR "PM: Some system devices failed to power down, "
                        "aborting hibernation\n");
@@ -407,8 +410,11 @@ static int resume_target_kernel(bool platform_mode)
        local_irq_disable();
 
        error = sysdev_suspend(PMSG_QUIESCE);
-       if (!error)
+       if (!error) {
                error = syscore_suspend();
+               if (error)
+                       sysdev_resume();
+       }
        if (error)
                goto Enable_irqs;
 
index 2814c32aed51c121a7ff9689aa38f6b98d025b15..8935369d503a309a036e75f975a903982fa6af80 100644 (file)
@@ -164,8 +164,11 @@ static int suspend_enter(suspend_state_t state)
        BUG_ON(!irqs_disabled());
 
        error = sysdev_suspend(PMSG_SUSPEND);
-       if (!error)
+       if (!error) {
                error = syscore_suspend();
+               if (error)
+                       sysdev_resume();
+       }
        if (!error) {
                if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {
                        error = suspend_ops->enter(state);
index 0fc1eed28d2783e0b2779fe50d1ff86fbf4ca858..dc7ab65f3b36cb0b71c8365e13d0e73a9601f6ee 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/regset.h>
+#include <linux/hw_breakpoint.h>
 
 
 /*
@@ -879,3 +880,19 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
        return ret;
 }
 #endif /* CONFIG_COMPAT */
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+int ptrace_get_breakpoints(struct task_struct *tsk)
+{
+       if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt))
+               return 0;
+
+       return -1;
+}
+
+void ptrace_put_breakpoints(struct task_struct *tsk)
+{
+       if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt))
+               flush_ptrace_hw_breakpoint(tsk);
+}
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
index 48013633d792f4682b0777dd96caf10beb6c8e73..312f8b95c2d44fbbc7c7097de04b52d92abc0648 100644 (file)
@@ -4111,20 +4111,20 @@ need_resched:
                                        try_to_wake_up_local(to_wakeup);
                        }
                        deactivate_task(rq, prev, DEQUEUE_SLEEP);
+
+                       /*
+                        * If we are going to sleep and we have plugged IO queued, make
+                        * sure to submit it to avoid deadlocks.
+                        */
+                       if (blk_needs_flush_plug(prev)) {
+                               raw_spin_unlock(&rq->lock);
+                               blk_schedule_flush_plug(prev);
+                               raw_spin_lock(&rq->lock);
+                       }
                }
                switch_count = &prev->nvcsw;
        }
 
-       /*
-        * If we are going to sleep and we have plugged IO queued, make
-        * sure to submit it to avoid deadlocks.
-        */
-       if (prev->state != TASK_RUNNING && blk_needs_flush_plug(prev)) {
-               raw_spin_unlock(&rq->lock);
-               blk_flush_plug(prev);
-               raw_spin_lock(&rq->lock);
-       }
-
        pre_schedule(rq, prev);
 
        if (unlikely(!rq->nr_running))
index 7f00772e57c90b9b5ee62a65b55f3b1a2f5af706..6fa833ab2cb80ebac3e3f38007f0d7c47995769e 100644 (file)
@@ -2104,21 +2104,20 @@ balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
              enum cpu_idle_type idle, int *all_pinned,
              int *this_best_prio, struct cfs_rq *busiest_cfs_rq)
 {
-       int loops = 0, pulled = 0, pinned = 0;
+       int loops = 0, pulled = 0;
        long rem_load_move = max_load_move;
        struct task_struct *p, *n;
 
        if (max_load_move == 0)
                goto out;
 
-       pinned = 1;
-
        list_for_each_entry_safe(p, n, &busiest_cfs_rq->tasks, se.group_node) {
                if (loops++ > sysctl_sched_nr_migrate)
                        break;
 
                if ((p->se.load.weight >> 1) > rem_load_move ||
-                   !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned))
+                   !can_migrate_task(p, busiest, this_cpu, sd, idle,
+                                     all_pinned))
                        continue;
 
                pull_task(busiest, p, this_rq, this_cpu);
@@ -2153,9 +2152,6 @@ out:
         */
        schedstat_add(sd, lb_gained[idle], pulled);
 
-       if (all_pinned)
-               *all_pinned = pinned;
-
        return max_load_move - rem_load_move;
 }
 
@@ -3127,6 +3123,8 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        if (!sds.busiest || sds.busiest_nr_running == 0)
                goto out_balanced;
 
+       sds.avg_load = (SCHED_LOAD_SCALE * sds.total_load) / sds.total_pwr;
+
        /*
         * If the busiest group is imbalanced the below checks don't
         * work because they assumes all things are equal, which typically
@@ -3151,7 +3149,6 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
         * Don't pull any tasks if this group is already above the domain
         * average load.
         */
-       sds.avg_load = (SCHED_LOAD_SCALE * sds.total_load) / sds.total_pwr;
        if (sds.this_load >= sds.avg_load)
                goto out_balanced;
 
@@ -3340,6 +3337,7 @@ redo:
                 * still unbalanced. ld_moved simply stays zero, so it is
                 * correctly treated as an imbalance.
                 */
+               all_pinned = 1;
                local_irq_save(flags);
                double_rq_lock(this_rq, busiest);
                ld_moved = move_tasks(this_rq, this_cpu, busiest,
index 25028dd4fa18044846caa1098bf87b28c1c81be4..c340ca658f37a0c09726a31a6f126f18c9380355 100644 (file)
@@ -19,7 +19,6 @@
  */
 #include <linux/device.h>
 #include <linux/file.h>
-#include <linux/mutex.h>
 #include <linux/posix-clock.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
@@ -34,19 +33,19 @@ static struct posix_clock *get_posix_clock(struct file *fp)
 {
        struct posix_clock *clk = fp->private_data;
 
-       mutex_lock(&clk->mutex);
+       down_read(&clk->rwsem);
 
        if (!clk->zombie)
                return clk;
 
-       mutex_unlock(&clk->mutex);
+       up_read(&clk->rwsem);
 
        return NULL;
 }
 
 static void put_posix_clock(struct posix_clock *clk)
 {
-       mutex_unlock(&clk->mutex);
+       up_read(&clk->rwsem);
 }
 
 static ssize_t posix_clock_read(struct file *fp, char __user *buf,
@@ -156,7 +155,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
        struct posix_clock *clk =
                container_of(inode->i_cdev, struct posix_clock, cdev);
 
-       mutex_lock(&clk->mutex);
+       down_read(&clk->rwsem);
 
        if (clk->zombie) {
                err = -ENODEV;
@@ -172,7 +171,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
                fp->private_data = clk;
        }
 out:
-       mutex_unlock(&clk->mutex);
+       up_read(&clk->rwsem);
        return err;
 }
 
@@ -211,25 +210,20 @@ int posix_clock_register(struct posix_clock *clk, dev_t devid)
        int err;
 
        kref_init(&clk->kref);
-       mutex_init(&clk->mutex);
+       init_rwsem(&clk->rwsem);
 
        cdev_init(&clk->cdev, &posix_clock_file_operations);
        clk->cdev.owner = clk->ops.owner;
        err = cdev_add(&clk->cdev, devid, 1);
-       if (err)
-               goto no_cdev;
 
        return err;
-no_cdev:
-       mutex_destroy(&clk->mutex);
-       return err;
 }
 EXPORT_SYMBOL_GPL(posix_clock_register);
 
 static void delete_clock(struct kref *kref)
 {
        struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
-       mutex_destroy(&clk->mutex);
+
        if (clk->release)
                clk->release(clk);
 }
@@ -238,9 +232,9 @@ void posix_clock_unregister(struct posix_clock *clk)
 {
        cdev_del(&clk->cdev);
 
-       mutex_lock(&clk->mutex);
+       down_write(&clk->rwsem);
        clk->zombie = true;
-       mutex_unlock(&clk->mutex);
+       up_write(&clk->rwsem);
 
        kref_put(&clk->kref, delete_clock);
 }
index 61d7d59f4a1ad5175cfb14a5922c14270919167b..2ad39e556cb4a408ca09ba408e8a1ecf85fd756b 100644 (file)
@@ -141,7 +141,7 @@ if FTRACE
 config FUNCTION_TRACER
        bool "Kernel Function Tracer"
        depends on HAVE_FUNCTION_TRACER
-       select FRAME_POINTER if !ARM_UNWIND && !S390
+       select FRAME_POINTER if !ARM_UNWIND && !S390 && !MICROBLAZE
        select KALLSYMS
        select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
index 7aa40f8e182d569bcba8c0a3f33bb0f73b6f4950..6957aa298dfa45581b45832b7251a2ee4029000e 100644 (file)
@@ -850,29 +850,21 @@ static void blk_add_trace_plug(void *ignore, struct request_queue *q)
                __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);
 }
 
-static void blk_add_trace_unplug_io(void *ignore, struct request_queue *q)
+static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
+                                   unsigned int depth, bool explicit)
 {
        struct blk_trace *bt = q->blk_trace;
 
        if (bt) {
-               unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE];
-               __be64 rpdu = cpu_to_be64(pdu);
+               __be64 rpdu = cpu_to_be64(depth);
+               u32 what;
 
-               __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0,
-                               sizeof(rpdu), &rpdu);
-       }
-}
-
-static void blk_add_trace_unplug_timer(void *ignore, struct request_queue *q)
-{
-       struct blk_trace *bt = q->blk_trace;
-
-       if (bt) {
-               unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE];
-               __be64 rpdu = cpu_to_be64(pdu);
+               if (explicit)
+                       what = BLK_TA_UNPLUG_IO;
+               else
+                       what = BLK_TA_UNPLUG_TIMER;
 
-               __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_TIMER, 0,
-                               sizeof(rpdu), &rpdu);
+               __blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);
        }
 }
 
@@ -1015,9 +1007,7 @@ static void blk_register_tracepoints(void)
        WARN_ON(ret);
        ret = register_trace_block_plug(blk_add_trace_plug, NULL);
        WARN_ON(ret);
-       ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
-       WARN_ON(ret);
-       ret = register_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
+       ret = register_trace_block_unplug(blk_add_trace_unplug, NULL);
        WARN_ON(ret);
        ret = register_trace_block_split(blk_add_trace_split, NULL);
        WARN_ON(ret);
@@ -1032,8 +1022,7 @@ static void blk_unregister_tracepoints(void)
        unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
        unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
        unregister_trace_block_split(blk_add_trace_split, NULL);
-       unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
-       unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
+       unregister_trace_block_unplug(blk_add_trace_unplug, NULL);
        unregister_trace_block_plug(blk_add_trace_plug, NULL);
        unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
        unregister_trace_block_getrq(blk_add_trace_getrq, NULL);
index d38c16a06a6fb25d4f31559af0c1544f6cae987f..1cb49be7c7fb5b30fdab269d044b130899b93340 100644 (file)
@@ -1110,6 +1110,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
+       entry->padding                  = 0;
        entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
index e88f74fe1d4ce02fedf3e6052feaf2cbdd2017da..2fe110341359539b0498d49472bbdee19e344dc2 100644 (file)
@@ -116,6 +116,7 @@ static int trace_define_common_fields(void)
        __common_field(unsigned char, flags);
        __common_field(unsigned char, preempt_count);
        __common_field(int, pid);
+       __common_field(int, padding);
 
        return ret;
 }
index 140dce750450edc8db5285817c26fd354ec0c56a..14733d4d156b5e90603cafec70eb9907b141b6dd 100644 (file)
@@ -430,9 +430,12 @@ static int watchdog_enable(int cpu)
                p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
                if (IS_ERR(p)) {
                        printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
-                       if (!err)
+                       if (!err) {
                                /* if hardlockup hasn't already set this */
                                err = PTR_ERR(p);
+                               /* and disable the perf event */
+                               watchdog_nmi_disable(cpu);
+                       }
                        goto out;
                }
                kthread_bind(p, cpu);
index 8859a41806dddae875e1ceae1e6ed94a4e3aebff..e3378e8d3a5ce7e16fbbbb35ebd30a1c51fde650 100644 (file)
@@ -1291,8 +1291,14 @@ __acquires(&gcwq->lock)
                        return true;
                spin_unlock_irq(&gcwq->lock);
 
-               /* CPU has come up in between, retry migration */
+               /*
+                * We've raced with CPU hot[un]plug.  Give it a breather
+                * and retry migration.  cond_resched() is required here;
+                * otherwise, we might deadlock against cpu_stop trying to
+                * bring down the CPU on non-preemptive kernel.
+                */
                cpu_relax();
+               cond_resched();
        }
 }
 
index c0ea40ba20828b67c10e29d790ca13846572b8a0..854b57bd7d9d346276fe83599f5cbd306c6e0fe4 100644 (file)
@@ -232,10 +232,10 @@ EXPORT_SYMBOL(flex_array_clear);
 
 /**
  * flex_array_prealloc - guarantee that array space exists
- * @fa:                the flex array for which to preallocate parts
- * @start:     index of first array element for which space is allocated
- * @end:       index of last (inclusive) element for which space is allocated
- * @flags:     page allocation flags
+ * @fa:                        the flex array for which to preallocate parts
+ * @start:             index of first array element for which space is allocated
+ * @nr_elements:       number of elements for which space is allocated
+ * @flags:             page allocation flags
  *
  * This will guarantee that no future calls to flex_array_put()
  * will allocate memory.  It can be used if you are expecting to
@@ -245,14 +245,24 @@ EXPORT_SYMBOL(flex_array_clear);
  * Locking must be provided by the caller.
  */
 int flex_array_prealloc(struct flex_array *fa, unsigned int start,
-                       unsigned int end, gfp_t flags)
+                       unsigned int nr_elements, gfp_t flags)
 {
        int start_part;
        int end_part;
        int part_nr;
+       unsigned int end;
        struct flex_array_part *part;
 
-       if (start >= fa->total_nr_elements || end >= fa->total_nr_elements)
+       if (!start && !nr_elements)
+               return 0;
+       if (start >= fa->total_nr_elements)
+               return -ENOSPC;
+       if (!nr_elements)
+               return 0;
+
+       end = start + nr_elements - 1;
+
+       if (end >= fa->total_nr_elements)
                return -ENOSPC;
        if (elements_fit_in_base(fa))
                return 0;
@@ -343,6 +353,8 @@ int flex_array_shrink(struct flex_array *fa)
        int part_nr;
        int ret = 0;
 
+       if (!fa->total_nr_elements)
+               return 0;
        if (elements_fit_in_base(fa))
                return ret;
        for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) {
index 05672e819f8c4c9164dd40e3752d23b8b5f63577..a235f3cc471c6d427fd4c2e713a701fa0b1e7e1b 100644 (file)
@@ -49,12 +49,9 @@ static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
                        val = *s - '0';
                else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
                        val = _tolower(*s) - 'a' + 10;
-               else if (*s == '\n') {
-                       if (*(s + 1) == '\0')
-                               break;
-                       else
-                               return -EINVAL;
-               } else
+               else if (*s == '\n' && *(s + 1) == '\0')
+                       break;
+               else
                        return -EINVAL;
 
                if (val >= base)
index 325c2f9ecebdc431e87fc1ab375c1ac5e1365d64..d55769d63cb8b3efb8182a0f58a73ed496768b21 100644 (file)
@@ -315,12 +315,12 @@ static void __init test_kstrtou64_ok(void)
                {"65537",       10,     65537},
                {"2147483646",  10,     2147483646},
                {"2147483647",  10,     2147483647},
-               {"2147483648",  10,     2147483648},
-               {"2147483649",  10,     2147483649},
-               {"4294967294",  10,     4294967294},
-               {"4294967295",  10,     4294967295},
-               {"4294967296",  10,     4294967296},
-               {"4294967297",  10,     4294967297},
+               {"2147483648",  10,     2147483648ULL},
+               {"2147483649",  10,     2147483649ULL},
+               {"4294967294",  10,     4294967294ULL},
+               {"4294967295",  10,     4294967295ULL},
+               {"4294967296",  10,     4294967296ULL},
+               {"4294967297",  10,     4294967297ULL},
                {"9223372036854775806", 10,     9223372036854775806ULL},
                {"9223372036854775807", 10,     9223372036854775807ULL},
                {"9223372036854775808", 10,     9223372036854775808ULL},
@@ -369,12 +369,12 @@ static void __init test_kstrtos64_ok(void)
                {"65537",       10,     65537},
                {"2147483646",  10,     2147483646},
                {"2147483647",  10,     2147483647},
-               {"2147483648",  10,     2147483648},
-               {"2147483649",  10,     2147483649},
-               {"4294967294",  10,     4294967294},
-               {"4294967295",  10,     4294967295},
-               {"4294967296",  10,     4294967296},
-               {"4294967297",  10,     4294967297},
+               {"2147483648",  10,     2147483648LL},
+               {"2147483649",  10,     2147483649LL},
+               {"4294967294",  10,     4294967294LL},
+               {"4294967295",  10,     4294967295LL},
+               {"4294967296",  10,     4294967296LL},
+               {"4294967297",  10,     4294967297LL},
                {"9223372036854775806", 10,     9223372036854775806LL},
                {"9223372036854775807", 10,     9223372036854775807LL},
        };
@@ -418,10 +418,10 @@ static void __init test_kstrtou32_ok(void)
                {"65537",       10,     65537},
                {"2147483646",  10,     2147483646},
                {"2147483647",  10,     2147483647},
-               {"2147483648",  10,     2147483648},
-               {"2147483649",  10,     2147483649},
-               {"4294967294",  10,     4294967294},
-               {"4294967295",  10,     4294967295},
+               {"2147483648",  10,     2147483648U},
+               {"2147483649",  10,     2147483649U},
+               {"4294967294",  10,     4294967294U},
+               {"4294967295",  10,     4294967295U},
        };
        TEST_OK(kstrtou32, u32, "%u", test_u32_ok);
 }
index ea5fa4fe9d67879aa47be92ad9220a4d8d1beb31..a6cdc969ea42a7b5df5e74e8cb4d712f6f7bbd3b 100644 (file)
@@ -969,6 +969,9 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
                         */
                        tmp = b->in[b->in_pos++];
 
+                       if (tmp == 0x00)
+                               return XZ_STREAM_END;
+
                        if (tmp >= 0xE0 || tmp == 0x01) {
                                s->lzma2.need_props = true;
                                s->lzma2.need_dict_reset = false;
@@ -1001,9 +1004,6 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
                                                lzma_reset(s);
                                }
                        } else {
-                               if (tmp == 0x00)
-                                       return XZ_STREAM_END;
-
                                if (tmp > 0x02)
                                        return XZ_DATA_ERROR;
 
index 0a619e0e2e0bd26da68b26948f065e1be72a8aa0..83326ad66d9b15df1027a0274d92886c85386394 100644 (file)
@@ -244,24 +244,28 @@ static ssize_t single_flag_show(struct kobject *kobj,
                                struct kobj_attribute *attr, char *buf,
                                enum transparent_hugepage_flag flag)
 {
-       if (test_bit(flag, &transparent_hugepage_flags))
-               return sprintf(buf, "[yes] no\n");
-       else
-               return sprintf(buf, "yes [no]\n");
+       return sprintf(buf, "%d\n",
+                      !!test_bit(flag, &transparent_hugepage_flags));
 }
+
 static ssize_t single_flag_store(struct kobject *kobj,
                                 struct kobj_attribute *attr,
                                 const char *buf, size_t count,
                                 enum transparent_hugepage_flag flag)
 {
-       if (!memcmp("yes", buf,
-                   min(sizeof("yes")-1, count))) {
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul(buf, 10, &value);
+       if (ret < 0)
+               return ret;
+       if (value > 1)
+               return -EINVAL;
+
+       if (value)
                set_bit(flag, &transparent_hugepage_flags);
-       } else if (!memcmp("no", buf,
-                          min(sizeof("no")-1, count))) {
+       else
                clear_bit(flag, &transparent_hugepage_flags);
-       } else
-               return -EINVAL;
 
        return count;
 }
@@ -680,8 +684,11 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        return VM_FAULT_OOM;
                page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
                                          vma, haddr, numa_node_id(), 0);
-               if (unlikely(!page))
+               if (unlikely(!page)) {
+                       count_vm_event(THP_FAULT_FALLBACK);
                        goto out;
+               }
+               count_vm_event(THP_FAULT_ALLOC);
                if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
                        put_page(page);
                        goto out;
@@ -909,11 +916,13 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                new_page = NULL;
 
        if (unlikely(!new_page)) {
+               count_vm_event(THP_FAULT_FALLBACK);
                ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
                                                   pmd, orig_pmd, page, haddr);
                put_page(page);
                goto out;
        }
+       count_vm_event(THP_FAULT_ALLOC);
 
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
                put_page(new_page);
@@ -1390,6 +1399,7 @@ int split_huge_page(struct page *page)
 
        BUG_ON(!PageSwapBacked(page));
        __split_huge_page(page, anon_vma);
+       count_vm_event(THP_SPLIT);
 
        BUG_ON(PageCompound(page));
 out_unlock:
@@ -1398,6 +1408,9 @@ out:
        return ret;
 }
 
+#define VM_NO_THP (VM_SPECIAL|VM_INSERTPAGE|VM_MIXEDMAP|VM_SAO| \
+                  VM_HUGETLB|VM_SHARED|VM_MAYSHARE)
+
 int hugepage_madvise(struct vm_area_struct *vma,
                     unsigned long *vm_flags, int advice)
 {
@@ -1406,11 +1419,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
                /*
                 * Be somewhat over-protective like KSM for now!
                 */
-               if (*vm_flags & (VM_HUGEPAGE |
-                                VM_SHARED   | VM_MAYSHARE   |
-                                VM_PFNMAP   | VM_IO      | VM_DONTEXPAND |
-                                VM_RESERVED | VM_HUGETLB | VM_INSERTPAGE |
-                                VM_MIXEDMAP | VM_SAO))
+               if (*vm_flags & (VM_HUGEPAGE | VM_NO_THP))
                        return -EINVAL;
                *vm_flags &= ~VM_NOHUGEPAGE;
                *vm_flags |= VM_HUGEPAGE;
@@ -1426,11 +1435,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
                /*
                 * Be somewhat over-protective like KSM for now!
                 */
-               if (*vm_flags & (VM_NOHUGEPAGE |
-                                VM_SHARED   | VM_MAYSHARE   |
-                                VM_PFNMAP   | VM_IO      | VM_DONTEXPAND |
-                                VM_RESERVED | VM_HUGETLB | VM_INSERTPAGE |
-                                VM_MIXEDMAP | VM_SAO))
+               if (*vm_flags & (VM_NOHUGEPAGE | VM_NO_THP))
                        return -EINVAL;
                *vm_flags &= ~VM_HUGEPAGE;
                *vm_flags |= VM_NOHUGEPAGE;
@@ -1564,10 +1569,14 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma)
                 * page fault if needed.
                 */
                return 0;
-       if (vma->vm_file || vma->vm_ops)
+       if (vma->vm_ops)
                /* khugepaged not yet working on file or special mappings */
                return 0;
-       VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
+       /*
+        * If is_pfn_mapping() is true is_learn_pfn_mapping() must be
+        * true too, verify it here.
+        */
+       VM_BUG_ON(is_linear_pfn_mapping(vma) || vma->vm_flags & VM_NO_THP);
        hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
        hend = vma->vm_end & HPAGE_PMD_MASK;
        if (hstart < hend)
@@ -1784,9 +1793,11 @@ static void collapse_huge_page(struct mm_struct *mm,
                                      node, __GFP_OTHER_NODE);
        if (unlikely(!new_page)) {
                up_read(&mm->mmap_sem);
+               count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                *hpage = ERR_PTR(-ENOMEM);
                return;
        }
+       count_vm_event(THP_COLLAPSE_ALLOC);
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
                up_read(&mm->mmap_sem);
                put_page(new_page);
@@ -1816,12 +1827,15 @@ static void collapse_huge_page(struct mm_struct *mm,
            (vma->vm_flags & VM_NOHUGEPAGE))
                goto out;
 
-       /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
-       if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
+       if (!vma->anon_vma || vma->vm_ops)
                goto out;
        if (is_vma_temporary_stack(vma))
                goto out;
-       VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
+       /*
+        * If is_pfn_mapping() is true is_learn_pfn_mapping() must be
+        * true too, verify it here.
+        */
+       VM_BUG_ON(is_linear_pfn_mapping(vma) || vma->vm_flags & VM_NO_THP);
 
        pgd = pgd_offset(mm, address);
        if (!pgd_present(*pgd))
@@ -2054,13 +2068,16 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
                        progress++;
                        continue;
                }
-               /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
-               if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
+               if (!vma->anon_vma || vma->vm_ops)
                        goto skip;
                if (is_vma_temporary_stack(vma))
                        goto skip;
-
-               VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
+               /*
+                * If is_pfn_mapping() is true is_learn_pfn_mapping()
+                * must be true too, verify it here.
+                */
+               VM_BUG_ON(is_linear_pfn_mapping(vma) ||
+                         vma->vm_flags & VM_NO_THP);
 
                hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
                hend = vma->vm_end & HPAGE_PMD_MASK;
@@ -2151,8 +2168,11 @@ static void khugepaged_do_scan(struct page **hpage)
 #ifndef CONFIG_NUMA
                if (!*hpage) {
                        *hpage = alloc_hugepage(khugepaged_defrag());
-                       if (unlikely(!*hpage))
+                       if (unlikely(!*hpage)) {
+                               count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                                break;
+                       }
+                       count_vm_event(THP_COLLAPSE_ALLOC);
                }
 #else
                if (IS_ERR(*hpage))
@@ -2192,8 +2212,11 @@ static struct page *khugepaged_alloc_hugepage(void)
 
        do {
                hpage = alloc_hugepage(khugepaged_defrag());
-               if (!hpage)
+               if (!hpage) {
+                       count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                        khugepaged_alloc_sleep();
+               } else
+                       count_vm_event(THP_COLLAPSE_ALLOC);
        } while (unlikely(!hpage) &&
                 likely(khugepaged_enabled()));
        return hpage;
@@ -2210,8 +2233,11 @@ static void khugepaged_loop(void)
        while (likely(khugepaged_enabled())) {
 #ifndef CONFIG_NUMA
                hpage = khugepaged_alloc_hugepage();
-               if (unlikely(!hpage))
+               if (unlikely(!hpage)) {
+                       count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                        break;
+               }
+               count_vm_event(THP_COLLAPSE_ALLOC);
 #else
                if (IS_ERR(hpage)) {
                        khugepaged_alloc_sleep();
index 9da8cab1b1b0abceae9569a794447f3ddb0c1134..61e66f026563b4b473fc73922d58a984c490c827 100644 (file)
@@ -1359,7 +1359,7 @@ split_fallthrough:
                 */
                mark_page_accessed(page);
        }
-       if (flags & FOLL_MLOCK) {
+       if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {
                /*
                 * The preliminary mapping check is mainly to avoid the
                 * pointless overhead of lock_page on the ZERO_PAGE
@@ -1410,6 +1410,12 @@ no_page_table:
        return page;
 }
 
+static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       return stack_guard_page_start(vma, addr) ||
+              stack_guard_page_end(vma, addr+PAGE_SIZE);
+}
+
 /**
  * __get_user_pages() - pin user pages in memory
  * @tsk:       task_struct of target task
@@ -1488,7 +1494,6 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                vma = find_extend_vma(mm, start);
                if (!vma && in_gate_area(mm, start)) {
                        unsigned long pg = start & PAGE_MASK;
-                       struct vm_area_struct *gate_vma = get_gate_vma(mm);
                        pgd_t *pgd;
                        pud_t *pud;
                        pmd_t *pmd;
@@ -1513,10 +1518,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                pte_unmap(pte);
                                return i ? : -EFAULT;
                        }
+                       vma = get_gate_vma(mm);
                        if (pages) {
                                struct page *page;
 
-                               page = vm_normal_page(gate_vma, start, *pte);
+                               page = vm_normal_page(vma, start, *pte);
                                if (!page) {
                                        if (!(gup_flags & FOLL_DUMP) &&
                                             is_zero_pfn(pte_pfn(*pte)))
@@ -1530,12 +1536,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                get_page(page);
                        }
                        pte_unmap(pte);
-                       if (vmas)
-                               vmas[i] = gate_vma;
-                       i++;
-                       start += PAGE_SIZE;
-                       nr_pages--;
-                       continue;
+                       goto next_page;
                }
 
                if (!vma ||
@@ -1565,6 +1566,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                int ret;
                                unsigned int fault_flags = 0;
 
+                               /* For mlock, just skip the stack guard page. */
+                               if (foll_flags & FOLL_MLOCK) {
+                                       if (stack_guard_page(vma, start))
+                                               goto next_page;
+                               }
                                if (foll_flags & FOLL_WRITE)
                                        fault_flags |= FAULT_FLAG_WRITE;
                                if (nonblocking)
@@ -1631,6 +1637,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                flush_anon_page(vma, page, start);
                                flush_dcache_page(page);
                        }
+next_page:
                        if (vmas)
                                vmas[i] = vma;
                        i++;
@@ -3386,7 +3393,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * run pte_offset_map on the pmd, if an huge pmd could
         * materialize from under us from a different thread.
         */
-       if (unlikely(__pte_alloc(mm, vma, pmd, address)))
+       if (unlikely(pmd_none(*pmd)) && __pte_alloc(mm, vma, pmd, address))
                return VM_FAULT_OOM;
        /* if an huge pmd materialized from under us just retry later */
        if (unlikely(pmd_trans_huge(*pmd)))
@@ -3678,7 +3685,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
                         */
 #ifdef CONFIG_HAVE_IOREMAP_PROT
                        vma = find_vma(mm, addr);
-                       if (!vma)
+                       if (!vma || vma->vm_start > addr)
                                break;
                        if (vma->vm_ops && vma->vm_ops->access)
                                ret = vma->vm_ops->access(vma, addr, buf,
index a2acaf820fe518a98a5e6008690967453fbef7d0..9ca1d604f7cd74aab7a897de22e0784a8c0bcb45 100644 (file)
@@ -375,7 +375,7 @@ void online_page(struct page *page)
 #endif
 
 #ifdef CONFIG_FLATMEM
-       max_mapnr = max(page_to_pfn(page), max_mapnr);
+       max_mapnr = max(pfn, max_mapnr);
 #endif
 
        ClearPageReserved(page);
index 2689a08c79affabda1e46b65271c60e3ba653ab7..516b2c2ddd5a55b244a89af33eeb3b6f3b88d410 100644 (file)
@@ -135,13 +135,6 @@ void munlock_vma_page(struct page *page)
        }
 }
 
-static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr)
-{
-       return (vma->vm_flags & VM_GROWSDOWN) &&
-               (vma->vm_start == addr) &&
-               !vma_stack_continue(vma->vm_prev, addr);
-}
-
 /**
  * __mlock_vma_pages_range() -  mlock a range of pages in the vma.
  * @vma:   target vma
@@ -169,7 +162,7 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        VM_BUG_ON(end   > vma->vm_end);
        VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
 
-       gup_flags = FOLL_TOUCH;
+       gup_flags = FOLL_TOUCH | FOLL_MLOCK;
        /*
         * We want to touch writable mappings with a write fault in order
         * to break COW, except for shared mappings because these don't COW
@@ -185,15 +178,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
                gup_flags |= FOLL_FORCE;
 
-       if (vma->vm_flags & VM_LOCKED)
-               gup_flags |= FOLL_MLOCK;
-
-       /* We don't try to access the guard page of a stack vma */
-       if (stack_guard_page(vma, start)) {
-               addr += PAGE_SIZE;
-               nr_pages--;
-       }
-
        return __get_user_pages(current, mm, addr, nr_pages, gup_flags,
                                NULL, NULL, nonblocking);
 }
index 2ec8eb5a9cdd0b4ae2e20471858bd4e09d83af00..772140c53ab185ebc76d1f185d6feb9fb8935c15 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -259,7 +259,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
         * randomize_va_space to 2, which will still cause mm->start_brk
         * to be arbitrarily shifted
         */
-       if (mm->start_brk > PAGE_ALIGN(mm->end_data))
+       if (current->brk_randomized)
                min_brk = mm->start_brk;
        else
                min_brk = mm->end_data;
@@ -1767,10 +1767,13 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                size = address - vma->vm_start;
                grow = (address - vma->vm_end) >> PAGE_SHIFT;
 
-               error = acct_stack_growth(vma, size, grow);
-               if (!error) {
-                       vma->vm_end = address;
-                       perf_event_mmap(vma);
+               error = -ENOMEM;
+               if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) {
+                       error = acct_stack_growth(vma, size, grow);
+                       if (!error) {
+                               vma->vm_end = address;
+                               perf_event_mmap(vma);
+                       }
                }
        }
        vma_unlock_anon_vma(vma);
@@ -1814,11 +1817,14 @@ static int expand_downwards(struct vm_area_struct *vma,
                size = vma->vm_end - address;
                grow = (vma->vm_start - address) >> PAGE_SHIFT;
 
-               error = acct_stack_growth(vma, size, grow);
-               if (!error) {
-                       vma->vm_start = address;
-                       vma->vm_pgoff -= grow;
-                       perf_event_mmap(vma);
+               error = -ENOMEM;
+               if (grow <= vma->vm_pgoff) {
+                       error = acct_stack_growth(vma, size, grow);
+                       if (!error) {
+                               vma->vm_start = address;
+                               vma->vm_pgoff -= grow;
+                               perf_event_mmap(vma);
+                       }
                }
        }
        vma_unlock_anon_vma(vma);
index 6a819d1b2c7dd70015b9fadff8f28d70f3b6f422..f52e85c80e8d554fcae1a7ad40e0617c0bb1318f 100644 (file)
@@ -83,24 +83,6 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk,
 }
 #endif /* CONFIG_NUMA */
 
-/*
- * If this is a system OOM (not a memcg OOM) and the task selected to be
- * killed is not already running at high (RT) priorities, speed up the
- * recovery by boosting the dying task to the lowest FIFO priority.
- * That helps with the recovery and avoids interfering with RT tasks.
- */
-static void boost_dying_task_prio(struct task_struct *p,
-                                 struct mem_cgroup *mem)
-{
-       struct sched_param param = { .sched_priority = 1 };
-
-       if (mem)
-               return;
-
-       if (!rt_task(p))
-               sched_setscheduler_nocheck(p, SCHED_FIFO, &param);
-}
-
 /*
  * The process p may have detached its own ->mm while exiting or through
  * use_mm(), but one or more of its subthreads may still have a valid
@@ -190,10 +172,13 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
 
        /*
         * The baseline for the badness score is the proportion of RAM that each
-        * task's rss and swap space use.
+        * task's rss, pagetable and swap space use.
         */
-       points = (get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS)) * 1000 /
-                       totalpages;
+       points = get_mm_rss(p->mm) + p->mm->nr_ptes;
+       points += get_mm_counter(p->mm, MM_SWAPENTS);
+
+       points *= 1000;
+       points /= totalpages;
        task_unlock(p);
 
        /*
@@ -452,13 +437,6 @@ static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
        set_tsk_thread_flag(p, TIF_MEMDIE);
        force_sig(SIGKILL, p);
 
-       /*
-        * We give our sacrificial lamb high priority and access to
-        * all the memory it needs. That way it should be able to
-        * exit() and clear out its resources quickly...
-        */
-       boost_dying_task_prio(p, mem);
-
        return 0;
 }
 #undef K
@@ -482,7 +460,6 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
         */
        if (p->flags & PF_EXITING) {
                set_tsk_thread_flag(p, TIF_MEMDIE);
-               boost_dying_task_prio(p, mem);
                return 0;
        }
 
@@ -556,7 +533,6 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
         */
        if (fatal_signal_pending(current)) {
                set_thread_flag(TIF_MEMDIE);
-               boost_dying_task_prio(current, NULL);
                return;
        }
 
@@ -712,7 +688,6 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
         */
        if (fatal_signal_pending(current)) {
                set_thread_flag(TIF_MEMDIE);
-               boost_dying_task_prio(current, NULL);
                return;
        }
 
index 2747f5e5abc15f9d56472d2b73b823e9e091e7cd..9f8a97b9a350d17ec070d5e741c04f8d9998e7a8 100644 (file)
@@ -3176,7 +3176,7 @@ static __init_refok int __build_all_zonelists(void *data)
  * Called with zonelists_mutex held always
  * unless system_state == SYSTEM_BOOTING.
  */
-void build_all_zonelists(void *data)
+void __ref build_all_zonelists(void *data)
 {
        set_zonelist_order();
 
index 58da7c150ba6d7b4132f423663ff920345038d7c..8fa27e4e582a236886eba7d875e6c612130468fc 100644 (file)
@@ -421,7 +421,8 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
                 * a waste to allocate index if we cannot allocate data.
                 */
                if (sbinfo->max_blocks) {
-                       if (percpu_counter_compare(&sbinfo->used_blocks, (sbinfo->max_blocks - 1)) > 0)
+                       if (percpu_counter_compare(&sbinfo->used_blocks,
+                                               sbinfo->max_blocks - 1) >= 0)
                                return ERR_PTR(-ENOSPC);
                        percpu_counter_inc(&sbinfo->used_blocks);
                        spin_lock(&inode->i_lock);
@@ -1397,7 +1398,8 @@ repeat:
                shmem_swp_unmap(entry);
                sbinfo = SHMEM_SB(inode->i_sb);
                if (sbinfo->max_blocks) {
-                       if ((percpu_counter_compare(&sbinfo->used_blocks, sbinfo->max_blocks) > 0) ||
+                       if (percpu_counter_compare(&sbinfo->used_blocks,
+                                               sbinfo->max_blocks) >= 0 ||
                            shmem_acct_block(info->flags)) {
                                spin_unlock(&info->lock);
                                error = -ENOSPC;
index 94d2a33a866e153830bfd1dbb285e26006262f6f..9d2e5e46bf09b85f6038232b6b3f32f928862ea4 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1940,7 +1940,7 @@ redo:
                 * Since this is without lock semantics the protection is only against
                 * code executing on this cpu *not* from access by other cpus.
                 */
-               if (unlikely(!this_cpu_cmpxchg_double(
+               if (unlikely(!irqsafe_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
                                object, tid,
                                get_freepointer(s, object), next_tid(tid)))) {
@@ -2145,7 +2145,7 @@ redo:
                set_freepointer(s, object, c->freelist);
 
 #ifdef CONFIG_CMPXCHG_LOCAL
-               if (unlikely(!this_cpu_cmpxchg_double(
+               if (unlikely(!irqsafe_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
                                c->freelist, tid,
                                object, next_tid(tid)))) {
index c7f5a6d4b75bfff6cc10d7e9b91a79590cd3aea6..f6b435c80079337489b17122f0d0ab1b829e12c3 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/memcontrol.h>
 #include <linux/delayacct.h>
 #include <linux/sysctl.h>
+#include <linux/oom.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1988,17 +1989,12 @@ static bool zone_reclaimable(struct zone *zone)
        return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
 }
 
-/*
- * As hibernation is going on, kswapd is freezed so that it can't mark
- * the zone into all_unreclaimable. It can't handle OOM during hibernation.
- * So let's check zone's unreclaimable in direct reclaim as well as kswapd.
- */
+/* All zones in zonelist are unreclaimable? */
 static bool all_unreclaimable(struct zonelist *zonelist,
                struct scan_control *sc)
 {
        struct zoneref *z;
        struct zone *zone;
-       bool all_unreclaimable = true;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                        gfp_zone(sc->gfp_mask), sc->nodemask) {
@@ -2006,13 +2002,11 @@ static bool all_unreclaimable(struct zonelist *zonelist,
                        continue;
                if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                        continue;
-               if (zone_reclaimable(zone)) {
-                       all_unreclaimable = false;
-                       break;
-               }
+               if (!zone->all_unreclaimable)
+                       return false;
        }
 
-       return all_unreclaimable;
+       return true;
 }
 
 /*
@@ -2108,6 +2102,14 @@ out:
        if (sc->nr_reclaimed)
                return sc->nr_reclaimed;
 
+       /*
+        * As hibernation is going on, kswapd is freezed so that it can't mark
+        * the zone into all_unreclaimable. Thus bypassing all_unreclaimable
+        * check.
+        */
+       if (oom_killer_disabled)
+               return 0;
+
        /* top priority shrink_zones still had more to do? don't OOM, then */
        if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc))
                return 1;
index 772b39b87d955078b4f0d7a1b7114751e0ef9a74..897ea9e88238d1a9ffd99c4f35124988bbc85ef0 100644 (file)
@@ -321,9 +321,12 @@ static inline void mod_state(struct zone *zone,
                /*
                 * The fetching of the stat_threshold is racy. We may apply
                 * a counter threshold to the wrong the cpu if we get
-                * rescheduled while executing here. However, the following
-                * will apply the threshold again and therefore bring the
-                * counter under the threshold.
+                * rescheduled while executing here. However, the next
+                * counter update will apply the threshold again and
+                * therefore bring the counter under the threshold again.
+                *
+                * Most of the time the thresholds are the same anyways
+                * for all cpus in a zone.
                 */
                t = this_cpu_read(pcp->stat_threshold);
 
@@ -945,7 +948,16 @@ static const char * const vmstat_text[] = {
        "unevictable_pgs_cleared",
        "unevictable_pgs_stranded",
        "unevictable_pgs_mlockfreed",
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       "thp_fault_alloc",
+       "thp_fault_fallback",
+       "thp_collapse_alloc",
+       "thp_collapse_alloc_failed",
+       "thp_split",
 #endif
+
+#endif /* CONFIG_VM_EVENTS_COUNTERS */
 };
 
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
index 48b8e084e710c30aa2984307aeaff94ed8571152..77367745be9bd4d03c3b7100c8108d71c8536d98 100644 (file)
@@ -929,15 +929,15 @@ error:
 }
 EXPORT_SYMBOL(p9_client_attach);
 
-struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
-       int clone)
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
+               char **wnames, int clone)
 {
        int err;
        struct p9_client *clnt;
        struct p9_fid *fid;
        struct p9_qid *wqids;
        struct p9_req_t *req;
-       int16_t nwqids, count;
+       uint16_t nwqids, count;
 
        err = 0;
        wqids = NULL;
@@ -955,7 +955,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
                fid = oldfid;
 
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
                oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
 
        req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
@@ -1220,27 +1220,6 @@ error:
 }
 EXPORT_SYMBOL(p9_client_fsync);
 
-int p9_client_sync_fs(struct p9_fid *fid)
-{
-       int err = 0;
-       struct p9_req_t *req;
-       struct p9_client *clnt;
-
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid);
-
-       clnt = fid->clnt;
-       req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid);
-       if (IS_ERR(req)) {
-               err = PTR_ERR(req);
-               goto error;
-       }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid);
-       p9_free_req(clnt, req);
-error:
-       return err;
-}
-EXPORT_SYMBOL(p9_client_sync_fs);
-
 int p9_client_clunk(struct p9_fid *fid)
 {
        int err;
index 8a4084fa8b5a907df17db9b023c215d1bb7da772..b58a501cf3d124a06939d266002bf48a92863ee1 100644 (file)
@@ -265,7 +265,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                        }
                        break;
                case 'T':{
-                               int16_t *nwname = va_arg(ap, int16_t *);
+                               uint16_t *nwname = va_arg(ap, uint16_t *);
                                char ***wnames = va_arg(ap, char ***);
 
                                errcode = p9pdu_readf(pdu, proto_version,
@@ -468,7 +468,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                case 'E':{
                                 int32_t cnt = va_arg(ap, int32_t);
                                 const char *k = va_arg(ap, const void *);
-                                const char *u = va_arg(ap, const void *);
+                                const char __user *u = va_arg(ap,
+                                                       const void __user *);
                                 errcode = p9pdu_writef(pdu, proto_version, "d",
                                                 cnt);
                                 if (!errcode && pdu_write_urw(pdu, k, u, cnt))
@@ -495,7 +496,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                        }
                        break;
                case 'T':{
-                               int16_t nwname = va_arg(ap, int);
+                               uint16_t nwname = va_arg(ap, int);
                                const char **wnames = va_arg(ap, const char **);
 
                                errcode = p9pdu_writef(pdu, proto_version, "w",
index d47880e971dd534ec92d3fecbed8a50d35649ab7..e883172f9aa2c1096d363483f252a603bba7f108 100644 (file)
@@ -66,7 +66,7 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
        uint32_t pdata_mapped_pages;
        struct trans_rpage_info  *rpinfo;
 
-       *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1);
+       *pdata_off = (__force size_t)req->tc->pubuf & (PAGE_SIZE-1);
 
        if (*pdata_off)
                first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off),
index e8f046b071821636daf99ae9ef79e88f28ef7a09..244e70742183dd689c347166885905baa1584e43 100644 (file)
@@ -326,8 +326,11 @@ req_retry_pinned:
                        outp = pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
                                        pdata_off, rpinfo->rp_data, pdata_len);
                } else {
-                       char *pbuf = req->tc->pubuf ? req->tc->pubuf :
-                                                               req->tc->pkbuf;
+                       char *pbuf;
+                       if (req->tc->pubuf)
+                               pbuf = (__force char *) req->tc->pubuf;
+                       else
+                               pbuf = req->tc->pkbuf;
                        outp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, pbuf,
                                        req->tc->pbuf_size);
                }
@@ -352,8 +355,12 @@ req_retry_pinned:
                        in = pack_sg_list_p(chan->sg, out+inp, VIRTQUEUE_NUM,
                                        pdata_off, rpinfo->rp_data, pdata_len);
                } else {
-                       char *pbuf = req->tc->pubuf ? req->tc->pubuf :
-                                                               req->tc->pkbuf;
+                       char *pbuf;
+                       if (req->tc->pubuf)
+                               pbuf = (__force char *) req->tc->pubuf;
+                       else
+                               pbuf = req->tc->pkbuf;
+
                        in = pack_sg_list(chan->sg, out+inp, VIRTQUEUE_NUM,
                                        pbuf, req->tc->pbuf_size);
                }
index c83f618282f709e424bc30af470139e77586dd66..b5a8afc2be331f5ac5b26649e4609e21039f8b85 100644 (file)
@@ -587,10 +587,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        hci_req_cancel(hdev, ENODEV);
        hci_req_lock(hdev);
 
-       /* Stop timer, it might be running */
-       del_timer_sync(&hdev->cmd_timer);
-
        if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
+               del_timer_sync(&hdev->cmd_timer);
                hci_req_unlock(hdev);
                return 0;
        }
@@ -629,6 +627,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 
        /* Drop last sent command */
        if (hdev->sent_cmd) {
+               del_timer_sync(&hdev->cmd_timer);
                kfree_skb(hdev->sent_cmd);
                hdev->sent_cmd = NULL;
        }
index cebe7588469fe8a82150d7dd26bea5a981cdfbb1..b2570159a04418bf213a512f6f1e1589faf7ff8a 100644 (file)
@@ -2387,8 +2387,6 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s
        if (!conn)
                goto unlock;
 
-       hci_conn_hold(conn);
-
        conn->remote_cap = ev->capability;
        conn->remote_oob = ev->oob_data;
        conn->remote_auth = ev->authentication;
index ca27f3a41536f35d4d608f9f0929b50105658f4d..2c8dd4494c63966ffd0e5df4f66546139dea2f81 100644 (file)
@@ -1051,6 +1051,7 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
        tx_skb = skb_clone(skb, GFP_ATOMIC);
        bt_cb(skb)->retries++;
        control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+       control &= L2CAP_CTRL_SAR;
 
        if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
                control |= L2CAP_CTRL_FINAL;
index 42fdffd1d76c0c17c5ab3382b94ea5bf4fcc62c9..94954c74f6ae61e5df6a5bcf9bb301300bd37eda 100644 (file)
@@ -369,6 +369,15 @@ static void __sco_sock_close(struct sock *sk)
 
        case BT_CONNECTED:
        case BT_CONFIG:
+               if (sco_pi(sk)->conn) {
+                       sk->sk_state = BT_DISCONN;
+                       sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
+                       hci_conn_put(sco_pi(sk)->conn->hcon);
+                       sco_pi(sk)->conn = NULL;
+               } else
+                       sco_chan_del(sk, ECONNRESET);
+               break;
+
        case BT_CONNECT:
        case BT_DISCONN:
                sco_chan_del(sk, ECONNRESET);
index e2160792e1bce49869fb5137a73deeabed8e1135..0c7badad62af07ab3e983c0871311a9212c481a3 100644 (file)
@@ -164,7 +164,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
                        goto drop;
 
                /* If STP is turned off, then forward */
-               if (p->br->stp_enabled == BR_NO_STP)
+               if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
                        goto forward;
 
                if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
index 008ff6c4eecf3da16c55901afd9e9fbde9f5ee2f..f3bc322c589128d14d6367368597f6da66958bcb 100644 (file)
@@ -249,11 +249,9 @@ static int br_parse_ip_options(struct sk_buff *skb)
                goto drop;
        }
 
-       /* Zero out the CB buffer if no options present */
-       if (iph->ihl == 5) {
-               memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+       memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+       if (iph->ihl == 5)
                return 0;
-       }
 
        opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
        if (ip_options_compile(dev_net(dev), opt, skb))
index 27dab26ad3b84ff213497bcd9029b7af75688560..054fdb5aeb88073d89293a424fcf7c6458f4bd51 100644 (file)
@@ -13,6 +13,7 @@
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
+
 #define container_obj(layr) ((struct cfsrvl *) layr)
 
 #define DGM_CMD_BIT  0x80
@@ -83,6 +84,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
 {
+       u8 packet_type;
        u32 zero = 0;
        struct caif_payload_info *info;
        struct cfsrvl *service = container_obj(layr);
@@ -94,7 +96,9 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
        if (cfpkt_getlen(pkt) > DGM_MTU)
                return -EMSGSIZE;
 
-       cfpkt_add_head(pkt, &zero, 4);
+       cfpkt_add_head(pkt, &zero, 3);
+       packet_type = 0x08; /* B9 set - UNCLASSIFIED */
+       cfpkt_add_head(pkt, &packet_type, 1);
 
        /* Add info for MUX-layer to route the packet out. */
        info = cfpkt_info(pkt);
index 46f34b2e04784d8fd379384851c3d5b19377ddee..24f1ffa74b06dbc17a751eef251f1c73f111d064 100644 (file)
@@ -244,9 +244,9 @@ static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
                                int phyid)
 {
        struct cfmuxl *muxl = container_obj(layr);
-       struct list_head *node;
+       struct list_head *node, *next;
        struct cflayer *layer;
-       list_for_each(node, &muxl->srvl_list) {
+       list_for_each_safe(node, next, &muxl->srvl_list) {
                layer = list_entry(node, struct cflayer, node);
                if (cfsrvl_phyid_match(layer, phyid))
                        layer->ctrlcmd(layer, ctrl, phyid);
index 57b1aed79014cdd6022fa04175a1344139f57334..8a6a05e7c3c8de434caf5ffbbb42316086c847b2 100644 (file)
@@ -1427,9 +1427,14 @@ static int bcm_init(struct sock *sk)
 static int bcm_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct bcm_sock *bo = bcm_sk(sk);
+       struct bcm_sock *bo;
        struct bcm_op *op, *next;
 
+       if (sk == NULL)
+               return 0;
+
+       bo = bcm_sk(sk);
+
        /* remove bcm_ops, timer, rx_unregister(), etc. */
 
        unregister_netdevice_notifier(&bo->notifier);
index 649acfa7c70a98ceb5fd3f131544f02e3cf838c8..0eb39a7fdf64afff51c7e59bd0985433302c60ee 100644 (file)
@@ -305,7 +305,12 @@ static int raw_init(struct sock *sk)
 static int raw_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct raw_sock *ro = raw_sk(sk);
+       struct raw_sock *ro;
+
+       if (!sk)
+               return 0;
+
+       ro = raw_sk(sk);
 
        unregister_netdevice_notifier(&ro->notifier);
 
index 05f357828a2fb8de1bb2be9f4103c90058484259..e15a82ccc05f69789e162c5caa51d4bb2cc082a5 100644 (file)
@@ -2267,6 +2267,19 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
        m->more_to_follow = false;
        m->pool = NULL;
 
+       /* middle */
+       m->middle = NULL;
+
+       /* data */
+       m->nr_pages = 0;
+       m->page_alignment = 0;
+       m->pages = NULL;
+       m->pagelist = NULL;
+       m->bio = NULL;
+       m->bio_iter = NULL;
+       m->bio_seg = 0;
+       m->trail = NULL;
+
        /* front */
        if (front_len) {
                if (front_len > PAGE_CACHE_SIZE) {
@@ -2286,19 +2299,6 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
        }
        m->front.iov_len = front_len;
 
-       /* middle */
-       m->middle = NULL;
-
-       /* data */
-       m->nr_pages = 0;
-       m->page_alignment = 0;
-       m->pages = NULL;
-       m->pagelist = NULL;
-       m->bio = NULL;
-       m->bio_iter = NULL;
-       m->bio_seg = 0;
-       m->trail = NULL;
-
        dout("ceph_msg_new %p front %d\n", m, front_len);
        return m;
 
index 50af02737a3d216e0b66c23003172163fbd71bbd..6b5dda1cb5df1a7adf6b93a49201b34d81eb8dcb 100644 (file)
@@ -470,8 +470,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                                         snapc, ops,
                                         use_mempool,
                                         GFP_NOFS, NULL, NULL);
-       if (IS_ERR(req))
-               return req;
+       if (!req)
+               return NULL;
 
        /* calculate max write size */
        calc_layout(osdc, vino, layout, off, plen, req, ops);
@@ -579,9 +579,15 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
 
        list_for_each_entry_safe(req, nreq, &osd->o_linger_requests,
                                 r_linger_osd) {
-               __unregister_linger_request(osdc, req);
+               /*
+                * reregister request prior to unregistering linger so
+                * that r_osd is preserved.
+                */
+               BUG_ON(!list_empty(&req->r_req_lru_item));
                __register_request(osdc, req);
-               list_move(&req->r_req_lru_item, &osdc->req_unsent);
+               list_add(&req->r_req_lru_item, &osdc->req_unsent);
+               list_add(&req->r_osd_item, &req->r_osd->o_requests);
+               __unregister_linger_request(osdc, req);
                dout("requeued lingering %p tid %llu osd%d\n", req, req->r_tid,
                     osd->o_osd);
        }
@@ -798,7 +804,7 @@ static void __register_request(struct ceph_osd_client *osdc,
        req->r_request->hdr.tid = cpu_to_le64(req->r_tid);
        INIT_LIST_HEAD(&req->r_req_lru_item);
 
-       dout("register_request %p tid %lld\n", req, req->r_tid);
+       dout("__register_request %p tid %lld\n", req, req->r_tid);
        __insert_request(osdc, req);
        ceph_osdc_get_request(req);
        osdc->num_requests++;
index 956d3b006e8b96598acb655c383de5d964167697..856b6ee9a1d5d5c1d4347d54048ac4f5d6bc73a1 100644 (file)
@@ -4773,7 +4773,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm
                 * is never reached
                 */
                WARN_ON(1);
-               err = -EINVAL;
+               err = -ENOTTY;
                break;
 
        }
@@ -5041,7 +5041,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                /* Set the per device memory buffer space.
                 * Not applicable in our case */
        case SIOCSIFLINK:
-               return -EINVAL;
+               return -ENOTTY;
 
        /*
         *      Unknown or private ioctl.
@@ -5062,7 +5062,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                /* Take care of Wireless Extensions */
                if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
                        return wext_handle_ioctl(net, &ifr, cmd, arg);
-               return -EINVAL;
+               return -ENOTTY;
        }
 }
 
@@ -5203,11 +5203,15 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
        }
 
        /* TSO requires that SG is present as well. */
-       if ((features & NETIF_F_TSO) && !(features & NETIF_F_SG)) {
-               netdev_info(dev, "Dropping NETIF_F_TSO since no SG feature.\n");
-               features &= ~NETIF_F_TSO;
+       if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
+               netdev_info(dev, "Dropping TSO features since no SG feature.\n");
+               features &= ~NETIF_F_ALL_TSO;
        }
 
+       /* TSO ECN requires that TSO is present as well. */
+       if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)
+               features &= ~NETIF_F_TSO_ECN;
+
        /* Software GSO depends on SG. */
        if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) {
                netdev_info(dev, "Dropping NETIF_F_GSO since no SG feature.\n");
index 87bb5f4de0e84601817a0f63733a725ebb478b03..c53ded2a98dfbcd26113a2265fc14f22fa352971 100644 (file)
@@ -41,12 +41,12 @@ config NET_DSA_MV88E6XXX_NEED_PPU
        default n
 
 config NET_DSA_MV88E6131
-       bool "Marvell 88E6095/6095F/6131 ethernet switch chip support"
+       bool "Marvell 88E6085/6095/6095F/6131 ethernet switch chip support"
        select NET_DSA_MV88E6XXX
        select NET_DSA_MV88E6XXX_NEED_PPU
        select NET_DSA_TAG_DSA
        ---help---
-         This enables support for the Marvell 88E6095/6095F/6131
+         This enables support for the Marvell 88E6085/6095/6095F/6131
          ethernet switch chips.
 
 config NET_DSA_MV88E6123_61_65
index 3da418894efcc715ceca776061028c7e7ce4d551..45f7411e90baf02fbed1642676f6448b74d024cb 100644 (file)
@@ -207,8 +207,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
         * mode, but do not enable forwarding of unknown unicasts.
         */
        val = 0x0433;
-       if (p == dsa_upstream_port(ds))
+       if (p == dsa_upstream_port(ds)) {
                val |= 0x0104;
+               /*
+                * On 6085, unknown multicast forward is controlled
+                * here rather than in Port Control 2 register.
+                */
+               if (ps->id == ID_6085)
+                       val |= 0x0008;
+       }
        if (ds->dsa_port_mask & (1 << p))
                val |= 0x0100;
        REG_WRITE(addr, 0x04, val);
@@ -251,10 +258,19 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
         * If this is the upstream port for this switch, enable
         * forwarding of unknown multicast addresses.
         */
-       val = 0x0080 | dsa_upstream_port(ds);
-       if (p == dsa_upstream_port(ds))
-               val |= 0x0040;
-       REG_WRITE(addr, 0x08, val);
+       if (ps->id == ID_6085)
+               /*
+                * on 6085, bits 3:0 are reserved, bit 6 control ARP
+                * mirroring, and multicast forward is handled in
+                * Port Control register.
+                */
+               REG_WRITE(addr, 0x08, 0x0080);
+       else {
+               val = 0x0080 | dsa_upstream_port(ds);
+               if (p == dsa_upstream_port(ds))
+                       val |= 0x0040;
+               REG_WRITE(addr, 0x08, val);
+       }
 
        /*
         * Rate Control: disable ingress rate limiting.
index ce2d33582859df2dd139941f79a70340c4775edc..5761185f884e8d72d32257476e94b273da0190d0 100644 (file)
@@ -1,5 +1,3 @@
 obj-$(CONFIG_IEEE802154) +=    ieee802154.o af_802154.o
 ieee802154-y           := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
 af_802154-y            := af_ieee802154.o raw.o dgram.o
-
-ccflags-y += -Wall -DDEBUG
index 5345b0bee6df816858c1424d0ccb50988d133aa2..cd9ca0811cfaf30a179db870bfe628d4d0261a2e 100644 (file)
@@ -1680,7 +1680,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
                return;
 
        cnf->sysctl = NULL;
-       unregister_sysctl_table(t->sysctl_header);
+       unregister_net_sysctl_table(t->sysctl_header);
        kfree(t->dev_name);
        kfree(t);
 }
index e9013d6c1f513adfbde31e16041a5c82235b6af4..5fe9b8b41df34fe8cdf7af72ce10138a3f92191a 100644 (file)
@@ -1978,9 +1978,6 @@ struct fib_table *fib_trie_table(u32 id)
        t = (struct trie *) tb->tb_data;
        memset(t, 0, sizeof(*t));
 
-       if (id == RT_TABLE_LOCAL)
-               pr_info("IPv4 FIB: Using LC-trie version %s\n", VERSION);
-
        return tb;
 }
 
index 6c0b7f4a3d7d3c97e83a197e16809e6fdb071234..38f23e721b80108d0a9ae3716fca5212cf8f737d 100644 (file)
@@ -73,7 +73,7 @@ int inet_csk_bind_conflict(const struct sock *sk,
                     !sk2->sk_bound_dev_if ||
                     sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
                        if (!reuse || !sk2->sk_reuse ||
-                           ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) {
+                           sk2->sk_state == TCP_LISTEN) {
                                const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
                                if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
                                    sk2_rcv_saddr == sk_rcv_saddr(sk))
@@ -122,8 +122,7 @@ again:
                                            (tb->num_owners < smallest_size || smallest_size == -1)) {
                                                smallest_size = tb->num_owners;
                                                smallest_rover = rover;
-                                               if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 &&
-                                                   !inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+                                               if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
                                                        spin_unlock(&head->lock);
                                                        snum = smallest_rover;
                                                        goto have_snum;
index dd1b20eca1a25fd845e03ecc077a1e0f43412eff..9df4e635fb5fe5d4a0c92526ad68b845094aa39d 100644 (file)
@@ -354,7 +354,8 @@ static void inetpeer_free_rcu(struct rcu_head *head)
 }
 
 /* May be called with local BH enabled. */
-static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base)
+static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base,
+                            struct inet_peer __rcu **stack[PEER_MAXDEPTH])
 {
        int do_free;
 
@@ -368,7 +369,6 @@ static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base)
         * We use refcnt=-1 to alert lockless readers this entry is deleted.
         */
        if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
-               struct inet_peer __rcu **stack[PEER_MAXDEPTH];
                struct inet_peer __rcu ***stackptr, ***delp;
                if (lookup(&p->daddr, stack, base) != p)
                        BUG();
@@ -422,7 +422,7 @@ static struct inet_peer_base *peer_to_base(struct inet_peer *p)
 }
 
 /* May be called with local BH enabled. */
-static int cleanup_once(unsigned long ttl)
+static int cleanup_once(unsigned long ttl, struct inet_peer __rcu **stack[PEER_MAXDEPTH])
 {
        struct inet_peer *p = NULL;
 
@@ -454,7 +454,7 @@ static int cleanup_once(unsigned long ttl)
                 * happen because of entry limits in route cache. */
                return -1;
 
-       unlink_from_pool(p, peer_to_base(p));
+       unlink_from_pool(p, peer_to_base(p), stack);
        return 0;
 }
 
@@ -524,7 +524,7 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
 
        if (base->total >= inet_peer_threshold)
                /* Remove one less-recently-used entry. */
-               cleanup_once(0);
+               cleanup_once(0, stack);
 
        return p;
 }
@@ -540,6 +540,7 @@ static void peer_check_expire(unsigned long dummy)
 {
        unsigned long now = jiffies;
        int ttl, total;
+       struct inet_peer __rcu **stack[PEER_MAXDEPTH];
 
        total = compute_total();
        if (total >= inet_peer_threshold)
@@ -548,7 +549,7 @@ static void peer_check_expire(unsigned long dummy)
                ttl = inet_peer_maxttl
                                - (inet_peer_maxttl - inet_peer_minttl) / HZ *
                                        total / inet_peer_threshold * HZ;
-       while (!cleanup_once(ttl)) {
+       while (!cleanup_once(ttl, stack)) {
                if (jiffies != now)
                        break;
        }
index 28a736f3442f456c1abd7b7d56eb2e9c4ffdb493..2391b24e8251e62e2c71eadad172a673a1e76c2f 100644 (file)
@@ -329,7 +329,7 @@ int ip_options_compile(struct net *net,
                                        pp_ptr = optptr + 2;
                                        goto error;
                                }
-                               if (skb) {
+                               if (rt) {
                                        memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
                                        opt->is_changed = 1;
                                }
@@ -371,7 +371,7 @@ int ip_options_compile(struct net *net,
                                                goto error;
                                        }
                                        opt->ts = optptr - iph;
-                                       if (skb) {
+                                       if (rt)  {
                                                memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
                                                timeptr = (__be32*)&optptr[optptr[2]+3];
                                        }
@@ -603,7 +603,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
        unsigned long orefdst;
        int err;
 
-       if (!opt->srr)
+       if (!opt->srr || !rt)
                return 0;
 
        if (skb->pkt_type != PACKET_HOST)
index c1acf69858fd722e6a755c8bf029a56039605b67..99e6e4bb1c72d044b97ba93ad6c0bd944d170edd 100644 (file)
@@ -2690,6 +2690,12 @@ static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
 
+static u32 *ipv4_rt_blackhole_cow_metrics(struct dst_entry *dst,
+                                         unsigned long old)
+{
+       return NULL;
+}
+
 static struct dst_ops ipv4_dst_blackhole_ops = {
        .family                 =       AF_INET,
        .protocol               =       cpu_to_be16(ETH_P_IP),
@@ -2698,6 +2704,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
        .default_mtu            =       ipv4_blackhole_default_mtu,
        .default_advmss         =       ipv4_default_advmss,
        .update_pmtu            =       ipv4_rt_blackhole_update_pmtu,
+       .cow_metrics            =       ipv4_rt_blackhole_cow_metrics,
 };
 
 struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)
index 1a456652086b7b4837b8e1035f0a96bb12eb6700..321e6e84dbccb93e08741263815aaae82610b0a8 100644 (file)
@@ -311,7 +311,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_do_large_bitmap,
        },
-#ifdef CONFIG_IP_MULTICAST
        {
                .procname       = "igmp_max_memberships",
                .data           = &sysctl_igmp_max_memberships,
@@ -319,8 +318,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-
-#endif
        {
                .procname       = "igmp_max_msf",
                .data           = &sysctl_igmp_max_msf,
index 1493534116df489b8a41411face52d2b06279928..a7bda0757053278e58218766df54cb49fac100d6 100644 (file)
@@ -4537,7 +4537,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
 
        t = p->sysctl;
        p->sysctl = NULL;
-       unregister_sysctl_table(t->sysctl_header);
+       unregister_net_sysctl_table(t->sysctl_header);
        kfree(t->dev_name);
        kfree(t);
 }
index 5aa8ec88f1946296ce4f776f8927f764cf4edbc1..59dccfbb5b11332f7f3957d2fb80a0f94a2784da 100644 (file)
@@ -371,7 +371,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
        iv = esp_tmp_iv(aead, tmp, seqhilen);
        req = esp_tmp_req(aead, iv);
        asg = esp_req_sg(aead, req);
-       sg = asg + 1;
+       sg = asg + sglists;
 
        skb->ip_summed = CHECKSUM_NONE;
 
index 1660546504668a1c0378e23fec57112cc9710826..f2c5b0fc0f218a0294b1c4308a46374bc3410d99 100644 (file)
@@ -44,7 +44,7 @@ int inet6_csk_bind_conflict(const struct sock *sk,
                     !sk2->sk_bound_dev_if ||
                     sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
                    (!sk->sk_reuse || !sk2->sk_reuse ||
-                    ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) &&
+                    sk2->sk_state == TCP_LISTEN) &&
                     ipv6_rcv_saddr_equal(sk, sk2))
                        break;
        }
index 843406f14d7b2b37ac33b039f52fe80feb132cba..fd0eec6f88c6d71d9eba6f1d104001d23bcb2721 100644 (file)
@@ -153,6 +153,12 @@ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
 
+static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
+                                        unsigned long old)
+{
+       return NULL;
+}
+
 static struct dst_ops ip6_dst_blackhole_ops = {
        .family                 =       AF_INET6,
        .protocol               =       cpu_to_be16(ETH_P_IPV6),
@@ -161,6 +167,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
        .default_mtu            =       ip6_blackhole_default_mtu,
        .default_advmss         =       ip6_default_advmss,
        .update_pmtu            =       ip6_rt_blackhole_update_pmtu,
+       .cow_metrics            =       ip6_rt_blackhole_cow_metrics,
 };
 
 static const u32 ip6_template_metrics[RTAX_MAX] = {
@@ -2012,7 +2019,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        rt->dst.output = ip6_output;
        rt->rt6i_dev = net->loopback_dev;
        rt->rt6i_idev = idev;
-       dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1);
        rt->dst.obsolete = -1;
 
        rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
index 15c37746845ed1ad678866756b4057421b7f3f0a..9e305d74b3d41a99a065da67fe54bd3a4a9ebaa6 100644 (file)
@@ -1335,7 +1335,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Check if there is enough headroom to insert fragment header. */
-       if ((skb_headroom(skb) < frag_hdr_sz) &&
+       if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
            pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
                goto out;
 
index c9890e25cd4c9681b14f838976a97ed4db560ac7..cc616974a447d582a66c837a09c8c95b1fb8900a 100644 (file)
@@ -1297,8 +1297,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
        /* Note : socket.c set MSG_EOR on SEQPACKET sockets */
        if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
                               MSG_NOSIGNAL)) {
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        lock_sock(sk);
index fce9bd3bd3feb61c3b6a2fbc078d9a5b8f7462c5..5c04f3e42704feda18993bcac15dc29b0f66c933 100644 (file)
@@ -667,7 +667,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("L2TP over IP");
 MODULE_VERSION("1.0");
 
-/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like
+/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
  * enums
  */
 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
index 058f1e9a91281859bf39501619da6eb5ece8d16a..903242111317f14438bc84881358875729e21948 100644 (file)
@@ -121,8 +121,7 @@ static inline int llc_fixup_skb(struct sk_buff *skb)
                s32 data_size = ntohs(pdulen) - llc_len;
 
                if (data_size < 0 ||
-                   ((skb_tail_pointer(skb) -
-                     (u8 *)pdu) - llc_len) < data_size)
+                   !pskb_may_pull(skb, data_size))
                        return 0;
                if (unlikely(pskb_trim_rcsum(skb, data_size)))
                        return 0;
index 334213571ad0ef9257c73a7d6ab81febb3ef9c36..44049733c4eaf6ab450e9ea48e676102669531ba 100644 (file)
@@ -1504,6 +1504,8 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
        enum ieee80211_smps_mode old_req;
        int err;
 
+       lockdep_assert_held(&sdata->u.mgd.mtx);
+
        old_req = sdata->u.mgd.req_smps;
        sdata->u.mgd.req_smps = smps_mode;
 
index dacace6b139301ad5625a738465190e2827af160..9ea7c0d0103f8d9f15fc5b7d04109316ee675ea2 100644 (file)
@@ -177,9 +177,9 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EOPNOTSUPP;
 
-       mutex_lock(&local->iflist_mtx);
+       mutex_lock(&sdata->u.mgd.mtx);
        err = __ieee80211_request_smps(sdata, smps_mode);
-       mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&sdata->u.mgd.mtx);
 
        return err;
 }
index 00a33242e90c2e89994a0711fcae7a61809225e5..a274300b6a566faee28c3e10d31fdba1bbd212c0 100644 (file)
@@ -343,6 +343,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct ipmac data;
 
+       /* MAC can be src only */
+       if (!(flags & IPSET_DIM_TWO_SRC))
+               return 0;
+
        data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
        if (data.id < map->first_ip || data.id > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
index 9152e69a162d75f2e5d779169c2c0b2ab3c6e0d6..72d1ac611fdc8e70124c6fca29686ffa416e9cd3 100644 (file)
@@ -1022,8 +1022,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
        if (cb->args[1] >= ip_set_max)
                goto out;
 
-       pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
        max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
+dump_last:
+       pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
        for (; cb->args[1] < max; cb->args[1]++) {
                index = (ip_set_id_t) cb->args[1];
                set = ip_set_list[index];
@@ -1038,8 +1039,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                 * so that lists (unions of sets) are dumped last.
                 */
                if (cb->args[0] != DUMP_ONE &&
-                   !((cb->args[0] == DUMP_ALL) ^
-                     (set->type->features & IPSET_DUMP_LAST)))
+                   ((cb->args[0] == DUMP_ALL) ==
+                    !!(set->type->features & IPSET_DUMP_LAST)))
                        continue;
                pr_debug("List set: %s\n", set->name);
                if (!cb->args[2]) {
@@ -1083,6 +1084,12 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                        goto release_refcount;
                }
        }
+       /* If we dump all sets, continue with dumping last ones */
+       if (cb->args[0] == DUMP_ALL) {
+               cb->args[0] = DUMP_LAST;
+               cb->args[1] = 0;
+               goto dump_last;
+       }
        goto out;
 
 nla_put_failure:
@@ -1093,11 +1100,6 @@ release_refcount:
                pr_debug("release set %s\n", ip_set_list[index]->name);
                ip_set_put_byindex(index);
        }
-
-       /* If we dump all sets, continue with dumping last ones */
-       if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
-               cb->args[0] = DUMP_LAST;
-
 out:
        if (nlh) {
                nlmsg_end(skb, nlh);
index 061d48cec137e3a88a3a98153d6d5cbd9d1c3464..b3babaed7719b770e02d478091885e7692eac68a 100644 (file)
@@ -81,6 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
        if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
                pr_warning("Protocol error: set match dimension "
                           "is over the limit!\n");
+               ip_set_nfnl_put(info->match_set.index);
                return -ERANGE;
        }
 
@@ -135,6 +136,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
                if (index == IPSET_INVALID_ID) {
                        pr_warning("Cannot find del_set index %u as target\n",
                                   info->del_set.index);
+                       if (info->add_set.index != IPSET_INVALID_ID)
+                               ip_set_nfnl_put(info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -142,6 +145,10 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
            info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
                pr_warning("Protocol error: SET target dimension "
                           "is over the limit!\n");
+               if (info->add_set.index != IPSET_INVALID_ID)
+                       ip_set_nfnl_put(info->add_set.index);
+               if (info->del_set.index != IPSET_INVALID_ID)
+                       ip_set_nfnl_put(info->del_set.index);
                return -ERANGE;
        }
 
@@ -192,6 +199,7 @@ set_match_checkentry(const struct xt_mtchk_param *par)
        if (info->match_set.dim > IPSET_DIM_MAX) {
                pr_warning("Protocol error: set match dimension "
                           "is over the limit!\n");
+               ip_set_nfnl_put(info->match_set.index);
                return -ERANGE;
        }
 
@@ -219,7 +227,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par)
        if (info->del_set.index != IPSET_INVALID_ID)
                ip_set_del(info->del_set.index,
                           skb, par->family,
-                          info->add_set.dim,
+                          info->del_set.dim,
                           info->del_set.flags);
 
        return XT_CONTINUE;
@@ -245,13 +253,19 @@ set_target_checkentry(const struct xt_tgchk_param *par)
                if (index == IPSET_INVALID_ID) {
                        pr_warning("Cannot find del_set index %u as target\n",
                                   info->del_set.index);
+                       if (info->add_set.index != IPSET_INVALID_ID)
+                               ip_set_nfnl_put(info->add_set.index);
                        return -ENOENT;
                }
        }
        if (info->add_set.dim > IPSET_DIM_MAX ||
-           info->del_set.flags > IPSET_DIM_MAX) {
+           info->del_set.dim > IPSET_DIM_MAX) {
                pr_warning("Protocol error: SET target dimension "
                           "is over the limit!\n");
+               if (info->add_set.index != IPSET_INVALID_ID)
+                       ip_set_nfnl_put(info->add_set.index);
+               if (info->del_set.index != IPSET_INVALID_ID)
+                       ip_set_nfnl_put(info->del_set.index);
                return -ERANGE;
        }
 
index 0698cad6176367c5a0ad6dffefcf07133304e9fb..1a21c571aa034fc90db2a38d4606681af03f0669 100644 (file)
@@ -569,6 +569,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
                sctp_assoc_set_primary(asoc, transport);
        if (asoc->peer.active_path == peer)
                asoc->peer.active_path = transport;
+       if (asoc->peer.retran_path == peer)
+               asoc->peer.retran_path = transport;
        if (asoc->peer.last_data_from == peer)
                asoc->peer.last_data_from = transport;
 
@@ -1323,6 +1325,8 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
 
        if (t)
                asoc->peer.retran_path = t;
+       else
+               t = asoc->peer.retran_path;
 
        SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
                                 " %p addr: ",
index dff27d5e22fdbe57433489cecb7cb70df8328449..61b1f5ada96a92aeb403c02c64694cb5e801106c 100644 (file)
@@ -554,7 +554,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
        memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
 
        /* Per TSVWG discussion with Randy. Allow the application to
-        * resemble a fragmented message.
+        * reassemble a fragmented message.
         */
        ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
 
index 8873fd8ddacd261ac03bc1bb7d5b7a236579baee..b2198e65d8bbec47798ccd841707e40c844dc908 100644 (file)
@@ -18,14 +18,13 @@ config SUNRPC_XPRT_RDMA
          If unsure, say N.
 
 config RPCSEC_GSS_KRB5
-       tristate
+       tristate "Secure RPC: Kerberos V mechanism"
        depends on SUNRPC && CRYPTO
-       prompt "Secure RPC: Kerberos V mechanism" if !(NFS_V4 || NFSD_V4)
+       depends on CRYPTO_MD5 && CRYPTO_DES && CRYPTO_CBC && CRYPTO_CTS
+       depends on CRYPTO_ECB && CRYPTO_HMAC && CRYPTO_SHA1 && CRYPTO_AES
+       depends on CRYPTO_ARC4
        default y
        select SUNRPC_GSS
-       select CRYPTO_MD5
-       select CRYPTO_DES
-       select CRYPTO_CBC
        help
          Choose Y here to enable Secure RPC using the Kerberos version 5
          GSS-API mechanism (RFC 1964).
index f3914d0c5079596d04af62417ca909693675a64f..339ba64cce1e2ee7134a2c9d09cd64f5fb9cb85e 100644 (file)
@@ -520,7 +520,7 @@ gss_refresh_upcall(struct rpc_task *task)
                warn_gssd();
                task->tk_timeout = 15*HZ;
                rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL);
-               return 0;
+               return -EAGAIN;
        }
        if (IS_ERR(gss_msg)) {
                err = PTR_ERR(gss_msg);
@@ -563,10 +563,12 @@ retry:
        if (PTR_ERR(gss_msg) == -EAGAIN) {
                err = wait_event_interruptible_timeout(pipe_version_waitqueue,
                                pipe_version >= 0, 15*HZ);
+               if (pipe_version < 0) {
+                       warn_gssd();
+                       err = -EACCES;
+               }
                if (err)
                        goto out;
-               if (pipe_version < 0)
-                       warn_gssd();
                goto retry;
        }
        if (IS_ERR(gss_msg)) {
index e7a96e478f63a74da8e90e0f80748857f5c18fb0..8d83f9d487130bb7789fe0dc53201ec3aedc5a95 100644 (file)
@@ -1508,7 +1508,10 @@ call_timeout(struct rpc_task *task)
                if (clnt->cl_chatty)
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
                                clnt->cl_protname, clnt->cl_server);
-               rpc_exit(task, -EIO);
+               if (task->tk_flags & RPC_TASK_TIMEOUT)
+                       rpc_exit(task, -ETIMEDOUT);
+               else
+                       rpc_exit(task, -EIO);
                return;
        }
 
index 9494c376735618c0f67fb3b9a0f88c70875062a4..ce5eb68a9664f6a93776304b304c80029efce84d 100644 (file)
@@ -906,6 +906,7 @@ void xprt_transmit(struct rpc_task *task)
        }
 
        dprintk("RPC: %5u xmit complete\n", task->tk_pid);
+       task->tk_flags |= RPC_TASK_SENT;
        spin_lock_bh(&xprt->transport_lock);
 
        xprt->ops->set_retrans_timeout(task);
index 3a43a830476884464abbaba9eae091b166ecabe8..b1d75beb7e20e8e3155a84be37161871023396ac 100644 (file)
@@ -524,6 +524,8 @@ static int unix_dgram_connect(struct socket *, struct sockaddr *,
                              int, int);
 static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
                                  struct msghdr *, size_t);
+static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
+                                 struct msghdr *, size_t, int);
 
 static const struct proto_ops unix_stream_ops = {
        .family =       PF_UNIX,
@@ -583,7 +585,7 @@ static const struct proto_ops unix_seqpacket_ops = {
        .setsockopt =   sock_no_setsockopt,
        .getsockopt =   sock_no_getsockopt,
        .sendmsg =      unix_seqpacket_sendmsg,
-       .recvmsg =      unix_dgram_recvmsg,
+       .recvmsg =      unix_seqpacket_recvmsg,
        .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
 };
@@ -1699,6 +1701,18 @@ static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock,
        return unix_dgram_sendmsg(kiocb, sock, msg, len);
 }
 
+static int unix_seqpacket_recvmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t size,
+                             int flags)
+{
+       struct sock *sk = sock->sk;
+
+       if (sk->sk_state != TCP_ESTABLISHED)
+               return -ENOTCONN;
+
+       return unix_dgram_recvmsg(iocb, sock, msg, size, flags);
+}
+
 static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
 {
        struct unix_sock *u = unix_sk(sk);
index f218385950ca06a3a8b6830c51c29ac370ca2ea0..e8a781422feb46b9c456438c47a3324dc7edcdbf 100644 (file)
@@ -532,7 +532,7 @@ int xfrm_init_replay(struct xfrm_state *x)
 
        if (replay_esn) {
                if (replay_esn->replay_window >
-                   replay_esn->bmp_len * sizeof(__u32))
+                   replay_esn->bmp_len * sizeof(__u32) * 8)
                        return -EINVAL;
 
        if ((x->props.flags & XFRM_STATE_ESN) && x->replay_esn)
index 5d1d60d3ca832c419bd41bf7b70d84bacb222494..c658cb3bc7c3ccf213fffee288f8b211a2c93293 100644 (file)
@@ -124,6 +124,9 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
 {
        struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
 
+       if ((p->flags & XFRM_STATE_ESN) && !rt)
+               return -EINVAL;
+
        if (!rt)
                return 0;
 
index 659326c3e89579b09f86077dbcbe5e1eb3a12d28..006ad817cd5f003023a7308b471eb9c4e46ba5de 100644 (file)
@@ -332,7 +332,7 @@ static int conf_choice(struct menu *menu)
                }
                if (!child)
                        continue;
-               if (line[strlen(line) - 1] == '?') {
+               if (line[0] && line[strlen(line) - 1] == '?') {
                        print_help(child);
                        continue;
                }
index 2984ea4f776f0c6cd683d36eb64d096be1ebe337..bbb51156261b723904499c81d563e5632e758bb2 100644 (file)
@@ -181,7 +181,7 @@ static int cap_inode_follow_link(struct dentry *dentry,
        return 0;
 }
 
-static int cap_inode_permission(struct inode *inode, int mask)
+static int cap_inode_permission(struct inode *inode, int mask, unsigned flags)
 {
        return 0;
 }
index 101142369db45c0846ca3dbe064b90a2ea83fbf9..4ba6d4cc061f294142b126b962a99986a1285a6c 100644 (file)
@@ -518,16 +518,14 @@ int security_inode_permission(struct inode *inode, int mask)
 {
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
-       return security_ops->inode_permission(inode, mask);
+       return security_ops->inode_permission(inode, mask, 0);
 }
 
 int security_inode_exec_permission(struct inode *inode, unsigned int flags)
 {
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
-       if (flags)
-               return -ECHILD;
-       return security_ops->inode_permission(inode, MAY_EXEC);
+       return security_ops->inode_permission(inode, MAY_EXEC, flags);
 }
 
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
index 9da6420e2056541f330d85e41be66f4742691e2b..1d027e29ce8d5400c9d4a681d52f2f28025aacd2 100644 (file)
@@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
  * @avd: access vector decisions
  * @result: result from avc_has_perm_noaudit
  * @a:  auxiliary audit data
+ * @flags: VFS walk flags
  *
  * Audit the granting or denial of permissions in accordance
  * with the policy.  This function is typically called by
@@ -481,9 +482,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
  * be performed under a lock, to allow the lock to be released
  * before calling the auditing code.
  */
-void avc_audit(u32 ssid, u32 tsid,
+int avc_audit(u32 ssid, u32 tsid,
               u16 tclass, u32 requested,
-              struct av_decision *avd, int result, struct common_audit_data *a)
+              struct av_decision *avd, int result, struct common_audit_data *a,
+              unsigned flags)
 {
        struct common_audit_data stack_data;
        u32 denied, audited;
@@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid,
        else
                audited = requested & avd->auditallow;
        if (!audited)
-               return;
+               return 0;
+
        if (!a) {
                a = &stack_data;
                COMMON_AUDIT_DATA_INIT(a, NONE);
        }
+
+       /*
+        * When in a RCU walk do the audit on the RCU retry.  This is because
+        * the collection of the dname in an inode audit message is not RCU
+        * safe.  Note this may drop some audits when the situation changes
+        * during retry. However this is logically just as if the operation
+        * happened a little later.
+        */
+       if ((a->type == LSM_AUDIT_DATA_FS) &&
+           (flags & IPERM_FLAG_RCU))
+               return -ECHILD;
+
        a->selinux_audit_data.tclass = tclass;
        a->selinux_audit_data.requested = requested;
        a->selinux_audit_data.ssid = ssid;
@@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid,
        a->lsm_pre_audit = avc_audit_pre_callback;
        a->lsm_post_audit = avc_audit_post_callback;
        common_lsm_audit(a);
+       return 0;
 }
 
 /**
@@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * @tclass: target security class
  * @requested: requested permissions, interpreted based on @tclass
  * @auditdata: auxiliary audit data
+ * @flags: VFS walk flags
  *
  * Check the AVC to determine whether the @requested permissions are granted
  * for the SID pair (@ssid, @tsid), interpreting the permissions
@@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * permissions are granted, -%EACCES if any permissions are denied, or
  * another -errno upon other errors.
  */
-int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
-                u32 requested, struct common_audit_data *auditdata)
+int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
+                      u32 requested, struct common_audit_data *auditdata,
+                      unsigned flags)
 {
        struct av_decision avd;
-       int rc;
+       int rc, rc2;
 
        rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
-       avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+
+       rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
+                       flags);
+       if (rc2)
+               return rc2;
        return rc;
 }
 
index f9c3764e48590e5737a0afddb63043b25675f23b..8fb248843009de5e6b71a01cae7b884cd597ba36 100644 (file)
@@ -1446,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk,
        }
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
-       if (audit == SECURITY_CAP_AUDIT)
-               avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+       if (audit == SECURITY_CAP_AUDIT) {
+               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+               if (rc2)
+                       return rc2;
+       }
        return rc;
 }
 
@@ -1467,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct common_audit_data *adp)
+                         struct common_audit_data *adp,
+                         unsigned flags)
 {
        struct inode_security_struct *isec;
        struct common_audit_data ad;
@@ -1487,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred,
                ad.u.fs.inode = inode;
        }
 
-       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
+       return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1504,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred,
        COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
-       return inode_has_perm(cred, inode, av, &ad);
+       return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1540,7 +1544,7 @@ static int file_has_perm(const struct cred *cred,
        /* av is zero if only checking access to the descriptor. */
        rc = 0;
        if (av)
-               rc = inode_has_perm(cred, inode, av, &ad);
+               rc = inode_has_perm(cred, inode, av, &ad, 0);
 
 out:
        return rc;
@@ -1574,7 +1578,8 @@ static int may_create(struct inode *dir,
                return rc;
 
        if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
-               rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid);
+               rc = security_transition_sid(sid, dsec->sid, tclass,
+                                            &dentry->d_name, &newsid);
                if (rc)
                        return rc;
        }
@@ -2103,7 +2108,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                        file = file_priv->file;
                        inode = file->f_path.dentry->d_inode;
                        if (inode_has_perm(cred, inode,
-                                          FILE__READ | FILE__WRITE, NULL)) {
+                                          FILE__READ | FILE__WRITE, NULL, 0)) {
                                drop_tty = 1;
                        }
                }
@@ -2635,7 +2640,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
        return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
-static int selinux_inode_permission(struct inode *inode, int mask)
+static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
 {
        const struct cred *cred = current_cred();
        struct common_audit_data ad;
@@ -2657,7 +2662,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 
        perms = file_mask_to_av(inode->i_mode, mask);
 
-       return inode_has_perm(cred, inode, perms, &ad);
+       return inode_has_perm(cred, inode, perms, &ad, flags);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3205,7 +3210,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
+       return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0);
 }
 
 /* task security operations */
index 5615081b73eca403e438678fcea782dc06e580e3..e77b2ac2908b7f754113bb6dd5023427da5f35fb 100644 (file)
@@ -54,11 +54,11 @@ struct avc_cache_stats {
 
 void __init avc_init(void);
 
-void avc_audit(u32 ssid, u32 tsid,
+int avc_audit(u32 ssid, u32 tsid,
               u16 tclass, u32 requested,
               struct av_decision *avd,
               int result,
-              struct common_audit_data *a);
+             struct common_audit_data *a, unsigned flags);
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@@ -66,9 +66,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         unsigned flags,
                         struct av_decision *avd);
 
-int avc_has_perm(u32 ssid, u32 tsid,
-                u16 tclass, u32 requested,
-                struct common_audit_data *auditdata);
+int avc_has_perm_flags(u32 ssid, u32 tsid,
+                      u16 tclass, u32 requested,
+                      struct common_audit_data *auditdata,
+                      unsigned);
+
+static inline int avc_has_perm(u32 ssid, u32 tsid,
+                              u16 tclass, u32 requested,
+                              struct common_audit_data *auditdata)
+{
+       return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0);
+}
 
 u32 avc_policy_seqno(void);
 
index e7b850ad57ee1547018ff37c4c3bb496d6bccb21..e6e7ce0d3d5546a052f1e2a66568536e398c9c1a 100644 (file)
@@ -502,7 +502,7 @@ static int policydb_index(struct policydb *p)
                goto out;
 
        rc = flex_array_prealloc(p->type_val_to_struct_array, 0,
-                                p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO);
+                                p->p_types.nprim, GFP_KERNEL | __GFP_ZERO);
        if (rc)
                goto out;
 
@@ -519,7 +519,7 @@ static int policydb_index(struct policydb *p)
                        goto out;
 
                rc = flex_array_prealloc(p->sym_val_to_name[i],
-                                        0, p->symtab[i].nprim - 1,
+                                        0, p->symtab[i].nprim,
                                         GFP_KERNEL | __GFP_ZERO);
                if (rc)
                        goto out;
@@ -2375,7 +2375,7 @@ int policydb_read(struct policydb *p, void *fp)
                goto bad;
 
        /* preallocate so we don't have to worry about the put ever failing */
-       rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1,
+       rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim,
                                 GFP_KERNEL | __GFP_ZERO);
        if (rc)
                goto bad;
index c6f8fcadae07787f8f04204bff0a34fb7672829e..400a5d5cde6183c9bc3c6d348f58b623e2821b46 100644 (file)
@@ -686,7 +686,7 @@ static int smack_inode_rename(struct inode *old_inode,
  *
  * Returns 0 if access is permitted, -EACCES otherwise
  */
-static int smack_inode_permission(struct inode *inode, int mask)
+static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
 {
        struct smk_audit_info ad;
 
@@ -696,6 +696,10 @@ static int smack_inode_permission(struct inode *inode, int mask)
         */
        if (mask == 0)
                return 0;
+
+       /* May be droppable after audit */
+       if (flags & IPERM_FLAG_RCU)
+               return -ECHILD;
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
        smk_ad_setfield_u_fs_inode(&ad, inode);
        return smk_curacc(smk_of_inode(inode), mask, &ad);
index 58804c7acfcf63acde8c445d33e24ebb5f246d35..fd2188c3df2b4c436c9a6112cbc577c309d2898e 100644 (file)
@@ -170,7 +170,7 @@ static void tas_set_volume(struct tas *tas)
        /* analysing the volume and mixer tables shows
         * that they are similar enough when we shift
         * the mixer table down by 4 bits. The error
-        * is minuscule, in just one item the error
+        * is miniscule, in just one item the error
         * is 1, at a value of 0x07f17b (mixer table
         * value is 0x07f17a) */
        tmp = tas_gaintable[left];
index a08ad57c49b6adf48a6fcc516dd02d62c159f406..5d98194bcad55b6963037d95d35743909517018a 100644 (file)
@@ -365,6 +365,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 
 EXPORT_SYMBOL(snd_ctl_add);
 
+/**
+ * snd_ctl_replace - replace the control instance of the card
+ * @card: the card instance
+ * @kcontrol: the control instance to replace
+ * @add_on_replace: add the control if not already added
+ *
+ * Replaces the given control.  If the given control does not exist
+ * and the add_on_replace flag is set, the control is added.  If the
+ * control exists, it is destroyed first.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ *
+ * It frees automatically the control which cannot be added or replaced.
+ */
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
+                   bool add_on_replace)
+{
+       struct snd_ctl_elem_id id;
+       unsigned int idx;
+       struct snd_kcontrol *old;
+       int ret;
+
+       if (!kcontrol)
+               return -EINVAL;
+       if (snd_BUG_ON(!card || !kcontrol->info)) {
+               ret = -EINVAL;
+               goto error;
+       }
+       id = kcontrol->id;
+       down_write(&card->controls_rwsem);
+       old = snd_ctl_find_id(card, &id);
+       if (!old) {
+               if (add_on_replace)
+                       goto add;
+               up_write(&card->controls_rwsem);
+               ret = -EINVAL;
+               goto error;
+       }
+       ret = snd_ctl_remove(card, old);
+       if (ret < 0) {
+               up_write(&card->controls_rwsem);
+               goto error;
+       }
+add:
+       if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+               up_write(&card->controls_rwsem);
+               ret = -ENOMEM;
+               goto error;
+       }
+       list_add_tail(&kcontrol->list, &card->controls);
+       card->controls_count += kcontrol->count;
+       kcontrol->id.numid = card->last_numid + 1;
+       card->last_numid += kcontrol->count;
+       up_write(&card->controls_rwsem);
+       for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+       return 0;
+
+error:
+       snd_ctl_free_one(kcontrol);
+       return ret;
+}
+EXPORT_SYMBOL(snd_ctl_replace);
+
 /**
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
index a0080aa45ae968dfbcd9607fa39f7b587acc7c33..30ecad41403c1becb741f7312ca247eb96054b8c 100644 (file)
@@ -514,7 +514,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
        id = card->id;
        
        if (*id == '\0')
-               strcpy(id, "default");
+               strcpy(id, "Default");
 
        while (1) {
                if (loops-- == 0) {
index 64449cb8f873774a91eb836973c1ab0a1ad2d9b8..abfeff1611ce271eabe0bd98a1b75f613d626f96 100644 (file)
@@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream)
 #define XRUN_LOG_CNT   10
 
 struct hwptr_log_entry {
+       unsigned int in_interrupt;
        unsigned long jiffies;
        snd_pcm_uframes_t pos;
        snd_pcm_uframes_t period_size;
@@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log {
 };
 
 static void xrun_log(struct snd_pcm_substream *substream,
-                    snd_pcm_uframes_t pos)
+                    snd_pcm_uframes_t pos, int in_interrupt)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
@@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
                        return;
        }
        entry = &log->entries[log->idx];
+       entry->in_interrupt = in_interrupt;
        entry->jiffies = jiffies;
        entry->pos = pos;
        entry->period_size = runtime->period_size;
@@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
                entry = &log->entries[idx];
                if (entry->period_size == 0)
                        break;
-               snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
+               snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
                           "hwptr=%ld/%ld\n",
-                          name, entry->jiffies, (unsigned long)entry->pos,
+                          name, entry->in_interrupt ? "[Q] " : "",
+                          entry->jiffies,
+                          (unsigned long)entry->pos,
                           (unsigned long)entry->period_size,
                           (unsigned long)entry->buffer_size,
                           (unsigned long)entry->old_hw_ptr,
@@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
 #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
 
 #define hw_ptr_error(substream, fmt, args...) do { } while (0)
-#define xrun_log(substream, pos)       do { } while (0)
+#define xrun_log(substream, pos, in_interrupt) do { } while (0)
 #define xrun_log_show(substream)       do { } while (0)
 
 #endif
@@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        }
        pos -= pos % runtime->min_align;
        if (xrun_debug(substream, XRUN_DEBUG_LOG))
-               xrun_log(substream, pos);
+               xrun_log(substream, pos, in_interrupt);
        hw_base = runtime->hw_ptr_base;
        new_hw_ptr = hw_base + pos;
        if (in_interrupt) {
index e486f48660fb00ac21038158805cee228bd42b97..26071489970bebcd8af0aa5f86bd626d01b8f42f 100644 (file)
@@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS
          To compile this driver as a module, choose M here: the module
          will be called snd-firewire-speakers.
 
+config SND_ISIGHT
+       tristate "Apple iSight microphone"
+       select SND_PCM
+       select SND_FIREWIRE_LIB
+       help
+         Say Y here to include support for the front and rear microphones
+         of the Apple iSight web camera.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-isight.
+
 endif # SND_FIREWIRE
index e5b1634d9ad4bcdc593e7c82dcac3b86b024604b..d71ed8935f76603e9a75217d2f34763a3ca03f82 100644 (file)
@@ -1,6 +1,8 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
                         fcp.o cmp.o amdtp.o
 snd-firewire-speakers-objs := speakers.o
+snd-isight-objs := isight.o
 
 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
 obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
+obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
new file mode 100644 (file)
index 0000000..86ee16c
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * Apple iSight audio driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lib.h"
+#include "iso-resources.h"
+#include "packets-buffer.h"
+
+#define OUI_APPLE              0x000a27
+#define MODEL_APPLE_ISIGHT     0x000008
+#define SW_ISIGHT_AUDIO                0x000010
+
+#define REG_AUDIO_ENABLE       0x000
+#define  AUDIO_ENABLE          0x80000000
+#define REG_DEF_AUDIO_GAIN     0x204
+#define REG_GAIN_RAW_START     0x210
+#define REG_GAIN_RAW_END       0x214
+#define REG_GAIN_DB_START      0x218
+#define REG_GAIN_DB_END                0x21c
+#define REG_SAMPLE_RATE_INQUIRY        0x280
+#define REG_ISO_TX_CONFIG      0x300
+#define  SPEED_SHIFT           16
+#define REG_SAMPLE_RATE                0x400
+#define  RATE_48000            0x80000000
+#define REG_GAIN               0x500
+#define REG_MUTE               0x504
+
+#define MAX_FRAMES_PER_PACKET  475
+
+#define QUEUE_LENGTH           20
+
+struct isight {
+       struct snd_card *card;
+       struct fw_unit *unit;
+       struct fw_device *device;
+       u64 audio_base;
+       struct fw_address_handler iris_handler;
+       struct snd_pcm_substream *pcm;
+       struct mutex mutex;
+       struct iso_packets_buffer buffer;
+       struct fw_iso_resources resources;
+       struct fw_iso_context *context;
+       bool pcm_active;
+       bool pcm_running;
+       bool first_packet;
+       int packet_index;
+       u32 total_samples;
+       unsigned int buffer_pointer;
+       unsigned int period_counter;
+       s32 gain_min, gain_max;
+       unsigned int gain_tlv[4];
+};
+
+struct audio_payload {
+       __be32 sample_count;
+       __be32 signature;
+       __be32 sample_total;
+       __be32 reserved;
+       __be16 samples[2 * MAX_FRAMES_PER_PACKET];
+};
+
+MODULE_DESCRIPTION("iSight audio driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+static struct fw_iso_packet audio_packet = {
+       .payload_length = sizeof(struct audio_payload),
+       .interrupt = 1,
+       .header_length = 4,
+};
+
+static void isight_update_pointers(struct isight *isight, unsigned int count)
+{
+       struct snd_pcm_runtime *runtime = isight->pcm->runtime;
+       unsigned int ptr;
+
+       smp_wmb(); /* update buffer data before buffer pointer */
+
+       ptr = isight->buffer_pointer;
+       ptr += count;
+       if (ptr >= runtime->buffer_size)
+               ptr -= runtime->buffer_size;
+       ACCESS_ONCE(isight->buffer_pointer) = ptr;
+
+       isight->period_counter += count;
+       if (isight->period_counter >= runtime->period_size) {
+               isight->period_counter -= runtime->period_size;
+               snd_pcm_period_elapsed(isight->pcm);
+       }
+}
+
+static void isight_samples(struct isight *isight,
+                          const __be16 *samples, unsigned int count)
+{
+       struct snd_pcm_runtime *runtime;
+       unsigned int count1;
+
+       if (!ACCESS_ONCE(isight->pcm_running))
+               return;
+
+       runtime = isight->pcm->runtime;
+       if (isight->buffer_pointer + count <= runtime->buffer_size) {
+               memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+                      samples, count * 4);
+       } else {
+               count1 = runtime->buffer_size - isight->buffer_pointer;
+               memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+                      samples, count1 * 4);
+               samples += count1 * 2;
+               memcpy(runtime->dma_area, samples, (count - count1) * 4);
+       }
+
+       isight_update_pointers(isight, count);
+}
+
+static void isight_pcm_abort(struct isight *isight)
+{
+       unsigned long flags;
+
+       if (ACCESS_ONCE(isight->pcm_active)) {
+               snd_pcm_stream_lock_irqsave(isight->pcm, flags);
+               if (snd_pcm_running(isight->pcm))
+                       snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
+       }
+}
+
+static void isight_dropped_samples(struct isight *isight, unsigned int total)
+{
+       struct snd_pcm_runtime *runtime;
+       u32 dropped;
+       unsigned int count1;
+
+       if (!ACCESS_ONCE(isight->pcm_running))
+               return;
+
+       runtime = isight->pcm->runtime;
+       dropped = total - isight->total_samples;
+       if (dropped < runtime->buffer_size) {
+               if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
+                       memset(runtime->dma_area + isight->buffer_pointer * 4,
+                              0, dropped * 4);
+               } else {
+                       count1 = runtime->buffer_size - isight->buffer_pointer;
+                       memset(runtime->dma_area + isight->buffer_pointer * 4,
+                              0, count1 * 4);
+                       memset(runtime->dma_area, 0, (dropped - count1) * 4);
+               }
+               isight_update_pointers(isight, dropped);
+       } else {
+               isight_pcm_abort(isight);
+       }
+}
+
+static void isight_packet(struct fw_iso_context *context, u32 cycle,
+                         size_t header_length, void *header, void *data)
+{
+       struct isight *isight = data;
+       const struct audio_payload *payload;
+       unsigned int index, length, count, total;
+       int err;
+
+       if (isight->packet_index < 0)
+               return;
+       index = isight->packet_index;
+       payload = isight->buffer.packets[index].buffer;
+       length = be32_to_cpup(header) >> 16;
+
+       if (likely(length >= 16 &&
+                  payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
+               count = be32_to_cpu(payload->sample_count);
+               if (likely(count <= (length - 16) / 4)) {
+                       total = be32_to_cpu(payload->sample_total);
+                       if (unlikely(total != isight->total_samples)) {
+                               if (!isight->first_packet)
+                                       isight_dropped_samples(isight, total);
+                               isight->first_packet = false;
+                               isight->total_samples = total;
+                       }
+
+                       isight_samples(isight, payload->samples, count);
+                       isight->total_samples += count;
+               }
+       }
+
+       err = fw_iso_context_queue(isight->context, &audio_packet,
+                                  &isight->buffer.iso_buffer,
+                                  isight->buffer.packets[index].offset);
+       if (err < 0) {
+               dev_err(&isight->unit->device, "queueing error: %d\n", err);
+               isight_pcm_abort(isight);
+               isight->packet_index = -1;
+               return;
+       }
+
+       if (++index >= QUEUE_LENGTH)
+               index = 0;
+       isight->packet_index = index;
+}
+
+static int isight_connect(struct isight *isight)
+{
+       int ch, err, rcode, errors = 0;
+       __be32 value;
+
+retry_after_bus_reset:
+       ch = fw_iso_resources_allocate(&isight->resources,
+                                      sizeof(struct audio_payload),
+                                      isight->device->max_speed);
+       if (ch < 0) {
+               err = ch;
+               goto error;
+       }
+
+       value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
+       for (;;) {
+               rcode = fw_run_transaction(
+                               isight->device->card,
+                               TCODE_WRITE_QUADLET_REQUEST,
+                               isight->device->node_id,
+                               isight->resources.generation,
+                               isight->device->max_speed,
+                               isight->audio_base + REG_ISO_TX_CONFIG,
+                               &value, 4);
+               if (rcode == RCODE_COMPLETE) {
+                       return 0;
+               } else if (rcode == RCODE_GENERATION) {
+                       fw_iso_resources_free(&isight->resources);
+                       goto retry_after_bus_reset;
+               } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
+                       err = -EIO;
+                       goto err_resources;
+               }
+               msleep(5);
+       }
+
+err_resources:
+       fw_iso_resources_free(&isight->resources);
+error:
+       return err;
+}
+
+static int isight_open(struct snd_pcm_substream *substream)
+{
+       static const struct snd_pcm_hardware hardware = {
+               .info = SNDRV_PCM_INFO_MMAP |
+                       SNDRV_PCM_INFO_MMAP_VALID |
+                       SNDRV_PCM_INFO_BATCH |
+                       SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_BLOCK_TRANSFER,
+               .formats = SNDRV_PCM_FMTBIT_S16_BE,
+               .rates = SNDRV_PCM_RATE_48000,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+               .buffer_bytes_max = 4 * 1024 * 1024,
+               .period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
+               .period_bytes_max = 1024 * 1024,
+               .periods_min = 2,
+               .periods_max = UINT_MAX,
+       };
+       struct isight *isight = substream->private_data;
+
+       substream->runtime->hw = hardware;
+
+       return iso_packets_buffer_init(&isight->buffer, isight->unit,
+                                      QUEUE_LENGTH,
+                                      sizeof(struct audio_payload),
+                                      DMA_FROM_DEVICE);
+}
+
+static int isight_close(struct snd_pcm_substream *substream)
+{
+       struct isight *isight = substream->private_data;
+
+       iso_packets_buffer_destroy(&isight->buffer, isight->unit);
+
+       return 0;
+}
+
+static int isight_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *hw_params)
+{
+       struct isight *isight = substream->private_data;
+       int err;
+
+       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       ACCESS_ONCE(isight->pcm_active) = true;
+
+       return 0;
+}
+
+static int reg_read(struct isight *isight, int offset, __be32 *value)
+{
+       return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
+                                 isight->audio_base + offset, value, 4);
+}
+
+static int reg_write(struct isight *isight, int offset, __be32 value)
+{
+       return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 isight->audio_base + offset, &value, 4);
+}
+
+static void isight_stop_streaming(struct isight *isight)
+{
+       if (!isight->context)
+               return;
+
+       fw_iso_context_stop(isight->context);
+       fw_iso_context_destroy(isight->context);
+       isight->context = NULL;
+       fw_iso_resources_free(&isight->resources);
+       reg_write(isight, REG_AUDIO_ENABLE, 0);
+}
+
+static int isight_hw_free(struct snd_pcm_substream *substream)
+{
+       struct isight *isight = substream->private_data;
+
+       ACCESS_ONCE(isight->pcm_active) = false;
+
+       mutex_lock(&isight->mutex);
+       isight_stop_streaming(isight);
+       mutex_unlock(&isight->mutex);
+
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int isight_start_streaming(struct isight *isight)
+{
+       unsigned int i;
+       int err;
+
+       if (isight->context) {
+               if (isight->packet_index < 0)
+                       isight_stop_streaming(isight);
+               else
+                       return 0;
+       }
+
+       err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
+       if (err < 0)
+               goto error;
+
+       err = isight_connect(isight);
+       if (err < 0)
+               goto error;
+
+       err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
+       if (err < 0)
+               goto err_resources;
+
+       isight->context = fw_iso_context_create(isight->device->card,
+                                               FW_ISO_CONTEXT_RECEIVE,
+                                               isight->resources.channel,
+                                               isight->device->max_speed,
+                                               4, isight_packet, isight);
+       if (IS_ERR(isight->context)) {
+               err = PTR_ERR(isight->context);
+               isight->context = NULL;
+               goto err_resources;
+       }
+
+       for (i = 0; i < QUEUE_LENGTH; ++i) {
+               err = fw_iso_context_queue(isight->context, &audio_packet,
+                                          &isight->buffer.iso_buffer,
+                                          isight->buffer.packets[i].offset);
+               if (err < 0)
+                       goto err_context;
+       }
+
+       isight->first_packet = true;
+       isight->packet_index = 0;
+
+       err = fw_iso_context_start(isight->context, -1, 0,
+                                  FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
+       if (err < 0)
+               goto err_context;
+
+       return 0;
+
+err_context:
+       fw_iso_context_destroy(isight->context);
+       isight->context = NULL;
+err_resources:
+       fw_iso_resources_free(&isight->resources);
+       reg_write(isight, REG_AUDIO_ENABLE, 0);
+error:
+       return err;
+}
+
+static int isight_prepare(struct snd_pcm_substream *substream)
+{
+       struct isight *isight = substream->private_data;
+       int err;
+
+       isight->buffer_pointer = 0;
+       isight->period_counter = 0;
+
+       mutex_lock(&isight->mutex);
+       err = isight_start_streaming(isight);
+       mutex_unlock(&isight->mutex);
+
+       return err;
+}
+
+static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct isight *isight = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               ACCESS_ONCE(isight->pcm_running) = true;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               ACCESS_ONCE(isight->pcm_running) = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
+{
+       struct isight *isight = substream->private_data;
+
+       return ACCESS_ONCE(isight->buffer_pointer);
+}
+
+static int isight_create_pcm(struct isight *isight)
+{
+       static struct snd_pcm_ops ops = {
+               .open      = isight_open,
+               .close     = isight_close,
+               .ioctl     = snd_pcm_lib_ioctl,
+               .hw_params = isight_hw_params,
+               .hw_free   = isight_hw_free,
+               .prepare   = isight_prepare,
+               .trigger   = isight_trigger,
+               .pointer   = isight_pointer,
+               .page      = snd_pcm_lib_get_vmalloc_page,
+               .mmap      = snd_pcm_lib_mmap_vmalloc,
+       };
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
+       if (err < 0)
+               return err;
+       pcm->private_data = isight;
+       strcpy(pcm->name, "iSight");
+       isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       isight->pcm->ops = &ops;
+
+       return 0;
+}
+
+static int isight_gain_info(struct snd_kcontrol *ctl,
+                           struct snd_ctl_elem_info *info)
+{
+       struct isight *isight = ctl->private_data;
+
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 1;
+       info->value.integer.min = isight->gain_min;
+       info->value.integer.max = isight->gain_max;
+
+       return 0;
+}
+
+static int isight_gain_get(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct isight *isight = ctl->private_data;
+       __be32 gain;
+       int err;
+
+       err = reg_read(isight, REG_GAIN, &gain);
+       if (err < 0)
+               return err;
+
+       value->value.integer.value[0] = (s32)be32_to_cpu(gain);
+
+       return 0;
+}
+
+static int isight_gain_put(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct isight *isight = ctl->private_data;
+
+       if (value->value.integer.value[0] < isight->gain_min ||
+           value->value.integer.value[0] > isight->gain_max)
+               return -EINVAL;
+
+       return reg_write(isight, REG_GAIN,
+                        cpu_to_be32(value->value.integer.value[0]));
+}
+
+static int isight_mute_get(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct isight *isight = ctl->private_data;
+       __be32 mute;
+       int err;
+
+       err = reg_read(isight, REG_MUTE, &mute);
+       if (err < 0)
+               return err;
+
+       value->value.integer.value[0] = !mute;
+
+       return 0;
+}
+
+static int isight_mute_put(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct isight *isight = ctl->private_data;
+
+       return reg_write(isight, REG_MUTE,
+                        (__force __be32)!value->value.integer.value[0]);
+}
+
+static int isight_create_mixer(struct isight *isight)
+{
+       static const struct snd_kcontrol_new gain_control = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Capture Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = isight_gain_info,
+               .get = isight_gain_get,
+               .put = isight_gain_put,
+       };
+       static const struct snd_kcontrol_new mute_control = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Capture Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = isight_mute_get,
+               .put = isight_mute_put,
+       };
+       __be32 value;
+       struct snd_kcontrol *ctl;
+       int err;
+
+       err = reg_read(isight, REG_GAIN_RAW_START, &value);
+       if (err < 0)
+               return err;
+       isight->gain_min = be32_to_cpu(value);
+
+       err = reg_read(isight, REG_GAIN_RAW_END, &value);
+       if (err < 0)
+               return err;
+       isight->gain_max = be32_to_cpu(value);
+
+       isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
+       isight->gain_tlv[1] = 2 * sizeof(unsigned int);
+
+       err = reg_read(isight, REG_GAIN_DB_START, &value);
+       if (err < 0)
+               return err;
+       isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100;
+
+       err = reg_read(isight, REG_GAIN_DB_END, &value);
+       if (err < 0)
+               return err;
+       isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100;
+
+       ctl = snd_ctl_new1(&gain_control, isight);
+       if (ctl)
+               ctl->tlv.p = isight->gain_tlv;
+       err = snd_ctl_add(isight->card, ctl);
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void isight_card_free(struct snd_card *card)
+{
+       struct isight *isight = card->private_data;
+
+       fw_iso_resources_destroy(&isight->resources);
+       fw_unit_put(isight->unit);
+       fw_device_put(isight->device);
+       mutex_destroy(&isight->mutex);
+}
+
+static u64 get_unit_base(struct fw_unit *unit)
+{
+       struct fw_csr_iterator i;
+       int key, value;
+
+       fw_csr_iterator_init(&i, unit->directory);
+       while (fw_csr_iterator_next(&i, &key, &value))
+               if (key == CSR_OFFSET)
+                       return CSR_REGISTER_BASE + value * 4;
+       return 0;
+}
+
+static int isight_probe(struct device *unit_dev)
+{
+       struct fw_unit *unit = fw_unit(unit_dev);
+       struct fw_device *fw_dev = fw_parent_device(unit);
+       struct snd_card *card;
+       struct isight *isight;
+       int err;
+
+       err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
+       if (err < 0)
+               return err;
+       snd_card_set_dev(card, unit_dev);
+
+       isight = card->private_data;
+       isight->card = card;
+       mutex_init(&isight->mutex);
+       isight->unit = fw_unit_get(unit);
+       isight->device = fw_device_get(fw_dev);
+       isight->audio_base = get_unit_base(unit);
+       if (!isight->audio_base) {
+               dev_err(&unit->device, "audio unit base not found\n");
+               err = -ENXIO;
+               goto err_unit;
+       }
+       fw_iso_resources_init(&isight->resources, unit);
+
+       card->private_free = isight_card_free;
+
+       strcpy(card->driver, "iSight");
+       strcpy(card->shortname, "Apple iSight");
+       snprintf(card->longname, sizeof(card->longname),
+                "Apple iSight (GUID %08x%08x) at %s, S%d",
+                fw_dev->config_rom[3], fw_dev->config_rom[4],
+                dev_name(&unit->device), 100 << fw_dev->max_speed);
+       strcpy(card->mixername, "iSight");
+
+       err = isight_create_pcm(isight);
+       if (err < 0)
+               goto error;
+
+       err = isight_create_mixer(isight);
+       if (err < 0)
+               goto error;
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dev_set_drvdata(unit_dev, isight);
+
+       return 0;
+
+err_unit:
+       fw_unit_put(isight->unit);
+       fw_device_put(isight->device);
+       mutex_destroy(&isight->mutex);
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static int isight_remove(struct device *dev)
+{
+       struct isight *isight = dev_get_drvdata(dev);
+
+       isight_pcm_abort(isight);
+
+       snd_card_disconnect(isight->card);
+
+       mutex_lock(&isight->mutex);
+       isight_stop_streaming(isight);
+       mutex_unlock(&isight->mutex);
+
+       snd_card_free_when_closed(isight->card);
+
+       return 0;
+}
+
+static void isight_bus_reset(struct fw_unit *unit)
+{
+       struct isight *isight = dev_get_drvdata(&unit->device);
+
+       if (fw_iso_resources_update(&isight->resources) < 0) {
+               isight_pcm_abort(isight);
+
+               mutex_lock(&isight->mutex);
+               isight_stop_streaming(isight);
+               mutex_unlock(&isight->mutex);
+       }
+}
+
+static const struct ieee1394_device_id isight_id_table[] = {
+       {
+               .match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
+                               IEEE1394_MATCH_VERSION,
+               .specifier_id = OUI_APPLE,
+               .version      = SW_ISIGHT_AUDIO,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
+
+static struct fw_driver isight_driver = {
+       .driver   = {
+               .owner  = THIS_MODULE,
+               .name   = KBUILD_MODNAME,
+               .bus    = &fw_bus_type,
+               .probe  = isight_probe,
+               .remove = isight_remove,
+       },
+       .update   = isight_bus_reset,
+       .id_table = isight_id_table,
+};
+
+static int __init alsa_isight_init(void)
+{
+       return driver_register(&isight_driver.driver);
+}
+
+static void __exit alsa_isight_exit(void)
+{
+       driver_unregister(&isight_driver.driver);
+}
+
+module_init(alsa_isight_init);
+module_exit(alsa_isight_exit);
index 775dbd5f34452b76e53086d2f8b6225020cb6ce4..9d4a6714f9ecf724f0f213249e8631fee30af517 100644 (file)
@@ -36,6 +36,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 
        return 0;
 }
+EXPORT_SYMBOL(fw_iso_resources_init);
 
 /**
  * fw_iso_resources_destroy - destroy a resource manager
@@ -48,6 +49,7 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
        mutex_destroy(&r->mutex);
        fw_unit_put(r->unit);
 }
+EXPORT_SYMBOL(fw_iso_resources_destroy);
 
 static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
 {
@@ -152,6 +154,7 @@ retry_after_bus_reset:
 
        return channel;
 }
+EXPORT_SYMBOL(fw_iso_resources_allocate);
 
 /**
  * fw_iso_resources_update - update resource allocations after a bus reset
@@ -203,6 +206,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
 
        return channel;
 }
+EXPORT_SYMBOL(fw_iso_resources_update);
 
 /**
  * fw_iso_resources_free - frees allocated resources
@@ -230,3 +234,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
 
        mutex_unlock(&r->mutex);
 }
+EXPORT_SYMBOL(fw_iso_resources_free);
index 1e20e60ba6a6d869b16b5e4f6ab5080d7021c4f1..3c61ca2e6152472c81e6d59fca0a7e6c3bd1dbca 100644 (file)
@@ -60,6 +60,7 @@ err_packets:
 error:
        return err;
 }
+EXPORT_SYMBOL(iso_packets_buffer_init);
 
 /**
  * iso_packets_buffer_destroy - frees packet buffer resources
@@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
        fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
        kfree(b->packets);
 }
+EXPORT_SYMBOL(iso_packets_buffer_destroy);
index 2dad40f3f6228b86bffe7c01c1eab8904b0ea694..c95d8f1aae87d725ebecacd9c0947ea437421bf7 100644 (file)
@@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
-obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
+obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o
index ee538f1ae8462f0de200d66fa861009fae537a43..4831800239d3b786081de5b17b06bff2e2d8caa9 100644 (file)
@@ -37,8 +37,8 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-#define FREQ_LO                 (87 * 16000)
-#define FREQ_HI                (108 * 16000)
+#define FREQ_LO                 (50UL * 16000)
+#define FREQ_HI                (150UL * 16000)
 
 /*
  * definitions
@@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = {
  * lowlevel part
  */
 
+static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
+{
+       u16 l;
+       u8 data;
+
+       tea->ops->set_direction(tea, 1);
+       udelay(16);
+
+       for (l = 25; l > 0; l--) {
+               data = (val >> 24) & TEA575X_DATA;
+               val <<= 1;                      /* shift data */
+               tea->ops->set_pins(tea, data | TEA575X_WREN);
+               udelay(2);
+               tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
+               udelay(2);
+               tea->ops->set_pins(tea, data | TEA575X_WREN);
+               udelay(2);
+       }
+
+       if (!tea->mute)
+               tea->ops->set_pins(tea, 0);
+}
+
+static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
+{
+       u16 l, rdata;
+       u32 data = 0;
+
+       tea->ops->set_direction(tea, 0);
+       tea->ops->set_pins(tea, 0);
+       udelay(16);
+
+       for (l = 24; l--;) {
+               tea->ops->set_pins(tea, TEA575X_CLK);
+               udelay(2);
+               if (!l)
+                       tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
+               tea->ops->set_pins(tea, 0);
+               udelay(2);
+               data <<= 1;                     /* shift data */
+               rdata = tea->ops->get_pins(tea);
+               if (!l)
+                       tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
+               if (rdata & TEA575X_DATA)
+                       data++;
+               udelay(2);
+       }
+
+       if (tea->mute)
+               tea->ops->set_pins(tea, TEA575X_WREN);
+
+       return data;
+}
+
+static void snd_tea575x_get_freq(struct snd_tea575x *tea)
+{
+       unsigned long freq;
+
+       freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+       /* freq *= 12.5 */
+       freq *= 125;
+       freq /= 10;
+       /* crystal fixup */
+       if (tea->tea5759)
+               freq += TEA575X_FMIF;
+       else
+               freq -= TEA575X_FMIF;
+
+       tea->freq = freq * 16;          /* from kHz */
+}
+
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
        unsigned long freq;
 
-       freq = tea->freq / 16;          /* to kHz */
-       if (freq > 108000)
-               freq = 108000;
-       if (freq < 87000)
-               freq = 87000;
+       freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
+       freq /= 16;             /* to kHz */
        /* crystal fixup */
        if (tea->tea5759)
-               freq -= tea->freq_fixup;
+               freq -= TEA575X_FMIF;
        else
-               freq += tea->freq_fixup;
+               freq += TEA575X_FMIF;
        /* freq /= 12.5 */
        freq *= 10;
        freq /= 125;
 
        tea->val &= ~TEA575X_BIT_FREQ_MASK;
        tea->val |= freq & TEA575X_BIT_FREQ_MASK;
-       tea->ops->write(tea, tea->val);
+       snd_tea575x_write(tea, tea->val);
 }
 
 /*
@@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        struct snd_tea575x *tea = video_drvdata(file);
 
-       strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
        strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
-       strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-       sprintf(v->bus_info, "PCI");
+       strlcpy(v->card, tea->card, sizeof(v->card));
+       strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
+       strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
        v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
+       struct snd_tea575x *tea = video_drvdata(file);
+
        if (v->index > 0)
                return -EINVAL;
 
+       snd_tea575x_read(tea);
+
        strcpy(v->name, "FM");
        v->type = V4L2_TUNER_RADIO;
+       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
        v->rangelow = FREQ_LO;
        v->rangehigh = FREQ_HI;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xffff;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+       v->signal = tea->tuned ? 0xffff : 0;
+
        return 0;
 }
 
@@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
        struct snd_tea575x *tea = video_drvdata(file);
 
+       if (f->tuner != 0)
+               return -EINVAL;
        f->type = V4L2_TUNER_RADIO;
+       snd_tea575x_get_freq(tea);
        f->frequency = tea->freq;
        return 0;
 }
@@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct snd_tea575x *tea = video_drvdata(file);
 
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+
        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
                return -EINVAL;
 
@@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               if (tea->ops->mute) {
-                       ctrl->value = tea->mute;
-                       return 0;
-               }
+               ctrl->value = tea->mute;
+               return 0;
        }
        return -EINVAL;
 }
@@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               if (tea->ops->mute) {
-                       tea->ops->mute(tea, ctrl->value);
+               if (tea->mute != ctrl->value) {
                        tea->mute = ctrl->value;
-                       return 0;
+                       snd_tea575x_set_freq(tea);
                }
+               return 0;
        }
        return -EINVAL;
 }
@@ -293,18 +370,16 @@ static struct video_device tea575x_radio = {
 /*
  * initialize all the tea575x chips
  */
-void snd_tea575x_init(struct snd_tea575x *tea)
+int snd_tea575x_init(struct snd_tea575x *tea)
 {
        int retval;
-       unsigned int val;
        struct video_device *tea575x_radio_inst;
 
-       val = tea->ops->read(tea);
-       if (val == 0x1ffffff || val == 0) {
-               snd_printk(KERN_ERR
-                          "tea575x-tuner: Cannot find TEA575x chip\n");
-               return;
-       }
+       tea->mute = 1;
+
+       snd_tea575x_write(tea, 0x55AA);
+       if (snd_tea575x_read(tea) != 0x55AA)
+               return -ENODEV;
 
        tea->in_use = 0;
        tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
@@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea)
        tea575x_radio_inst = video_device_alloc();
        if (tea575x_radio_inst == NULL) {
                printk(KERN_ERR "tea575x-tuner: not enough memory\n");
-               return;
+               return -ENOMEM;
        }
 
        memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
@@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea)
        if (retval) {
                printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
                kfree(tea575x_radio_inst);
-               return;
+               return retval;
        }
 
        snd_tea575x_set_freq(tea);
-
-       /* mute on init */
-       if (tea->ops->mute) {
-               tea->ops->mute(tea, 1);
-               tea->mute = 1;
-       }
        tea->vd = tea575x_radio_inst;
+
+       return 0;
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
index 76c09021807325944e3edb8b57bc2525e14b306c..6c93e051f9ae6d2fd6eadffe21bac7bf03cd3c02 100644 (file)
@@ -22,10 +22,6 @@ config SOUND_VWSND
          <file:Documentation/sound/oss/vwsnd> for more info on this driver's
          capabilities.
 
-config SOUND_AU1550_AC97
-       tristate "Au1550/Au1200 AC97 Sound"
-       depends on SOC_AU1550 || SOC_AU1200
-
 config SOUND_MSNDCLAS
        tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
        depends on (m || !STANDALONE) && ISA
index 90ffb99c6b17a8450fb580024a53efcba8e1b6e1..77f21b68bf0f32cc5d7f362330a2cd554539ca20 100644 (file)
@@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST)        += waveartist.o
 obj-$(CONFIG_SOUND_MSNDCLAS)   += msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)    += msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)      += vwsnd.o
-obj-$(CONFIG_SOUND_AU1550_AC97)        += au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)        += swarm_cs4297a.o
 
 obj-$(CONFIG_DMASOUND)         += dmasound/
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
deleted file mode 100644 (file)
index 0cd23d9..0000000
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*
- * ac97_codec.c: Generic AC97 mixer/modem module
- *
- * Derived from ac97 mixer in maestro and trident driver.
- *
- * Copyright 2000 Silicon Integrated System Corporation
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT 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.
- *
- **************************************************************************
- *
- * The Intel Audio Codec '97 specification is available at:
- * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf
- *
- **************************************************************************
- *
- * History
- * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
- *     Removed non existent WM9700
- *     Added support for WM9705, WM9708, WM9709, WM9710, WM9711
- *     WM9712 and WM9717
- * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
- *     corrections to support WM9707 in ViewPad 1000
- * v0.4 Mar 15 2000 Ollie Lho
- *     dual codecs support verified with 4 channels output
- * v0.3 Feb 22 2000 Ollie Lho
- *     bug fix for record mask setting
- * v0.2 Feb 10 2000 Ollie Lho
- *     add ac97_read_proc for /proc/driver/{vendor}/ac97
- * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
- *     Isolated from trident.c to support multiple ac97 codec
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ac97_codec.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#define CODEC_ID_BUFSZ 14
-
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
-                            unsigned int left, unsigned int right);
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
-static int ac97_init_mixer(struct ac97_codec *codec);
-
-static int wolfson_init03(struct ac97_codec * codec);
-static int wolfson_init04(struct ac97_codec * codec);
-static int wolfson_init05(struct ac97_codec * codec);
-static int wolfson_init11(struct ac97_codec * codec);
-static int wolfson_init13(struct ac97_codec * codec);
-static int tritech_init(struct ac97_codec * codec);
-static int tritech_maestro_init(struct ac97_codec * codec);
-static int sigmatel_9708_init(struct ac97_codec *codec);
-static int sigmatel_9721_init(struct ac97_codec *codec);
-static int sigmatel_9744_init(struct ac97_codec *codec);
-static int ad1886_init(struct ac97_codec *codec);
-static int eapd_control(struct ac97_codec *codec, int);
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int cmedia_init(struct ac97_codec * codec);
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-
-
-/*
- *     AC97 operations.
- *
- *     If you are adding a codec then you should be able to use
- *             eapd_ops - any codec that supports EAPD amp control (most)
- *             null_ops - any ancient codec that supports nothing
- *
- *     The three functions are
- *             init - used for non AC97 standard initialisation
- *             amplifier - used to do amplifier control (1=on 0=off)
- *             digital - switch to digital modes (0 = analog)
- *
- *     Not all codecs support all features, not all drivers use all the
- *     operations yet
- */
-static struct ac97_ops null_ops = { NULL, NULL, NULL };
-static struct ac97_ops default_ops = { NULL, eapd_control, NULL };
-static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control};
-static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
-static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
-static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
-static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
-static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
-static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
-static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
-static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
-static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
-static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
-static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
-static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
-static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL};
-static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control};
-
-/* sorted by vendor/device id */
-static const struct {
-       u32 id;
-       char *name;
-       struct ac97_ops *ops;
-       int flags;
-} ac97_codec_ids[] = {
-       {0x41445303, "Analog Devices AD1819",   &null_ops},
-       {0x41445340, "Analog Devices AD1881",   &null_ops},
-       {0x41445348, "Analog Devices AD1881A",  &null_ops},
-       {0x41445360, "Analog Devices AD1885",   &default_ops},
-       {0x41445361, "Analog Devices AD1886",   &ad1886_ops},
-       {0x41445370, "Analog Devices AD1981",   &null_ops},
-       {0x41445372, "Analog Devices AD1981A",  &null_ops},
-       {0x41445374, "Analog Devices AD1981B",  &null_ops},
-       {0x41445460, "Analog Devices AD1885",   &default_ops},
-       {0x41445461, "Analog Devices AD1886",   &ad1886_ops},
-       {0x414B4D00, "Asahi Kasei AK4540",      &null_ops},
-       {0x414B4D01, "Asahi Kasei AK4542",      &null_ops},
-       {0x414B4D02, "Asahi Kasei AK4543",      &null_ops},
-       {0x414C4326, "ALC100P",                 &null_ops},
-       {0x414C4710, "ALC200/200P",             &null_ops},
-       {0x414C4720, "ALC650",                  &default_digital_ops},
-       {0x434D4941, "CMedia",                  &cmedia_ops,            AC97_NO_PCM_VOLUME },
-       {0x434D4942, "CMedia",                  &cmedia_ops,            AC97_NO_PCM_VOLUME },
-       {0x434D4961, "CMedia",                  &cmedia_digital_ops,    AC97_NO_PCM_VOLUME },
-       {0x43525900, "Cirrus Logic CS4297",     &default_ops},
-       {0x43525903, "Cirrus Logic CS4297",     &default_ops},
-       {0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
-       {0x43525914, "Cirrus Logic CS4297A rev B", &default_ops},
-       {0x43525923, "Cirrus Logic CS4298",     &null_ops},
-       {0x4352592B, "Cirrus Logic CS4294",     &null_ops},
-       {0x4352592D, "Cirrus Logic CS4294",     &null_ops},
-       {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
-       {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
-       {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
-       {0x43585430, "CXT48",                   &default_ops,           AC97_DELUDED_MODEM },
-       {0x43585442, "CXT66",                   &default_ops,           AC97_DELUDED_MODEM },
-       {0x44543031, "Diamond Technology DT0893", &default_ops},
-       {0x45838308, "ESS Allegro ES1988",      &null_ops},
-       {0x49434511, "ICE1232",                 &null_ops}, /* I hope --jk */
-       {0x4e534331, "National Semiconductor LM4549", &null_ops},
-       {0x53494c22, "Silicon Laboratory Si3036", &null_ops},
-       {0x53494c23, "Silicon Laboratory Si3038", &null_ops},
-       {0x545200FF, "TriTech TR?????",         &tritech_m_ops},
-       {0x54524102, "TriTech TR28022",         &null_ops},
-       {0x54524103, "TriTech TR28023",         &null_ops},
-       {0x54524106, "TriTech TR28026",         &null_ops},
-       {0x54524108, "TriTech TR28028",         &tritech_ops},
-       {0x54524123, "TriTech TR A5",           &null_ops},
-       {0x574D4C03, "Wolfson WM9703/07/08/17", &wolfson_ops03},
-       {0x574D4C04, "Wolfson WM9704M/WM9704Q", &wolfson_ops04},
-       {0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
-       {0x574D4C09, "Wolfson WM9709",          &null_ops},
-       {0x574D4C12, "Wolfson WM9711/9712",     &wolfson_ops11},
-       {0x574D4C13, "Wolfson WM9713",  &wolfson_ops13, AC97_DEFAULT_POWER_OFF},
-       {0x83847600, "SigmaTel STAC????",       &null_ops},
-       {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
-       {0x83847605, "SigmaTel STAC9704",       &null_ops},
-       {0x83847608, "SigmaTel STAC9708",       &sigmatel_9708_ops},
-       {0x83847609, "SigmaTel STAC9721/23",    &sigmatel_9721_ops},
-       {0x83847644, "SigmaTel STAC9744/45",    &sigmatel_9744_ops},
-       {0x83847652, "SigmaTel STAC9752/53",    &default_ops},
-       {0x83847656, "SigmaTel STAC9756/57",    &sigmatel_9744_ops},
-       {0x83847666, "SigmaTel STAC9750T",      &sigmatel_9744_ops},
-       {0x83847684, "SigmaTel STAC9783/84?",   &null_ops},
-       {0x57454301, "Winbond 83971D",          &null_ops},
-};
-
-/* this table has default mixer values for all OSS mixers. */
-static struct mixer_defaults {
-       int mixer;
-       unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-       /* all values 0 -> 100 in bytes */
-       {SOUND_MIXER_VOLUME,    0x4343},
-       {SOUND_MIXER_BASS,      0x4343},
-       {SOUND_MIXER_TREBLE,    0x4343},
-       {SOUND_MIXER_PCM,       0x4343},
-       {SOUND_MIXER_SPEAKER,   0x4343},
-       {SOUND_MIXER_LINE,      0x4343},
-       {SOUND_MIXER_MIC,       0x0000},
-       {SOUND_MIXER_CD,        0x4343},
-       {SOUND_MIXER_ALTPCM,    0x4343},
-       {SOUND_MIXER_IGAIN,     0x4343},
-       {SOUND_MIXER_LINE1,     0x4343},
-       {SOUND_MIXER_PHONEIN,   0x4343},
-       {SOUND_MIXER_PHONEOUT,  0x4343},
-       {SOUND_MIXER_VIDEO,     0x4343},
-       {-1,0}
-};
-
-/* table to scale scale from OSS mixer value to AC97 mixer register value */   
-static struct ac97_mixer_hw {
-       unsigned char offset;
-       int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
-       [SOUND_MIXER_VOLUME]    =       {AC97_MASTER_VOL_STEREO,64},
-       [SOUND_MIXER_BASS]      =       {AC97_MASTER_TONE,      16},
-       [SOUND_MIXER_TREBLE]    =       {AC97_MASTER_TONE,      16},
-       [SOUND_MIXER_PCM]       =       {AC97_PCMOUT_VOL,       32},
-       [SOUND_MIXER_SPEAKER]   =       {AC97_PCBEEP_VOL,       16},
-       [SOUND_MIXER_LINE]      =       {AC97_LINEIN_VOL,       32},
-       [SOUND_MIXER_MIC]       =       {AC97_MIC_VOL,          32},
-       [SOUND_MIXER_CD]        =       {AC97_CD_VOL,           32},
-       [SOUND_MIXER_ALTPCM]    =       {AC97_HEADPHONE_VOL,    64},
-       [SOUND_MIXER_IGAIN]     =       {AC97_RECORD_GAIN,      16},
-       [SOUND_MIXER_LINE1]     =       {AC97_AUX_VOL,          32},
-       [SOUND_MIXER_PHONEIN]   =       {AC97_PHONE_VOL,        32},
-       [SOUND_MIXER_PHONEOUT]  =       {AC97_MASTER_VOL_MONO,  64},
-       [SOUND_MIXER_VIDEO]     =       {AC97_VIDEO_VOL,        32},
-};
-
-/* the following tables allow us to go from OSS <-> ac97 quickly. */
-enum ac97_recsettings {
-       AC97_REC_MIC=0,
-       AC97_REC_CD,
-       AC97_REC_VIDEO,
-       AC97_REC_AUX,
-       AC97_REC_LINE,
-       AC97_REC_STEREO, /* combination of all enabled outputs..  */
-       AC97_REC_MONO,        /*.. or the mono equivalent */
-       AC97_REC_PHONE
-};
-
-static const unsigned int ac97_rm2oss[] = {
-       [AC97_REC_MIC]   = SOUND_MIXER_MIC,
-       [AC97_REC_CD]    = SOUND_MIXER_CD,
-       [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
-       [AC97_REC_AUX]   = SOUND_MIXER_LINE1,
-       [AC97_REC_LINE]  = SOUND_MIXER_LINE,
-       [AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
-       [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static const unsigned int ac97_oss_rm[] = {
-       [SOUND_MIXER_MIC]       = AC97_REC_MIC,
-       [SOUND_MIXER_CD]        = AC97_REC_CD,
-       [SOUND_MIXER_VIDEO]     = AC97_REC_VIDEO,
-       [SOUND_MIXER_LINE1]     = AC97_REC_AUX,
-       [SOUND_MIXER_LINE]      = AC97_REC_LINE,
-       [SOUND_MIXER_IGAIN]     = AC97_REC_STEREO,
-       [SOUND_MIXER_PHONEIN]   = AC97_REC_PHONE
-};
-
-static LIST_HEAD(codecs);
-static LIST_HEAD(codec_drivers);
-static DEFINE_MUTEX(codec_mutex);
-
-/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
-   about that given mixer, and should be holding a spinlock for the card */
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) 
-{
-       u16 val;
-       int ret = 0;
-       int scale;
-       struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-       val = codec->codec_read(codec , mh->offset);
-
-       if (val & AC97_MUTE) {
-               ret = 0;
-       } else if (AC97_STEREO_MASK & (1 << oss_channel)) {
-               /* nice stereo mixers .. */
-               int left,right;
-
-               left = (val >> 8)  & 0x7f;
-               right = val  & 0x7f;
-
-               if (oss_channel == SOUND_MIXER_IGAIN) {
-                       right = (right * 100) / mh->scale;
-                       left = (left * 100) / mh->scale;
-               } else {
-                       /* these may have 5 or 6 bit resolution */
-                       if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
-                               scale = (1 << codec->bit_resolution);
-                       else
-                               scale = mh->scale;
-
-                       right = 100 - ((right * 100) / scale);
-                       left = 100 - ((left * 100) / scale);
-               }
-               ret = left | (right << 8);
-       } else if (oss_channel == SOUND_MIXER_SPEAKER) {
-               ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
-       } else if (oss_channel == SOUND_MIXER_PHONEIN) {
-               ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-       } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-               scale = (1 << codec->bit_resolution);
-               ret = 100 - (((val & 0x1f) * 100) / scale);
-       } else if (oss_channel == SOUND_MIXER_MIC) {
-               ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-               /*  the low bit is optional in the tone sliders and masking
-                   it lets us avoid the 0xf 'bypass'.. */
-       } else if (oss_channel == SOUND_MIXER_BASS) {
-               ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
-       } else if (oss_channel == SOUND_MIXER_TREBLE) {
-               ret = 100 - (((val & 0xe) * 100) / mh->scale);
-       }
-
-#ifdef DEBUG
-       printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
-              "0x%04x -> 0x%04x\n",
-              oss_channel, codec->id ? "Secondary" : "Primary",
-              mh->offset, val, ret);
-#endif
-
-       return ret;
-}
-
-/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
-   make sure all is well in arg land, call with spinlock held */
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
-                     unsigned int left, unsigned int right)
-{
-       u16 val = 0;
-       int scale;
-       struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-#ifdef DEBUG
-       printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
-              "left vol:%2d, right vol:%2d:",
-              oss_channel, codec->id ? "Secondary" : "Primary",
-              mh->offset, left, right);
-#endif
-
-       if (AC97_STEREO_MASK & (1 << oss_channel)) {
-               /* stereo mixers */
-               if (left == 0 && right == 0) {
-                       val = AC97_MUTE;
-               } else {
-                       if (oss_channel == SOUND_MIXER_IGAIN) {
-                               right = (right * mh->scale) / 100;
-                               left = (left * mh->scale) / 100;
-                               if (right >= mh->scale)
-                                       right = mh->scale-1;
-                               if (left >= mh->scale)
-                                       left = mh->scale-1;
-                       } else {
-                               /* these may have 5 or 6 bit resolution */
-                               if (oss_channel == SOUND_MIXER_VOLUME ||
-                                   oss_channel == SOUND_MIXER_ALTPCM)
-                                       scale = (1 << codec->bit_resolution);
-                               else
-                                       scale = mh->scale;
-
-                               right = ((100 - right) * scale) / 100;
-                               left = ((100 - left) * scale) / 100;
-                               if (right >= scale)
-                                       right = scale-1;
-                               if (left >= scale)
-                                       left = scale-1;
-                       }
-                       val = (left << 8) | right;
-               }
-       } else if (oss_channel == SOUND_MIXER_BASS) {
-               val = codec->codec_read(codec , mh->offset) & ~0x0f00;
-               left = ((100 - left) * mh->scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val |= (left << 8) & 0x0e00;
-       } else if (oss_channel == SOUND_MIXER_TREBLE) {
-               val = codec->codec_read(codec , mh->offset) & ~0x000f;
-               left = ((100 - left) * mh->scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val |= left & 0x000e;
-       } else if(left == 0) {
-               val = AC97_MUTE;
-       } else if (oss_channel == SOUND_MIXER_SPEAKER) {
-               left = ((100 - left) * mh->scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val = left << 1;
-       } else if (oss_channel == SOUND_MIXER_PHONEIN) {
-               left = ((100 - left) * mh->scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val = left;
-       } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-               scale = (1 << codec->bit_resolution);
-               left = ((100 - left) * scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val = left;
-       } else if (oss_channel == SOUND_MIXER_MIC) {
-               val = codec->codec_read(codec , mh->offset) & ~0x801f;
-               left = ((100 - left) * mh->scale) / 100;
-               if (left >= mh->scale)
-                       left = mh->scale-1;
-               val |= left;
-               /*  the low bit is optional in the tone sliders and masking
-                   it lets us avoid the 0xf 'bypass'.. */
-       }
-#ifdef DEBUG
-       printk(" 0x%04x", val);
-#endif
-
-       codec->codec_write(codec, mh->offset, val);
-
-#ifdef DEBUG
-       val = codec->codec_read(codec, mh->offset);
-       printk(" -> 0x%04x\n", val);
-#endif
-}
-
-/* a thin wrapper for write_mixer */
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) 
-{
-       unsigned int left,right;
-
-       /* cleanse input a little */
-       right = ((val >> 8)  & 0xff) ;
-       left = (val  & 0xff) ;
-
-       if (right > 100) right = 100;
-       if (left > 100) left = 100;
-
-       codec->mixer_state[oss_mixer] = (right << 8) | left;
-       codec->write_mixer(codec, oss_mixer, left, right);
-}
-
-/* read or write the recmask, the ac97 can really have left and right recording
-   inputs independently set, but OSS doesn't seem to want us to express that to
-   the user. the caller guarantees that we have a supported bit set, and they
-   must be holding the card's spinlock */
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) 
-{
-       unsigned int val;
-
-       if (rw) {
-               /* read it from the card */
-               val = codec->codec_read(codec, AC97_RECORD_SELECT);
-#ifdef DEBUG
-               printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
-#endif
-               return (1 << ac97_rm2oss[val & 0x07]);
-       }
-
-       /* else, write the first set in the mask as the
-          output */    
-       /* clear out current set value first (AC97 supports only 1 input!) */
-       val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
-       if (mask != val)
-           mask &= ~val;
-       
-       val = ffs(mask); 
-       val = ac97_oss_rm[val-1];
-       val |= val << 8;  /* set both channels */
-
-#ifdef DEBUG
-       printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
-#endif
-
-       codec->codec_write(codec, AC97_RECORD_SELECT, val);
-
-       return 0;
-};
-
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
-{
-       int i, val = 0;
-
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-               memset(&info, 0, sizeof(info));
-               strlcpy(info.id, codec->name, sizeof(info.id));
-               strlcpy(info.name, codec->name, sizeof(info.name));
-               info.modify_counter = codec->modcnt;
-               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-               memset(&info, 0, sizeof(info));
-               strlcpy(info.id, codec->name, sizeof(info.id));
-               strlcpy(info.name, codec->name, sizeof(info.name));
-               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-               return -EINVAL;
-
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int __user *)arg);
-
-       if (_SIOC_DIR(cmd) == _SIOC_READ) {
-               switch (_IOC_NR(cmd)) {
-               case SOUND_MIXER_RECSRC: /* give them the current record source */
-                       if (!codec->recmask_io) {
-                               val = 0;
-                       } else {
-                               val = codec->recmask_io(codec, 1, 0);
-                       }
-                       break;
-
-               case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
-                       val = codec->supported_mixers;
-                       break;
-
-               case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-                       val = codec->record_sources;
-                       break;
-
-               case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-                       val = codec->stereo_mixers;
-                       break;
-
-               case SOUND_MIXER_CAPS:
-                       val = SOUND_CAP_EXCL_INPUT;
-                       break;
-
-               default: /* read a specific mixer */
-                       i = _IOC_NR(cmd);
-
-                       if (!supported_mixer(codec, i)) 
-                               return -EINVAL;
-
-                       /* do we ever want to touch the hardware? */
-                       /* val = codec->read_mixer(codec, i); */
-                       val = codec->mixer_state[i];
-                       break;
-               }
-               return put_user(val, (int __user *)arg);
-       }
-
-       if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
-               codec->modcnt++;
-               if (get_user(val, (int __user *)arg))
-                       return -EFAULT;
-
-               switch (_IOC_NR(cmd)) {
-               case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-                       if (!codec->recmask_io) return -EINVAL;
-                       if (!val) return 0;
-                       if (!(val &= codec->record_sources)) return -EINVAL;
-
-                       codec->recmask_io(codec, 0, val);
-
-                       return 0;
-               default: /* write a specific mixer */
-                       i = _IOC_NR(cmd);
-
-                       if (!supported_mixer(codec, i)) 
-                               return -EINVAL;
-
-                       ac97_set_mixer(codec, i, val);
-
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-/**
- *     codec_id        -  Turn id1/id2 into a PnP string
- *     @id1: Vendor ID1
- *     @id2: Vendor ID2
- *     @buf: CODEC_ID_BUFSZ byte buffer
- *
- *     Fills buf with a zero terminated PnP ident string for the id1/id2
- *     pair. For convenience the return is the passed in buffer pointer.
- */
-static char *codec_id(u16 id1, u16 id2, char *buf)
-{
-       if(id1&0x8080) {
-               snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
-       } else {
-               buf[0] = (id1 >> 8);
-               buf[1] = (id1 & 0xFF);
-               buf[2] = (id2 >> 8);
-               snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
-       }
-       return buf;
-}
-/**
- *     ac97_check_modem - Check if the Codec is a modem
- *     @codec: codec to check
- *
- *     Return true if the device is an AC97 1.0 or AC97 2.0 modem
- */
-static int ac97_check_modem(struct ac97_codec *codec)
-{
-       /* Check for an AC97 1.0 soft modem (ID1) */
-       if(codec->codec_read(codec, AC97_RESET) & 2)
-               return 1;
-       /* Check for an AC97 2.x soft modem */
-       codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-       if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
-               return 1;
-       return 0;
-}
-
-
-/**
- *     ac97_alloc_codec - Allocate an AC97 codec
- *
- *     Returns a new AC97 codec structure. AC97 codecs may become
- *     refcounted soon so this interface is needed. Returns with
- *     one reference taken.
- */
-struct ac97_codec *ac97_alloc_codec(void)
-{
-       struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL);
-       if(!codec)
-               return NULL;
-
-       spin_lock_init(&codec->lock);
-       INIT_LIST_HEAD(&codec->list);
-       return codec;
-}
-
-EXPORT_SYMBOL(ac97_alloc_codec);
-
-/**
- *     ac97_release_codec -    Release an AC97 codec
- *     @codec: codec to release
- *
- *     Release an allocated AC97 codec. This will be refcounted in
- *     time but for the moment is trivial. Calls the unregister
- *     handler if the codec is now defunct.
- */
-void ac97_release_codec(struct ac97_codec *codec)
-{
-       /* Remove from the list first, we don't want to be
-          "rediscovered" */
-       mutex_lock(&codec_mutex);
-       list_del(&codec->list);
-       mutex_unlock(&codec_mutex);
-       /*
-        *      The driver needs to deal with internal
-        *      locking to avoid accidents here. 
-        */
-       if(codec->driver)
-               codec->driver->remove(codec, codec->driver);
-       kfree(codec);
-}
-
-EXPORT_SYMBOL(ac97_release_codec);
-
-/**
- *     ac97_probe_codec - Initialize and setup AC97-compatible codec
- *     @codec: (in/out) Kernel info for a single AC97 codec
- *
- *     Reset the AC97 codec, then initialize the mixer and
- *     the rest of the @codec structure.
- *
- *     The codec_read and codec_write fields of @codec are
- *     required to be setup and working when this function
- *     is called.  All other fields are set by this function.
- *
- *     codec_wait field of @codec can optionally be provided
- *     when calling this function.  If codec_wait is not %NULL,
- *     this function will call codec_wait any time it is
- *     necessary to wait for the audio chip to reach the
- *     codec-ready state.  If codec_wait is %NULL, then
- *     the default behavior is to call schedule_timeout.
- *     Currently codec_wait is used to wait for AC97 codec
- *     reset to complete. 
- *
- *     Some codecs will power down when a register reset is
- *     performed. We now check for such codecs.
- *
- *     Returns 1 (true) on success, or 0 (false) on failure.
- */
-int ac97_probe_codec(struct ac97_codec *codec)
-{
-       u16 id1, id2;
-       u16 audio;
-       int i;
-       char cidbuf[CODEC_ID_BUFSZ];
-       u16 f;
-       struct list_head *l;
-       struct ac97_driver *d;
-       
-       /* wait for codec-ready state */
-       if (codec->codec_wait)
-               codec->codec_wait(codec);
-       else
-               udelay(10);
-
-       /* will the codec power down if register reset ? */
-       id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
-       id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-       codec->name = NULL;
-       codec->codec_ops = &null_ops;
-       for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
-               if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
-                       codec->type = ac97_codec_ids[i].id;
-                       codec->name = ac97_codec_ids[i].name;
-                       codec->codec_ops = ac97_codec_ids[i].ops;
-                       codec->flags = ac97_codec_ids[i].flags;
-                       break;
-               }
-       }
-
-       codec->model = (id1 << 16) | id2;
-       if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
-               /* reset codec and wait for the ready bit before we continue */
-               codec->codec_write(codec, AC97_RESET, 0L);
-               if (codec->codec_wait)
-                       codec->codec_wait(codec);
-               else
-                       udelay(10);
-       }
-
-       /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
-        * be read zero.
-        *
-        * FIXME: is the following comment outdated?  -jgarzik
-        * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-        */
-       if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-               printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-                      (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
-                      : (codec->id&1 ? "Secondary":  "Primary"));
-               return 0;
-       }
-       
-       /* probe for Modem Codec */
-       codec->modem = ac97_check_modem(codec);
-
-       /* enable SPDIF */
-       f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-       if((codec->codec_ops == &null_ops) && (f & 4))
-               codec->codec_ops = &default_digital_ops;
-       
-       /* A device which thinks its a modem but isn't */
-       if(codec->flags & AC97_DELUDED_MODEM)
-               codec->modem = 0;
-               
-       if (codec->name == NULL)
-               codec->name = "Unknown";
-       printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", 
-               codec->modem ? "Modem" : (audio ? "Audio" : ""),
-              codec_id(id1, id2, cidbuf), codec->name);
-
-       if(!ac97_init_mixer(codec))
-               return 0;
-               
-       /* 
-        *      Attach last so the caller can override the mixer
-        *      callbacks.
-        */
-        
-       mutex_lock(&codec_mutex);
-       list_add(&codec->list, &codecs);
-
-       list_for_each(l, &codec_drivers) {
-               d = list_entry(l, struct ac97_driver, list);
-               if ((codec->model ^ d->codec_id) & d->codec_mask)
-                       continue;
-               if(d->probe(codec, d) == 0)
-               {
-                       codec->driver = d;
-                       break;
-               }
-       }
-
-       mutex_unlock(&codec_mutex);
-       return 1;
-}
-
-static int ac97_init_mixer(struct ac97_codec *codec)
-{
-       u16 cap;
-       int i;
-
-       cap = codec->codec_read(codec, AC97_RESET);
-
-       /* mixer masks */
-       codec->supported_mixers = AC97_SUPPORTED_MASK;
-       codec->stereo_mixers = AC97_STEREO_MASK;
-       codec->record_sources = AC97_RECORD_MASK;
-       if (!(cap & 0x04))
-               codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
-       if (!(cap & 0x10))
-               codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
-
-
-       /* detect bit resolution */
-       codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
-       if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020)
-               codec->bit_resolution = 6;
-       else
-               codec->bit_resolution = 5;
-
-       /* generic OSS to AC97 wrapper */
-       codec->read_mixer = ac97_read_mixer;
-       codec->write_mixer = ac97_write_mixer;
-       codec->recmask_io = ac97_recmask_io;
-       codec->mixer_ioctl = ac97_mixer_ioctl;
-
-       /* initialize mixer channel volumes */
-       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-               struct mixer_defaults *md = &mixer_defaults[i];
-               if (md->mixer == -1) 
-                       break;
-               if (!supported_mixer(codec, md->mixer)) 
-                       continue;
-               ac97_set_mixer(codec, md->mixer, md->value);
-       }
-
-       /* codec specific initialization for 4-6 channel output or secondary codec stuff */
-       if (codec->codec_ops->init != NULL) {
-               codec->codec_ops->init(codec);
-       }
-
-       /*
-        *      Volume is MUTE only on this device. We have to initialise
-        *      it but its useless beyond that.
-        */
-       if(codec->flags & AC97_NO_PCM_VOLUME)
-       {
-               codec->supported_mixers &= ~SOUND_MASK_PCM;
-               printk(KERN_WARNING "AC97 codec does not have proper volume support.\n");
-       }
-       return 1;
-}
-
-#define AC97_SIGMATEL_ANALOG    0x6c   /* Analog Special */
-#define AC97_SIGMATEL_DAC2INVERT 0x6e
-#define AC97_SIGMATEL_BIAS1     0x70
-#define AC97_SIGMATEL_BIAS2     0x72
-#define AC97_SIGMATEL_MULTICHN  0x74   /* Multi-Channel programming */
-#define AC97_SIGMATEL_CIC1      0x76
-#define AC97_SIGMATEL_CIC2      0x78
-
-
-static int sigmatel_9708_init(struct ac97_codec * codec)
-{
-       u16 codec72, codec6c;
-
-       codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
-       codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
-
-       if ((codec72==0) && (codec6c==0)) {
-               codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-               codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
-               codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-               codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
-       } else if ((codec72==0x8000) && (codec6c==0)) {
-               codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-               codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
-               codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
-       } else if ((codec72==0x8000) && (codec6c==0x0080)) {
-               /* nothing */
-       }
-       codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-       return 0;
-}
-
-
-static int sigmatel_9721_init(struct ac97_codec * codec)
-{
-       /* Only set up secondary codec */
-       if (codec->id == 0)
-               return 0;
-
-       codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
-
-       /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
-          sloc 3,4 = 0x01, slot 7,8 = 0x00, */
-       codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
-
-       /* we don't have the crystal when we are on an AMR card, so use
-          BIT_CLK as our clock source. Write the magic word ABBA and read
-          back to enable register 0x78 */
-       codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-       codec->codec_read(codec, AC97_SIGMATEL_CIC1);
-
-       /* sync all the clocks*/
-       codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
-
-       return 0;
-}
-
-
-static int sigmatel_9744_init(struct ac97_codec * codec)
-{
-       // patch for SigmaTel
-       codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-       codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
-       codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-       codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
-       codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-       return 0;
-}
-
-static int cmedia_init(struct ac97_codec *codec)
-{
-       /* Initialise the CMedia 9739 */
-       /*
-               We could set various options here
-               Register 0x20 bit 0x100 sets mic as center bass
-               Also do multi_channel_ctrl &=~0x3000 |=0x1000
-               
-               For now we set up the GPIO and PC beep 
-       */
-       
-       u16 v;
-       
-       /* MIC */
-       codec->codec_write(codec, 0x64, 0x3000);
-       v = codec->codec_read(codec, 0x64);
-       v &= ~0x8000;
-       codec->codec_write(codec, 0x64, v);
-       codec->codec_write(codec, 0x70, 0x0100);
-       codec->codec_write(codec, 0x72, 0x0020);
-       return 0;
-}
-       
-#define AC97_WM97XX_FMIXER_VOL 0x72
-#define AC97_WM97XX_RMIXER_VOL 0x74
-#define AC97_WM97XX_TEST 0x5a
-#define AC97_WM9704_RPCM_VOL 0x70
-#define AC97_WM9711_OUT3VOL 0x16
-
-static int wolfson_init03(struct ac97_codec * codec)
-{
-       /* this is known to work for the ViewSonic ViewPad 1000 */
-       codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000);
-       return 0;
-}
-
-static int wolfson_init04(struct ac97_codec * codec)
-{
-       codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808);
-
-       // patch for DVD noise
-       codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200);
-
-       // init vol as PCM vol
-       codec->codec_write(codec, AC97_WM9704_RPCM_VOL,
-               codec->codec_read(codec, AC97_PCMOUT_VOL));
-
-       /* set rear surround volume */
-       codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-       return 0;
-}
-
-/* WM9705, WM9710 */
-static int wolfson_init05(struct ac97_codec * codec)
-{
-       /* set front mixer volume */
-       codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-       return 0;
-}
-
-/* WM9711, WM9712 */
-static int wolfson_init11(struct ac97_codec * codec)
-{
-       /* stop pop's during suspend/resume */
-       codec->codec_write(codec, AC97_WM97XX_TEST,
-               codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf);
-
-       /* set out3 volume */
-       codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808);
-       return 0;
-}
-
-/* WM9713 */
-static int wolfson_init13(struct ac97_codec * codec)
-{
-       codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
-       codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
-       codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
-       codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
-       codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
-       codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
-
-       return 0;
-}
-
-static int tritech_init(struct ac97_codec * codec)
-{
-       codec->codec_write(codec, 0x26, 0x0300);
-       codec->codec_write(codec, 0x26, 0x0000);
-       codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-       codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
-       return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-static int tritech_maestro_init(struct ac97_codec * codec)
-{
-       /* no idea what this does */
-       codec->codec_write(codec, 0x2A, 0x0001);
-       codec->codec_write(codec, 0x2C, 0x0000);
-       codec->codec_write(codec, 0x2C, 0XFFFF);
-       return 0;
-}
-
-
-
-/* 
- *     Presario700 workaround 
- *     for Jack Sense/SPDIF Register mis-setting causing
- *     no audible output
- *     by Santiago Nullo 04/05/2002
- */
-
-#define AC97_AD1886_JACK_SENSE 0x72
-
-static int ad1886_init(struct ac97_codec * codec)
-{
-       /* from AD1886 Specs */
-       codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
-       return 0;
-}
-
-
-
-
-/*
- *     This is basically standard AC97. It should work as a default for
- *     almost all modern codecs. Note that some cards wire EAPD *backwards*
- *     That side of it is up to the card driver not us to cope with.
- *
- */
-
-static int eapd_control(struct ac97_codec * codec, int on)
-{
-       if(on)
-               codec->codec_write(codec, AC97_POWER_CONTROL,
-                       codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
-       else
-               codec->codec_write(codec, AC97_POWER_CONTROL,
-                       codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000);
-       return 0;
-}
-
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-       u16 reg;
-       
-       reg = codec->codec_read(codec, AC97_SPDIF_CONTROL);
-       
-       switch(rate)
-       {
-               /* Off by default */
-               default:
-               case 0:
-                       reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-                       codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF));
-                       if(rate == 0)
-                               return 0;
-                       return -EINVAL;
-               case 1:
-                       reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
-                       break;
-               case 2:
-                       reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
-                       break;
-               case 3:
-                       reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
-                       break;
-       }
-       
-       reg &= ~AC97_SC_CC_MASK;
-       reg |= (mode & AUDIO_CCMASK) << 6;
-       
-       if(mode & AUDIO_DIGITAL)
-               reg |= 2;
-       if(mode & AUDIO_PRO)
-               reg |= 1;
-       if(mode & AUDIO_DRS)
-               reg |= 0x4000;
-
-       codec->codec_write(codec, AC97_SPDIF_CONTROL, reg);
-
-       reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-       reg &= (AC97_EA_SLOT_MASK);
-       reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots;
-       codec->codec_write(codec, AC97_EXTENDED_STATUS, reg);
-       
-       reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-       if(!(reg & 0x0400))
-       {
-               codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/*
- *     Crystal digital audio control (CS4299)
- */
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-       u16 cv;
-
-       if(mode & AUDIO_DIGITAL)
-               return -EINVAL;
-               
-       switch(rate)
-       {
-               case 0: cv = 0x0; break;        /* SPEN off */
-               case 48000: cv = 0x8004; break; /* 48KHz digital */
-               case 44100: cv = 0x8104; break; /* 44.1KHz digital */
-               case 32768:                     /* 32Khz */
-               default:
-                       return -EINVAL;
-       }
-       codec->codec_write(codec, 0x68, cv);
-       return 0;
-}
-
-/*
- *     CMedia digital audio control
- *     Needs more work.
- */
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-       u16 cv;
-
-       if(mode & AUDIO_DIGITAL)
-               return -EINVAL;
-               
-       switch(rate)
-       {
-               case 0:         cv = 0x0001; break;     /* SPEN off */
-               case 48000:     cv = 0x0009; break;     /* 48KHz digital */
-               default:
-                       return -EINVAL;
-       }
-       codec->codec_write(codec, 0x2A, 0x05c4);
-       codec->codec_write(codec, 0x6C, cv);
-       
-       /* Switch on mix to surround */
-       cv = codec->codec_read(codec, 0x64);
-       cv &= ~0x0200;
-       if(mode)
-               cv |= 0x0200;
-       codec->codec_write(codec, 0x64, cv);
-       return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-#if 0  /* there has been 1 person on the planet with a pt101 that we
-        know of.  If they care, they can put this back in :) */
-static int pt101_init(struct ac97_codec * codec)
-{
-       printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
-       /* who knows.. */
-       codec->codec_write(codec, 0x2A, 0x0001);
-       codec->codec_write(codec, 0x2C, 0x0000);
-       codec->codec_write(codec, 0x2C, 0xFFFF);
-       codec->codec_write(codec, 0x10, 0x9F1F);
-       codec->codec_write(codec, 0x12, 0x0808);
-       codec->codec_write(codec, 0x14, 0x9F1F);
-       codec->codec_write(codec, 0x16, 0x9F1F);
-       codec->codec_write(codec, 0x18, 0x0404);
-       codec->codec_write(codec, 0x1A, 0x0000);
-       codec->codec_write(codec, 0x1C, 0x0000);
-       codec->codec_write(codec, 0x02, 0x0404);
-       codec->codec_write(codec, 0x04, 0x0808);
-       codec->codec_write(codec, 0x0C, 0x801F);
-       codec->codec_write(codec, 0x0E, 0x801F);
-       return 0;
-}
-#endif
-       
-
-EXPORT_SYMBOL(ac97_probe_codec);
-
-MODULE_LICENSE("GPL");
-
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
deleted file mode 100644 (file)
index a8f626d..0000000
+++ /dev/null
@@ -1,2147 +0,0 @@
-/*
- * au1550_ac97.c  --  Sound driver for Alchemy Au1550 MIPS Internet Edge
- *                    Processor.
- *
- * Copyright 2004 Embedded Edge, LLC
- *     dan@embeddededge.com
- *
- * Mostly copied from the au1000.c driver and some from the
- * PowerMac dbdma driver.
- * We assume the processor can do memory coherent DMA.
- *
- * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1xxx.h>
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* misc stuff */
-#define POLL_COUNT   0x50000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* The number of DBDMA ring descriptors to allocate.  No sense making
- * this too large....if you can't keep up with a few you aren't likely
- * to be able to with lots of them, either.
- */
-#define NUM_DBDMA_DESCRIPTORS 4
-
-#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg)
-
-/* Boot options
- * 0 = no VRA, 1 = use VRA if codec supports it
- */
-static DEFINE_MUTEX(au1550_ac97_mutex);
-static int      vra = 1;
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-static struct au1550_state {
-       /* soundcore stuff */
-       int             dev_audio;
-
-       struct ac97_codec *codec;
-       unsigned        codec_base_caps; /* AC'97 reg 00h, "Reset Register" */
-       unsigned        codec_ext_caps;  /* AC'97 reg 28h, "Extended Audio ID" */
-       int             no_vra;         /* do not use VRA */
-
-       spinlock_t      lock;
-       struct mutex open_mutex;
-       struct mutex sem;
-       fmode_t          open_mode;
-       wait_queue_head_t open_wait;
-
-       struct dmabuf {
-               u32             dmanr;
-               unsigned        sample_rate;
-               unsigned        src_factor;
-               unsigned        sample_size;
-               int             num_channels;
-               int             dma_bytes_per_sample;
-               int             user_bytes_per_sample;
-               int             cnt_factor;
-
-               void            *rawbuf;
-               unsigned        buforder;
-               unsigned        numfrag;
-               unsigned        fragshift;
-               void            *nextIn;
-               void            *nextOut;
-               int             count;
-               unsigned        total_bytes;
-               unsigned        error;
-               wait_queue_head_t wait;
-
-               /* redundant, but makes calculations easier */
-               unsigned        fragsize;
-               unsigned        dma_fragsize;
-               unsigned        dmasize;
-               unsigned        dma_qcount;
-
-               /* OSS stuff */
-               unsigned        mapped:1;
-               unsigned        ready:1;
-               unsigned        stopped:1;
-               unsigned        ossfragshift;
-               int             ossmaxfrags;
-               unsigned        subdivision;
-       } dma_dac, dma_adc;
-} au1550_state;
-
-static unsigned
-ld2(unsigned int x)
-{
-       unsigned        r = 0;
-
-       if (x >= 0x10000) {
-               x >>= 16;
-               r += 16;
-       }
-       if (x >= 0x100) {
-               x >>= 8;
-               r += 8;
-       }
-       if (x >= 0x10) {
-               x >>= 4;
-               r += 4;
-       }
-       if (x >= 4) {
-               x >>= 2;
-               r += 2;
-       }
-       if (x >= 2)
-               r++;
-       return r;
-}
-
-static void
-au1550_delay(int msec)
-{
-       if (in_interrupt())
-               return;
-
-       schedule_timeout_uninterruptible(msecs_to_jiffies(msec));
-}
-
-static u16
-rdcodec(struct ac97_codec *codec, u8 addr)
-{
-       struct au1550_state *s = codec->private_data;
-       unsigned long   flags;
-       u32             cmd, val;
-       u16             data;
-       int             i;
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-               if (!(val & PSC_AC97STAT_CP))
-                       break;
-       }
-       if (i == POLL_COUNT)
-               err("rdcodec: codec cmd pending expired!");
-
-       cmd = (u32)PSC_AC97CDC_INDX(addr);
-       cmd |= PSC_AC97CDC_RD;  /* read command */
-       au_writel(cmd, PSC_AC97CDC);
-       au_sync();
-
-       /* now wait for the data
-       */
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-               if (!(val & PSC_AC97STAT_CP))
-                       break;
-       }
-       if (i == POLL_COUNT) {
-               err("rdcodec: read poll expired!");
-               data = 0;
-               goto out;
-       }
-
-       /* wait for command done?
-       */
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97EVNT);
-               au_sync();
-               if (val & PSC_AC97EVNT_CD)
-                       break;
-       }
-       if (i == POLL_COUNT) {
-               err("rdcodec: read cmdwait expired!");
-               data = 0;
-               goto out;
-       }
-
-       data = au_readl(PSC_AC97CDC) & 0xffff;
-       au_sync();
-
-       /* Clear command done event.
-       */
-       au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-       au_sync();
-
- out:
-       spin_unlock_irqrestore(&s->lock, flags);
-
-       return data;
-}
-
-
-static void
-wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
-       struct au1550_state *s = codec->private_data;
-       unsigned long   flags;
-       u32             cmd, val;
-       int             i;
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-               if (!(val & PSC_AC97STAT_CP))
-                       break;
-       }
-       if (i == POLL_COUNT)
-               err("wrcodec: codec cmd pending expired!");
-
-       cmd = (u32)PSC_AC97CDC_INDX(addr);
-       cmd |= (u32)data;
-       au_writel(cmd, PSC_AC97CDC);
-       au_sync();
-
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-               if (!(val & PSC_AC97STAT_CP))
-                       break;
-       }
-       if (i == POLL_COUNT)
-               err("wrcodec: codec cmd pending expired!");
-
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97EVNT);
-               au_sync();
-               if (val & PSC_AC97EVNT_CD)
-                       break;
-       }
-       if (i == POLL_COUNT)
-               err("wrcodec: read cmdwait expired!");
-
-       /* Clear command done event.
-       */
-       au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-       au_sync();
-
-       spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-waitcodec(struct ac97_codec *codec)
-{
-       u16     temp;
-       u32     val;
-       int     i;
-
-       /* codec_wait is used to wait for a ready state after
-        * an AC97C_RESET.
-        */
-       au1550_delay(10);
-
-       /* first poll the CODEC_READY tag bit
-       */
-       for (i = 0; i < POLL_COUNT; i++) {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-               if (val & PSC_AC97STAT_CR)
-                       break;
-       }
-       if (i == POLL_COUNT) {
-               err("waitcodec: CODEC_READY poll expired!");
-               return;
-       }
-
-       /* get AC'97 powerdown control/status register
-       */
-       temp = rdcodec(codec, AC97_POWER_CONTROL);
-
-       /* If anything is powered down, power'em up
-       */
-       if (temp & 0x7f00) {
-               /* Power on
-               */
-               wrcodec(codec, AC97_POWER_CONTROL, 0);
-               au1550_delay(100);
-
-               /* Reread
-               */
-               temp = rdcodec(codec, AC97_POWER_CONTROL);
-       }
-
-       /* Check if Codec REF,ANL,DAC,ADC ready
-       */
-       if ((temp & 0x7f0f) != 0x000f)
-               err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-/* stop the ADC before calling */
-static void
-set_adc_rate(struct au1550_state *s, unsigned rate)
-{
-       struct dmabuf  *adc = &s->dma_adc;
-       struct dmabuf  *dac = &s->dma_dac;
-       unsigned        adc_rate, dac_rate;
-       u16             ac97_extstat;
-
-       if (s->no_vra) {
-               /* calc SRC factor
-               */
-               adc->src_factor = ((96000 / rate) + 1) >> 1;
-               adc->sample_rate = 48000 / adc->src_factor;
-               return;
-       }
-
-       adc->src_factor = 1;
-
-       ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-       rate = rate > 48000 ? 48000 : rate;
-
-       /* enable VRA
-       */
-       wrcodec(s->codec, AC97_EXTENDED_STATUS,
-               ac97_extstat | AC97_EXTSTAT_VRA);
-
-       /* now write the sample rate
-       */
-       wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
-
-       /* read it back for actual supported rate
-       */
-       adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-       pr_debug("set_adc_rate: set to %d Hz\n", adc_rate);
-
-       /* some codec's don't allow unequal DAC and ADC rates, in which case
-        * writing one rate reg actually changes both.
-        */
-       dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-       if (dac->num_channels > 2)
-               wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
-       if (dac->num_channels > 4)
-               wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
-       adc->sample_rate = adc_rate;
-       dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void
-set_dac_rate(struct au1550_state *s, unsigned rate)
-{
-       struct dmabuf  *dac = &s->dma_dac;
-       struct dmabuf  *adc = &s->dma_adc;
-       unsigned        adc_rate, dac_rate;
-       u16             ac97_extstat;
-
-       if (s->no_vra) {
-               /* calc SRC factor
-               */
-               dac->src_factor = ((96000 / rate) + 1) >> 1;
-               dac->sample_rate = 48000 / dac->src_factor;
-               return;
-       }
-
-       dac->src_factor = 1;
-
-       ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-       rate = rate > 48000 ? 48000 : rate;
-
-       /* enable VRA
-       */
-       wrcodec(s->codec, AC97_EXTENDED_STATUS,
-               ac97_extstat | AC97_EXTSTAT_VRA);
-
-       /* now write the sample rate
-       */
-       wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
-
-       /* I don't support different sample rates for multichannel,
-        * so make these channels the same.
-        */
-       if (dac->num_channels > 2)
-               wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
-       if (dac->num_channels > 4)
-               wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
-       /* read it back for actual supported rate
-       */
-       dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-
-       pr_debug("set_dac_rate: set to %d Hz\n", dac_rate);
-
-       /* some codec's don't allow unequal DAC and ADC rates, in which case
-        * writing one rate reg actually changes both.
-        */
-       adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-       dac->sample_rate = dac_rate;
-       adc->sample_rate = adc_rate;
-}
-
-static void
-stop_dac(struct au1550_state *s)
-{
-       struct dmabuf  *db = &s->dma_dac;
-       u32             stat;
-       unsigned long   flags;
-
-       if (db->stopped)
-               return;
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);
-       au_sync();
-
-       /* Wait for Transmit Busy to show disabled.
-       */
-       do {
-               stat = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((stat & PSC_AC97STAT_TB) != 0);
-
-       au1xxx_dbdma_reset(db->dmanr);
-
-       db->stopped = 1;
-
-       spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-stop_adc(struct au1550_state *s)
-{
-       struct dmabuf  *db = &s->dma_adc;
-       unsigned long   flags;
-       u32             stat;
-
-       if (db->stopped)
-               return;
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       au_writel(PSC_AC97PCR_RP, PSC_AC97PCR);
-       au_sync();
-
-       /* Wait for Receive Busy to show disabled.
-       */
-       do {
-               stat = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((stat & PSC_AC97STAT_RB) != 0);
-
-       au1xxx_dbdma_reset(db->dmanr);
-
-       db->stopped = 1;
-
-       spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void
-set_xmit_slots(int num_channels)
-{
-       u32     ac97_config, stat;
-
-       ac97_config = au_readl(PSC_AC97CFG);
-       au_sync();
-       ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       switch (num_channels) {
-       case 6:         /* stereo with surround and center/LFE,
-                        * slots 3,4,6,7,8,9
-                        */
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6);
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9);
-
-       case 4:         /* stereo with surround, slots 3,4,7,8 */
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7);
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8);
-
-       case 2:         /* stereo, slots 3,4 */
-       case 1:         /* mono */
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3);
-               ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4);
-       }
-
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       ac97_config |= PSC_AC97CFG_DE_ENABLE;
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       /* Wait for Device ready.
-       */
-       do {
-               stat = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-static void
-set_recv_slots(int num_channels)
-{
-       u32     ac97_config, stat;
-
-       ac97_config = au_readl(PSC_AC97CFG);
-       au_sync();
-       ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       /* Always enable slots 3 and 4 (stereo). Slot 6 is
-        * optional Mic ADC, which we don't support yet.
-        */
-       ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3);
-       ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4);
-
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       ac97_config |= PSC_AC97CFG_DE_ENABLE;
-       au_writel(ac97_config, PSC_AC97CFG);
-       au_sync();
-
-       /* Wait for Device ready.
-       */
-       do {
-               stat = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-/* Hold spinlock for both start_dac() and start_adc() calls */
-static void
-start_dac(struct au1550_state *s)
-{
-       struct dmabuf  *db = &s->dma_dac;
-
-       if (!db->stopped)
-               return;
-
-       set_xmit_slots(db->num_channels);
-       au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
-       au_sync();
-       au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
-       au_sync();
-
-       au1xxx_dbdma_start(db->dmanr);
-
-       db->stopped = 0;
-}
-
-static void
-start_adc(struct au1550_state *s)
-{
-       struct dmabuf  *db = &s->dma_adc;
-       int     i;
-
-       if (!db->stopped)
-               return;
-
-       /* Put two buffers on the ring to get things started.
-       */
-       for (i=0; i<2; i++) {
-               au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn),
-                               db->dma_fragsize, DDMA_FLAGS_IE);
-
-               db->nextIn += db->dma_fragsize;
-               if (db->nextIn >= db->rawbuf + db->dmasize)
-                       db->nextIn -= db->dmasize;
-       }
-
-       set_recv_slots(db->num_channels);
-       au1xxx_dbdma_start(db->dmanr);
-       au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
-       au_sync();
-       au_writel(PSC_AC97PCR_RS, PSC_AC97PCR);
-       au_sync();
-
-       db->stopped = 0;
-}
-
-static int
-prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
-{
-       unsigned user_bytes_per_sec;
-       unsigned        bufs;
-       unsigned        rate = db->sample_rate;
-
-       if (!db->rawbuf) {
-               db->ready = db->mapped = 0;
-               db->buforder = 5;       /* 32 * PAGE_SIZE */
-               db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
-               if (!db->rawbuf)
-                       return -ENOMEM;
-       }
-
-       db->cnt_factor = 1;
-       if (db->sample_size == 8)
-               db->cnt_factor *= 2;
-       if (db->num_channels == 1)
-               db->cnt_factor *= 2;
-       db->cnt_factor *= db->src_factor;
-
-       db->count = 0;
-       db->dma_qcount = 0;
-       db->nextIn = db->nextOut = db->rawbuf;
-
-       db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
-       db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
-                                       2 : db->num_channels);
-
-       user_bytes_per_sec = rate * db->user_bytes_per_sample;
-       bufs = PAGE_SIZE << db->buforder;
-       if (db->ossfragshift) {
-               if ((1000 << db->ossfragshift) < user_bytes_per_sec)
-                       db->fragshift = ld2(user_bytes_per_sec/1000);
-               else
-                       db->fragshift = db->ossfragshift;
-       } else {
-               db->fragshift = ld2(user_bytes_per_sec / 100 /
-                                   (db->subdivision ? db->subdivision : 1));
-               if (db->fragshift < 3)
-                       db->fragshift = 3;
-       }
-
-       db->fragsize = 1 << db->fragshift;
-       db->dma_fragsize = db->fragsize * db->cnt_factor;
-       db->numfrag = bufs / db->dma_fragsize;
-
-       while (db->numfrag < 4 && db->fragshift > 3) {
-               db->fragshift--;
-               db->fragsize = 1 << db->fragshift;
-               db->dma_fragsize = db->fragsize * db->cnt_factor;
-               db->numfrag = bufs / db->dma_fragsize;
-       }
-
-       if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-               db->numfrag = db->ossmaxfrags;
-
-       db->dmasize = db->dma_fragsize * db->numfrag;
-       memset(db->rawbuf, 0, bufs);
-
-       pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n",
-           rate, db->sample_size, db->num_channels);
-       pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n",
-           db->fragsize, db->cnt_factor, db->dma_fragsize);
-       pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize);
-
-       db->ready = 1;
-       return 0;
-}
-
-static int
-prog_dmabuf_adc(struct au1550_state *s)
-{
-       stop_adc(s);
-       return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static int
-prog_dmabuf_dac(struct au1550_state *s)
-{
-       stop_dac(s);
-       return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-static void dac_dma_interrupt(int irq, void *dev_id)
-{
-       struct au1550_state *s = (struct au1550_state *) dev_id;
-       struct dmabuf  *db = &s->dma_dac;
-       u32     ac97c_stat;
-
-       spin_lock(&s->lock);
-
-       ac97c_stat = au_readl(PSC_AC97STAT);
-       if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
-               pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
-       db->dma_qcount--;
-
-       if (db->count >= db->fragsize) {
-               if (au1xxx_dbdma_put_source(db->dmanr,
-                               virt_to_phys(db->nextOut), db->fragsize,
-                               DDMA_FLAGS_IE) == 0) {
-                       err("qcount < 2 and no ring room!");
-               }
-               db->nextOut += db->fragsize;
-               if (db->nextOut >= db->rawbuf + db->dmasize)
-                       db->nextOut -= db->dmasize;
-               db->count -= db->fragsize;
-               db->total_bytes += db->dma_fragsize;
-               db->dma_qcount++;
-       }
-
-       /* wake up anybody listening */
-       if (waitqueue_active(&db->wait))
-               wake_up(&db->wait);
-
-       spin_unlock(&s->lock);
-}
-
-
-static void adc_dma_interrupt(int irq, void *dev_id)
-{
-       struct  au1550_state *s = (struct au1550_state *)dev_id;
-       struct  dmabuf  *dp = &s->dma_adc;
-       u32     obytes;
-       char    *obuf;
-
-       spin_lock(&s->lock);
-
-       /* Pull the buffer from the dma queue.
-       */
-       au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
-
-       if ((dp->count + obytes) > dp->dmasize) {
-               /* Overrun. Stop ADC and log the error
-               */
-               spin_unlock(&s->lock);
-               stop_adc(s);
-               dp->error++;
-               err("adc overrun");
-               return;
-       }
-
-       /* Put a new empty buffer on the destination DMA.
-       */
-       au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn),
-                             dp->dma_fragsize, DDMA_FLAGS_IE);
-
-       dp->nextIn += dp->dma_fragsize;
-       if (dp->nextIn >= dp->rawbuf + dp->dmasize)
-               dp->nextIn -= dp->dmasize;
-
-       dp->count += obytes;
-       dp->total_bytes += obytes;
-
-       /* wake up anybody listening
-       */
-       if (waitqueue_active(&dp->wait))
-               wake_up(&dp->wait);
-
-       spin_unlock(&s->lock);
-}
-
-static loff_t
-au1550_llseek(struct file *file, loff_t offset, int origin)
-{
-       return -ESPIPE;
-}
-
-
-static int
-au1550_open_mixdev(struct inode *inode, struct file *file)
-{
-       mutex_lock(&au1550_ac97_mutex);
-       file->private_data = &au1550_state;
-       mutex_unlock(&au1550_ac97_mutex);
-       return 0;
-}
-
-static int
-au1550_release_mixdev(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int
-mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
-                        unsigned long arg)
-{
-       return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static long
-au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct au1550_state *s = file->private_data;
-       struct ac97_codec *codec = s->codec;
-       int ret;
-
-       mutex_lock(&au1550_ac97_mutex);
-       ret = mixdev_ioctl(codec, cmd, arg);
-       mutex_unlock(&au1550_ac97_mutex);
-
-       return ret;
-}
-
-static /*const */ struct file_operations au1550_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = au1550_llseek,
-       .unlocked_ioctl = au1550_ioctl_mixdev,
-       .open           = au1550_open_mixdev,
-       .release        = au1550_release_mixdev,
-};
-
-static int
-drain_dac(struct au1550_state *s, int nonblock)
-{
-       unsigned long   flags;
-       int             count, tmo;
-
-       if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
-               return 0;
-
-       for (;;) {
-               spin_lock_irqsave(&s->lock, flags);
-               count = s->dma_dac.count;
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count <= s->dma_dac.fragsize)
-                       break;
-               if (signal_pending(current))
-                       break;
-               if (nonblock)
-                       return -EBUSY;
-               tmo = 1000 * count / (s->no_vra ?
-                                     48000 : s->dma_dac.sample_rate);
-               tmo /= s->dma_dac.dma_bytes_per_sample;
-               au1550_delay(tmo);
-       }
-       if (signal_pending(current))
-               return -ERESTARTSYS;
-       return 0;
-}
-
-static inline u8 S16_TO_U8(s16 ch)
-{
-       return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
-       return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- *     If mono, copy left channel to right channel in dma buffer.
- *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- *     If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int
-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
-                                                              int dmacount)
-{
-       int             sample, i;
-       int             interp_bytes_per_sample;
-       int             num_samples;
-       int             mono = (db->num_channels == 1);
-       char            usersample[12];
-       s16             ch, dmasample[6];
-
-       if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-               /* no translation necessary, just copy
-               */
-               if (copy_from_user(dmabuf, userbuf, dmacount))
-                       return -EFAULT;
-               return dmacount;
-       }
-
-       interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-       num_samples = dmacount / interp_bytes_per_sample;
-
-       for (sample = 0; sample < num_samples; sample++) {
-               if (copy_from_user(usersample, userbuf,
-                                  db->user_bytes_per_sample)) {
-                       return -EFAULT;
-               }
-
-               for (i = 0; i < db->num_channels; i++) {
-                       if (db->sample_size == 8)
-                               ch = U8_TO_S16(usersample[i]);
-                       else
-                               ch = *((s16 *) (&usersample[i * 2]));
-                       dmasample[i] = ch;
-                       if (mono)
-                               dmasample[i + 1] = ch;  /* right channel */
-               }
-
-               /* duplicate every audio frame src_factor times
-               */
-               for (i = 0; i < db->src_factor; i++)
-                       memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
-               userbuf += db->user_bytes_per_sample;
-               dmabuf += interp_bytes_per_sample;
-       }
-
-       return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- *     If mono, send only left channel to user buffer.
- *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- *     If decimating (no VRA), skip over src_factor audio frames.
- */
-static int
-translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
-                                                            int dmacount)
-{
-       int             sample, i;
-       int             interp_bytes_per_sample;
-       int             num_samples;
-       int             mono = (db->num_channels == 1);
-       char            usersample[12];
-
-       if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-               /* no translation necessary, just copy
-               */
-               if (copy_to_user(userbuf, dmabuf, dmacount))
-                       return -EFAULT;
-               return dmacount;
-       }
-
-       interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-       num_samples = dmacount / interp_bytes_per_sample;
-
-       for (sample = 0; sample < num_samples; sample++) {
-               for (i = 0; i < db->num_channels; i++) {
-                       if (db->sample_size == 8)
-                               usersample[i] =
-                                       S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
-                       else
-                               *((s16 *) (&usersample[i * 2])) =
-                                       *((s16 *) (&dmabuf[i * 2]));
-               }
-
-               if (copy_to_user(userbuf, usersample,
-                                db->user_bytes_per_sample)) {
-                       return -EFAULT;
-               }
-
-               userbuf += db->user_bytes_per_sample;
-               dmabuf += interp_bytes_per_sample;
-       }
-
-       return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int
-copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
-{
-       char           *bufptr = to_user ? db->nextOut : db->nextIn;
-       char           *bufend = db->rawbuf + db->dmasize;
-       int             cnt, ret;
-
-       if (bufptr + count > bufend) {
-               int             partial = (int) (bufend - bufptr);
-               if (to_user) {
-                       if ((cnt = translate_to_user(db, userbuf,
-                                                    bufptr, partial)) < 0)
-                               return cnt;
-                       ret = cnt;
-                       if ((cnt = translate_to_user(db, userbuf + partial,
-                                                    db->rawbuf,
-                                                    count - partial)) < 0)
-                               return cnt;
-                       ret += cnt;
-               } else {
-                       if ((cnt = translate_from_user(db, bufptr, userbuf,
-                                                      partial)) < 0)
-                               return cnt;
-                       ret = cnt;
-                       if ((cnt = translate_from_user(db, db->rawbuf,
-                                                      userbuf + partial,
-                                                      count - partial)) < 0)
-                               return cnt;
-                       ret += cnt;
-               }
-       } else {
-               if (to_user)
-                       ret = translate_to_user(db, userbuf, bufptr, count);
-               else
-                       ret = translate_from_user(db, bufptr, userbuf, count);
-       }
-
-       return ret;
-}
-
-
-static ssize_t
-au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
-       struct au1550_state *s = file->private_data;
-       struct dmabuf  *db = &s->dma_adc;
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t         ret;
-       unsigned long   flags;
-       int             cnt, usercnt, avail;
-
-       if (db->mapped)
-               return -ENXIO;
-       if (!access_ok(VERIFY_WRITE, buffer, count))
-               return -EFAULT;
-       ret = 0;
-
-       count *= db->cnt_factor;
-
-       mutex_lock(&s->sem);
-       add_wait_queue(&db->wait, &wait);
-
-       while (count > 0) {
-               /* wait for samples in ADC dma buffer
-               */
-               do {
-                       spin_lock_irqsave(&s->lock, flags);
-                       if (db->stopped)
-                               start_adc(s);
-                       avail = db->count;
-                       if (avail <= 0)
-                               __set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irqrestore(&s->lock, flags);
-                       if (avail <= 0) {
-                               if (file->f_flags & O_NONBLOCK) {
-                                       if (!ret)
-                                               ret = -EAGAIN;
-                                       goto out;
-                               }
-                               mutex_unlock(&s->sem);
-                               schedule();
-                               if (signal_pending(current)) {
-                                       if (!ret)
-                                               ret = -ERESTARTSYS;
-                                       goto out2;
-                               }
-                               mutex_lock(&s->sem);
-                       }
-               } while (avail <= 0);
-
-               /* copy from nextOut to user
-               */
-               if ((cnt = copy_dmabuf_user(db, buffer,
-                                           count > avail ?
-                                           avail : count, 1)) < 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       goto out;
-               }
-
-               spin_lock_irqsave(&s->lock, flags);
-               db->count -= cnt;
-               db->nextOut += cnt;
-               if (db->nextOut >= db->rawbuf + db->dmasize)
-                       db->nextOut -= db->dmasize;
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               count -= cnt;
-               usercnt = cnt / db->cnt_factor;
-               buffer += usercnt;
-               ret += usercnt;
-       }                       /* while (count > 0) */
-
-out:
-       mutex_unlock(&s->sem);
-out2:
-       remove_wait_queue(&db->wait, &wait);
-       set_current_state(TASK_RUNNING);
-       return ret;
-}
-
-static ssize_t
-au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
-{
-       struct au1550_state *s = file->private_data;
-       struct dmabuf  *db = &s->dma_dac;
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t         ret = 0;
-       unsigned long   flags;
-       int             cnt, usercnt, avail;
-
-       pr_debug("write: count=%d\n", count);
-
-       if (db->mapped)
-               return -ENXIO;
-       if (!access_ok(VERIFY_READ, buffer, count))
-               return -EFAULT;
-
-       count *= db->cnt_factor;
-
-       mutex_lock(&s->sem);
-       add_wait_queue(&db->wait, &wait);
-
-       while (count > 0) {
-               /* wait for space in playback buffer
-               */
-               do {
-                       spin_lock_irqsave(&s->lock, flags);
-                       avail = (int) db->dmasize - db->count;
-                       if (avail <= 0)
-                               __set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irqrestore(&s->lock, flags);
-                       if (avail <= 0) {
-                               if (file->f_flags & O_NONBLOCK) {
-                                       if (!ret)
-                                               ret = -EAGAIN;
-                                       goto out;
-                               }
-                               mutex_unlock(&s->sem);
-                               schedule();
-                               if (signal_pending(current)) {
-                                       if (!ret)
-                                               ret = -ERESTARTSYS;
-                                       goto out2;
-                               }
-                               mutex_lock(&s->sem);
-                       }
-               } while (avail <= 0);
-
-               /* copy from user to nextIn
-               */
-               if ((cnt = copy_dmabuf_user(db, (char *) buffer,
-                                           count > avail ?
-                                           avail : count, 0)) < 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       goto out;
-               }
-
-               spin_lock_irqsave(&s->lock, flags);
-               db->count += cnt;
-               db->nextIn += cnt;
-               if (db->nextIn >= db->rawbuf + db->dmasize)
-                       db->nextIn -= db->dmasize;
-
-               /* If the data is available, we want to keep two buffers
-                * on the dma queue.  If the queue count reaches zero,
-                * we know the dma has stopped.
-                */
-               while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
-                       if (au1xxx_dbdma_put_source(db->dmanr,
-                               virt_to_phys(db->nextOut), db->fragsize,
-                               DDMA_FLAGS_IE) == 0) {
-                               err("qcount < 2 and no ring room!");
-                       }
-                       db->nextOut += db->fragsize;
-                       if (db->nextOut >= db->rawbuf + db->dmasize)
-                               db->nextOut -= db->dmasize;
-                       db->total_bytes += db->dma_fragsize;
-                       if (db->dma_qcount == 0)
-                               start_dac(s);
-                       db->dma_qcount++;
-               }
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               count -= cnt;
-               usercnt = cnt / db->cnt_factor;
-               buffer += usercnt;
-               ret += usercnt;
-       }                       /* while (count > 0) */
-
-out:
-       mutex_unlock(&s->sem);
-out2:
-       remove_wait_queue(&db->wait, &wait);
-       set_current_state(TASK_RUNNING);
-       return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int
-au1550_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct au1550_state *s = file->private_data;
-       unsigned long   flags;
-       unsigned int    mask = 0;
-
-       if (file->f_mode & FMODE_WRITE) {
-               if (!s->dma_dac.ready)
-                       return 0;
-               poll_wait(file, &s->dma_dac.wait, wait);
-       }
-       if (file->f_mode & FMODE_READ) {
-               if (!s->dma_adc.ready)
-                       return 0;
-               poll_wait(file, &s->dma_adc.wait, wait);
-       }
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       if (file->f_mode & FMODE_READ) {
-               if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-       if (file->f_mode & FMODE_WRITE) {
-               if (s->dma_dac.mapped) {
-                       if (s->dma_dac.count >=
-                           (signed)s->dma_dac.dma_fragsize)
-                               mask |= POLLOUT | POLLWRNORM;
-               } else {
-                       if ((signed) s->dma_dac.dmasize >=
-                           s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
-                               mask |= POLLOUT | POLLWRNORM;
-               }
-       }
-       spin_unlock_irqrestore(&s->lock, flags);
-       return mask;
-}
-
-static int
-au1550_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct au1550_state *s = file->private_data;
-       struct dmabuf  *db;
-       unsigned long   size;
-       int ret = 0;
-
-       mutex_lock(&au1550_ac97_mutex);
-       mutex_lock(&s->sem);
-       if (vma->vm_flags & VM_WRITE)
-               db = &s->dma_dac;
-       else if (vma->vm_flags & VM_READ)
-               db = &s->dma_adc;
-       else {
-               ret = -EINVAL;
-               goto out;
-       }
-       if (vma->vm_pgoff != 0) {
-               ret = -EINVAL;
-               goto out;
-       }
-       size = vma->vm_end - vma->vm_start;
-       if (size > (PAGE_SIZE << db->buforder)) {
-               ret = -EINVAL;
-               goto out;
-       }
-       if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)),
-                            size, vma->vm_page_prot)) {
-               ret = -EAGAIN;
-               goto out;
-       }
-       vma->vm_flags &= ~VM_IO;
-       db->mapped = 1;
-out:
-       mutex_unlock(&s->sem);
-       mutex_unlock(&au1550_ac97_mutex);
-       return ret;
-}
-
-#ifdef DEBUG
-static struct ioctl_str_t {
-       unsigned int    cmd;
-       const char     *str;
-} ioctl_str[] = {
-       {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
-       {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
-       {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
-       {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
-       {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
-       {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
-       {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
-       {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
-       {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
-       {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
-       {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
-       {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
-       {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
-       {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
-       {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
-       {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
-       {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
-       {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
-       {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
-       {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
-       {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
-       {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
-       {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
-       {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
-       {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
-       {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
-       {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
-       {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
-       {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
-       {OSS_GETVERSION, "OSS_GETVERSION"},
-       {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
-       {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
-       {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
-       {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-static int
-dma_count_done(struct dmabuf *db)
-{
-       if (db->stopped)
-               return 0;
-
-       return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
-}
-
-
-static int
-au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct au1550_state *s = file->private_data;
-       unsigned long   flags;
-       audio_buf_info  abinfo;
-       count_info      cinfo;
-       int             count;
-       int             val, mapped, ret, diff;
-
-       mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-               ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef DEBUG
-       for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) {
-               if (ioctl_str[count].cmd == cmd)
-                       break;
-       }
-       if (count < ARRAY_SIZE(ioctl_str))
-               pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg);
-       else
-               pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg);
-#endif
-
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, (int *) arg);
-
-       case SNDCTL_DSP_SYNC:
-               if (file->f_mode & FMODE_WRITE)
-                       return drain_dac(s, file->f_flags & O_NONBLOCK);
-               return 0;
-
-       case SNDCTL_DSP_SETDUPLEX:
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
-                               DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
-       case SNDCTL_DSP_RESET:
-               if (file->f_mode & FMODE_WRITE) {
-                       stop_dac(s);
-                       synchronize_irq();
-                       s->dma_dac.count = s->dma_dac.total_bytes = 0;
-                       s->dma_dac.nextIn = s->dma_dac.nextOut =
-                               s->dma_dac.rawbuf;
-               }
-               if (file->f_mode & FMODE_READ) {
-                       stop_adc(s);
-                       synchronize_irq();
-                       s->dma_adc.count = s->dma_adc.total_bytes = 0;
-                       s->dma_adc.nextIn = s->dma_adc.nextOut =
-                               s->dma_adc.rawbuf;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SPEED:
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (val >= 0) {
-                       if (file->f_mode & FMODE_READ) {
-                               stop_adc(s);
-                               set_adc_rate(s, val);
-                       }
-                       if (file->f_mode & FMODE_WRITE) {
-                               stop_dac(s);
-                               set_dac_rate(s, val);
-                       }
-                       if (s->open_mode & FMODE_READ)
-                               if ((ret = prog_dmabuf_adc(s)))
-                                       return ret;
-                       if (s->open_mode & FMODE_WRITE)
-                               if ((ret = prog_dmabuf_dac(s)))
-                                       return ret;
-               }
-               return put_user((file->f_mode & FMODE_READ) ?
-                               s->dma_adc.sample_rate :
-                               s->dma_dac.sample_rate,
-                               (int *)arg);
-
-       case SNDCTL_DSP_STEREO:
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       stop_adc(s);
-                       s->dma_adc.num_channels = val ? 2 : 1;
-                       if ((ret = prog_dmabuf_adc(s)))
-                               return ret;
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       stop_dac(s);
-                       s->dma_dac.num_channels = val ? 2 : 1;
-                       if (s->codec_ext_caps & AC97_EXT_DACS) {
-                               /* disable surround and center/lfe in AC'97
-                               */
-                               u16 ext_stat = rdcodec(s->codec,
-                                                      AC97_EXTENDED_STATUS);
-                               wrcodec(s->codec, AC97_EXTENDED_STATUS,
-                                       ext_stat | (AC97_EXTSTAT_PRI |
-                                                   AC97_EXTSTAT_PRJ |
-                                                   AC97_EXTSTAT_PRK));
-                       }
-                       if ((ret = prog_dmabuf_dac(s)))
-                               return ret;
-               }
-               return 0;
-
-       case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (val != 0) {
-                       if (file->f_mode & FMODE_READ) {
-                               if (val < 0 || val > 2)
-                                       return -EINVAL;
-                               stop_adc(s);
-                               s->dma_adc.num_channels = val;
-                               if ((ret = prog_dmabuf_adc(s)))
-                                       return ret;
-                       }
-                       if (file->f_mode & FMODE_WRITE) {
-                               switch (val) {
-                               case 1:
-                               case 2:
-                                       break;
-                               case 3:
-                               case 5:
-                                       return -EINVAL;
-                               case 4:
-                                       if (!(s->codec_ext_caps &
-                                             AC97_EXTID_SDAC))
-                                               return -EINVAL;
-                                       break;
-                               case 6:
-                                       if ((s->codec_ext_caps &
-                                            AC97_EXT_DACS) != AC97_EXT_DACS)
-                                               return -EINVAL;
-                                       break;
-                               default:
-                                       return -EINVAL;
-                               }
-
-                               stop_dac(s);
-                               if (val <= 2 &&
-                                   (s->codec_ext_caps & AC97_EXT_DACS)) {
-                                       /* disable surround and center/lfe
-                                        * channels in AC'97
-                                        */
-                                       u16             ext_stat =
-                                               rdcodec(s->codec,
-                                                       AC97_EXTENDED_STATUS);
-                                       wrcodec(s->codec,
-                                               AC97_EXTENDED_STATUS,
-                                               ext_stat | (AC97_EXTSTAT_PRI |
-                                                           AC97_EXTSTAT_PRJ |
-                                                           AC97_EXTSTAT_PRK));
-                               } else if (val >= 4) {
-                                       /* enable surround, center/lfe
-                                        * channels in AC'97
-                                        */
-                                       u16             ext_stat =
-                                               rdcodec(s->codec,
-                                                       AC97_EXTENDED_STATUS);
-                                       ext_stat &= ~AC97_EXTSTAT_PRJ;
-                                       if (val == 6)
-                                               ext_stat &=
-                                                       ~(AC97_EXTSTAT_PRI |
-                                                         AC97_EXTSTAT_PRK);
-                                       wrcodec(s->codec,
-                                               AC97_EXTENDED_STATUS,
-                                               ext_stat);
-                               }
-
-                               s->dma_dac.num_channels = val;
-                               if ((ret = prog_dmabuf_dac(s)))
-                                       return ret;
-                       }
-               }
-               return put_user(val, (int *) arg);
-
-       case SNDCTL_DSP_GETFMTS:        /* Returns a mask */
-               return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
-       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (val != AFMT_QUERY) {
-                       if (file->f_mode & FMODE_READ) {
-                               stop_adc(s);
-                               if (val == AFMT_S16_LE)
-                                       s->dma_adc.sample_size = 16;
-                               else {
-                                       val = AFMT_U8;
-                                       s->dma_adc.sample_size = 8;
-                               }
-                               if ((ret = prog_dmabuf_adc(s)))
-                                       return ret;
-                       }
-                       if (file->f_mode & FMODE_WRITE) {
-                               stop_dac(s);
-                               if (val == AFMT_S16_LE)
-                                       s->dma_dac.sample_size = 16;
-                               else {
-                                       val = AFMT_U8;
-                                       s->dma_dac.sample_size = 8;
-                               }
-                               if ((ret = prog_dmabuf_dac(s)))
-                                       return ret;
-                       }
-               } else {
-                       if (file->f_mode & FMODE_READ)
-                               val = (s->dma_adc.sample_size == 16) ?
-                                       AFMT_S16_LE : AFMT_U8;
-                       else
-                               val = (s->dma_dac.sample_size == 16) ?
-                                       AFMT_S16_LE : AFMT_U8;
-               }
-               return put_user(val, (int *) arg);
-
-       case SNDCTL_DSP_POST:
-               return 0;
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-               spin_lock_irqsave(&s->lock, flags);
-               if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
-                       val |= PCM_ENABLE_INPUT;
-               if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
-                       val |= PCM_ENABLE_OUTPUT;
-               spin_unlock_irqrestore(&s->lock, flags);
-               return put_user(val, (int *) arg);
-
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       if (val & PCM_ENABLE_INPUT) {
-                               spin_lock_irqsave(&s->lock, flags);
-                               start_adc(s);
-                               spin_unlock_irqrestore(&s->lock, flags);
-                       } else
-                               stop_adc(s);
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       if (val & PCM_ENABLE_OUTPUT) {
-                               spin_lock_irqsave(&s->lock, flags);
-                               start_dac(s);
-                               spin_unlock_irqrestore(&s->lock, flags);
-                       } else
-                               stop_dac(s);
-               }
-               return 0;
-
-       case SNDCTL_DSP_GETOSPACE:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               abinfo.fragsize = s->dma_dac.fragsize;
-               spin_lock_irqsave(&s->lock, flags);
-               count = s->dma_dac.count;
-               count -= dma_count_done(&s->dma_dac);
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count < 0)
-                       count = 0;
-               abinfo.bytes = (s->dma_dac.dmasize - count) /
-                       s->dma_dac.cnt_factor;
-               abinfo.fragstotal = s->dma_dac.numfrag;
-               abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-               pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments);
-               return copy_to_user((void *) arg, &abinfo,
-                                   sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETISPACE:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               abinfo.fragsize = s->dma_adc.fragsize;
-               spin_lock_irqsave(&s->lock, flags);
-               count = s->dma_adc.count;
-               count += dma_count_done(&s->dma_adc);
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count < 0)
-                       count = 0;
-               abinfo.bytes = count / s->dma_adc.cnt_factor;
-               abinfo.fragstotal = s->dma_adc.numfrag;
-               abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
-               return copy_to_user((void *) arg, &abinfo,
-                                   sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_NONBLOCK:
-               spin_lock(&file->f_lock);
-               file->f_flags |= O_NONBLOCK;
-               spin_unlock(&file->f_lock);
-               return 0;
-
-       case SNDCTL_DSP_GETODELAY:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               spin_lock_irqsave(&s->lock, flags);
-               count = s->dma_dac.count;
-               count -= dma_count_done(&s->dma_dac);
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count < 0)
-                       count = 0;
-               count /= s->dma_dac.cnt_factor;
-               return put_user(count, (int *) arg);
-
-       case SNDCTL_DSP_GETIPTR:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               spin_lock_irqsave(&s->lock, flags);
-               cinfo.bytes = s->dma_adc.total_bytes;
-               count = s->dma_adc.count;
-               if (!s->dma_adc.stopped) {
-                       diff = dma_count_done(&s->dma_adc);
-                       count += diff;
-                       cinfo.bytes += diff;
-                       cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
-                               virt_to_phys(s->dma_adc.rawbuf);
-               } else
-                       cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
-                               virt_to_phys(s->dma_adc.rawbuf);
-               if (s->dma_adc.mapped)
-                       s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count < 0)
-                       count = 0;
-               cinfo.blocks = count >> s->dma_adc.fragshift;
-               return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-       case SNDCTL_DSP_GETOPTR:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               spin_lock_irqsave(&s->lock, flags);
-               cinfo.bytes = s->dma_dac.total_bytes;
-               count = s->dma_dac.count;
-               if (!s->dma_dac.stopped) {
-                       diff = dma_count_done(&s->dma_dac);
-                       count -= diff;
-                       cinfo.bytes += diff;
-                       cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
-                               virt_to_phys(s->dma_dac.rawbuf);
-               } else
-                       cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
-                               virt_to_phys(s->dma_dac.rawbuf);
-               if (s->dma_dac.mapped)
-                       s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
-               spin_unlock_irqrestore(&s->lock, flags);
-               if (count < 0)
-                       count = 0;
-               cinfo.blocks = count >> s->dma_dac.fragshift;
-               return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               if (file->f_mode & FMODE_WRITE)
-                       return put_user(s->dma_dac.fragsize, (int *) arg);
-               else
-                       return put_user(s->dma_adc.fragsize, (int *) arg);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       stop_adc(s);
-                       s->dma_adc.ossfragshift = val & 0xffff;
-                       s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (s->dma_adc.ossfragshift < 4)
-                               s->dma_adc.ossfragshift = 4;
-                       if (s->dma_adc.ossfragshift > 15)
-                               s->dma_adc.ossfragshift = 15;
-                       if (s->dma_adc.ossmaxfrags < 4)
-                               s->dma_adc.ossmaxfrags = 4;
-                       if ((ret = prog_dmabuf_adc(s)))
-                               return ret;
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       stop_dac(s);
-                       s->dma_dac.ossfragshift = val & 0xffff;
-                       s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (s->dma_dac.ossfragshift < 4)
-                               s->dma_dac.ossfragshift = 4;
-                       if (s->dma_dac.ossfragshift > 15)
-                               s->dma_dac.ossfragshift = 15;
-                       if (s->dma_dac.ossmaxfrags < 4)
-                               s->dma_dac.ossmaxfrags = 4;
-                       if ((ret = prog_dmabuf_dac(s)))
-                               return ret;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SUBDIVIDE:
-               if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-                   (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-                       return -EINVAL;
-               if (get_user(val, (int *) arg))
-                       return -EFAULT;
-               if (val != 1 && val != 2 && val != 4)
-                       return -EINVAL;
-               if (file->f_mode & FMODE_READ) {
-                       stop_adc(s);
-                       s->dma_adc.subdivision = val;
-                       if ((ret = prog_dmabuf_adc(s)))
-                               return ret;
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       stop_dac(s);
-                       s->dma_dac.subdivision = val;
-                       if ((ret = prog_dmabuf_dac(s)))
-                               return ret;
-               }
-               return 0;
-
-       case SOUND_PCM_READ_RATE:
-               return put_user((file->f_mode & FMODE_READ) ?
-                               s->dma_adc.sample_rate :
-                               s->dma_dac.sample_rate,
-                               (int *)arg);
-
-       case SOUND_PCM_READ_CHANNELS:
-               if (file->f_mode & FMODE_READ)
-                       return put_user(s->dma_adc.num_channels, (int *)arg);
-               else
-                       return put_user(s->dma_dac.num_channels, (int *)arg);
-
-       case SOUND_PCM_READ_BITS:
-               if (file->f_mode & FMODE_READ)
-                       return put_user(s->dma_adc.sample_size, (int *)arg);
-               else
-                       return put_user(s->dma_dac.sample_size, (int *)arg);
-
-       case SOUND_PCM_WRITE_FILTER:
-       case SNDCTL_DSP_SETSYNCRO:
-       case SOUND_PCM_READ_FILTER:
-               return -EINVAL;
-       }
-
-       return mixdev_ioctl(s->codec, cmd, arg);
-}
-
-static long
-au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int ret;
-
-       mutex_lock(&au1550_ac97_mutex);
-       ret = au1550_ioctl(file, cmd, arg);
-       mutex_unlock(&au1550_ac97_mutex);
-
-       return ret;
-}
-
-static int
-au1550_open(struct inode *inode, struct file *file)
-{
-       int             minor = MINOR(inode->i_rdev);
-       DECLARE_WAITQUEUE(wait, current);
-       struct au1550_state *s = &au1550_state;
-       int             ret;
-
-#ifdef DEBUG
-       if (file->f_flags & O_NONBLOCK)
-               pr_debug("open: non-blocking\n");
-       else
-               pr_debug("open: blocking\n");
-#endif
-
-       file->private_data = s;
-       mutex_lock(&au1550_ac97_mutex);
-       /* wait for device to become free */
-       mutex_lock(&s->open_mutex);
-       while (s->open_mode & file->f_mode) {
-               ret = -EBUSY;
-               if (file->f_flags & O_NONBLOCK)
-                       goto out;
-               add_wait_queue(&s->open_wait, &wait);
-               __set_current_state(TASK_INTERRUPTIBLE);
-               mutex_unlock(&s->open_mutex);
-               schedule();
-               remove_wait_queue(&s->open_wait, &wait);
-               set_current_state(TASK_RUNNING);
-               ret = -ERESTARTSYS;
-               if (signal_pending(current))
-                       goto out2;
-               mutex_lock(&s->open_mutex);
-       }
-
-       stop_dac(s);
-       stop_adc(s);
-
-       if (file->f_mode & FMODE_READ) {
-               s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
-                       s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
-               s->dma_adc.num_channels = 1;
-               s->dma_adc.sample_size = 8;
-               set_adc_rate(s, 8000);
-               if ((minor & 0xf) == SND_DEV_DSP16)
-                       s->dma_adc.sample_size = 16;
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
-                       s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
-               s->dma_dac.num_channels = 1;
-               s->dma_dac.sample_size = 8;
-               set_dac_rate(s, 8000);
-               if ((minor & 0xf) == SND_DEV_DSP16)
-                       s->dma_dac.sample_size = 16;
-       }
-
-       if (file->f_mode & FMODE_READ) {
-               if ((ret = prog_dmabuf_adc(s)))
-                       goto out;
-       }
-       if (file->f_mode & FMODE_WRITE) {
-               if ((ret = prog_dmabuf_dac(s)))
-                       goto out;
-       }
-
-       s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-       mutex_init(&s->sem);
-       ret = 0;
-out:
-       mutex_unlock(&s->open_mutex);
-out2:
-       mutex_unlock(&au1550_ac97_mutex);
-       return ret;
-}
-
-static int
-au1550_release(struct inode *inode, struct file *file)
-{
-       struct au1550_state *s = file->private_data;
-
-       mutex_lock(&au1550_ac97_mutex);
-
-       if (file->f_mode & FMODE_WRITE) {
-               mutex_unlock(&au1550_ac97_mutex);
-               drain_dac(s, file->f_flags & O_NONBLOCK);
-               mutex_lock(&au1550_ac97_mutex);
-       }
-
-       mutex_lock(&s->open_mutex);
-       if (file->f_mode & FMODE_WRITE) {
-               stop_dac(s);
-               kfree(s->dma_dac.rawbuf);
-               s->dma_dac.rawbuf = NULL;
-       }
-       if (file->f_mode & FMODE_READ) {
-               stop_adc(s);
-               kfree(s->dma_adc.rawbuf);
-               s->dma_adc.rawbuf = NULL;
-       }
-       s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-       mutex_unlock(&s->open_mutex);
-       wake_up(&s->open_wait);
-       mutex_unlock(&au1550_ac97_mutex);
-       return 0;
-}
-
-static /*const */ struct file_operations au1550_audio_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = au1550_llseek,
-       .read           = au1550_read,
-       .write          = au1550_write,
-       .poll           = au1550_poll,
-       .unlocked_ioctl = au1550_unlocked_ioctl,
-       .mmap           = au1550_mmap,
-       .open           = au1550_open,
-       .release        = au1550_release,
-};
-
-MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
-MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
-MODULE_LICENSE("GPL");
-
-
-static int __devinit
-au1550_probe(void)
-{
-       struct au1550_state *s = &au1550_state;
-       int             val;
-
-       memset(s, 0, sizeof(struct au1550_state));
-
-       init_waitqueue_head(&s->dma_adc.wait);
-       init_waitqueue_head(&s->dma_dac.wait);
-       init_waitqueue_head(&s->open_wait);
-       mutex_init(&s->open_mutex);
-       spin_lock_init(&s->lock);
-
-       s->codec = ac97_alloc_codec();
-       if(s->codec == NULL) {
-               err("Out of memory");
-               return -1;
-       }
-       s->codec->private_data = s;
-       s->codec->id = 0;
-       s->codec->codec_read = rdcodec;
-       s->codec->codec_write = wrcodec;
-       s->codec->codec_wait = waitcodec;
-
-       if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL),
-                           0x30, "Au1550 AC97")) {
-               err("AC'97 ports in use");
-       }
-
-       /* Allocate the DMA Channels
-       */
-       if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
-           DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
-               err("Can't get DAC DMA");
-               goto err_dma1;
-       }
-       au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
-       if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
-                                       NUM_DBDMA_DESCRIPTORS) == 0) {
-               err("Can't get DAC DMA descriptors");
-               goto err_dma1;
-       }
-
-       if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,
-           DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
-               err("Can't get ADC DMA");
-               goto err_dma2;
-       }
-       au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
-       if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
-                                       NUM_DBDMA_DESCRIPTORS) == 0) {
-               err("Can't get ADC DMA descriptors");
-               goto err_dma2;
-       }
-
-       pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN);
-
-       /* register devices */
-
-       if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
-               goto err_dev1;
-       if ((s->codec->dev_mixer =
-            register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
-               goto err_dev2;
-
-       /* The GPIO for the appropriate PSC was configured by the
-        * board specific start up.
-        *
-        * configure PSC for AC'97
-        */
-       au_writel(0, AC97_PSC_CTRL);    /* Disable PSC */
-       au_sync();
-       au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);
-       au_sync();
-
-       /* cold reset the AC'97
-       */
-       au_writel(PSC_AC97RST_RST, PSC_AC97RST);
-       au_sync();
-       au1550_delay(10);
-       au_writel(0, PSC_AC97RST);
-       au_sync();
-
-       /* need to delay around 500msec(bleech) to give
-          some CODECs enough time to wakeup */
-       au1550_delay(500);
-
-       /* warm reset the AC'97 to start the bitclk
-       */
-       au_writel(PSC_AC97RST_SNC, PSC_AC97RST);
-       au_sync();
-       udelay(100);
-       au_writel(0, PSC_AC97RST);
-       au_sync();
-
-       /* Enable PSC
-       */
-       au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);
-       au_sync();
-
-       /* Wait for PSC ready.
-       */
-       do {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((val & PSC_AC97STAT_SR) == 0);
-
-       /* Configure AC97 controller.
-        * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
-        */
-       val = PSC_AC97CFG_SET_LEN(16);
-       val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8;
-
-       /* Enable device so we can at least
-        * talk over the AC-link.
-        */
-       au_writel(val, PSC_AC97CFG);
-       au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);
-       au_sync();
-       val |= PSC_AC97CFG_DE_ENABLE;
-       au_writel(val, PSC_AC97CFG);
-       au_sync();
-
-       /* Wait for Device ready.
-       */
-       do {
-               val = au_readl(PSC_AC97STAT);
-               au_sync();
-       } while ((val & PSC_AC97STAT_DR) == 0);
-
-       /* codec init */
-       if (!ac97_probe_codec(s->codec))
-               goto err_dev3;
-
-       s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
-       s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
-       pr_info("AC'97 Base/Extended ID = %04x/%04x",
-            s->codec_base_caps, s->codec_ext_caps);
-
-       if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
-               /* codec does not support VRA
-               */
-               s->no_vra = 1;
-       } else if (!vra) {
-               /* Boot option says disable VRA
-               */
-               u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-               wrcodec(s->codec, AC97_EXTENDED_STATUS,
-                       ac97_extstat & ~AC97_EXTSTAT_VRA);
-               s->no_vra = 1;
-       }
-       if (s->no_vra)
-               pr_info("no VRA, interpolating and decimating");
-
-       /* set mic to be the recording source */
-       val = SOUND_MASK_MIC;
-       mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
-                    (unsigned long) &val);
-
-       return 0;
-
- err_dev3:
-       unregister_sound_mixer(s->codec->dev_mixer);
- err_dev2:
-       unregister_sound_dsp(s->dev_audio);
- err_dev1:
-       au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
- err_dma2:
-       au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
- err_dma1:
-       release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-
-       ac97_release_codec(s->codec);
-       return -1;
-}
-
-static void __devinit
-au1550_remove(void)
-{
-       struct au1550_state *s = &au1550_state;
-
-       if (!s)
-               return;
-       synchronize_irq();
-       au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
-       au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
-       release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-       unregister_sound_dsp(s->dev_audio);
-       unregister_sound_mixer(s->codec->dev_mixer);
-       ac97_release_codec(s->codec);
-}
-
-static int __init
-init_au1550(void)
-{
-       return au1550_probe();
-}
-
-static void __exit
-cleanup_au1550(void)
-{
-       au1550_remove();
-}
-
-module_init(init_au1550);
-module_exit(cleanup_au1550);
-
-#ifndef MODULE
-
-static int __init
-au1550_setup(char *options)
-{
-       char           *this_opt;
-
-       if (!options || !*options)
-               return 0;
-
-       while ((this_opt = strsep(&options, ","))) {
-               if (!*this_opt)
-                       continue;
-               if (!strncmp(this_opt, "vra", 3)) {
-                       vra = 1;
-               }
-       }
-
-       return 1;
-}
-
-__setup("au1550_audio=", au1550_setup);
-
-#endif /* MODULE */
index 389cd7931668a233199555dfb19fb0dac7521a28..e90d103e177eab214d07dcc8e5a51ea62d91d76f 100644 (file)
@@ -534,6 +534,14 @@ config SND_ES1968_INPUT
          If you say N the buttons will directly control the master volume.
          It is recommended to say Y.
 
+config SND_ES1968_RADIO
+       bool "Enable TEA5757 radio tuner support for es1968"
+       depends on SND_ES1968
+       depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968
+       help
+         Say Y here to include support for TEA5757 radio tuner integrated on
+         some MediaForte cards (e.g. SF64-PCE2).
+
 config SND_FM801
        tristate "ForteMedia FM801"
        select SND_OPL3_LIB
@@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL
        depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
        help
          Say Y here to include support for soundcards based on the ForteMedia
-         FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
-         Forte SF256-PCS-02) into the snd-fm801 driver.
+         FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
+         SF64-PCR) into the snd-fm801 driver.
 
-config SND_FM801_TEA575X
+config SND_TEA575X
        tristate
-       depends on SND_FM801_TEA575X_BOOL
-       default SND_FM801
+       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
+       default SND_FM801 || SND_ES1968
 
 source "sound/pci/hda/Kconfig"
 
@@ -658,6 +666,15 @@ config SND_KORG1212
          To compile this driver as a module, choose M here: the module
          will be called snd-korg1212.
 
+config SND_LOLA
+       tristate "Digigram Lola"
+       select SND_PCM
+       help
+         Say Y to include support for Digigram Lola boards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-lola.
+
 config SND_LX6464ES
        tristate "Digigram LX6464ES"
        select SND_PCM
index 9cf4348ec137bd94bacc0213e613b2e5a24866b5..54fe325e3aa5160267e2ac83ba5d8efd255f08fc 100644 (file)
@@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \
        ca0106/ \
        cs46xx/ \
        cs5535audio/ \
+       lola/ \
        lx6464es/ \
        echoaudio/ \
        emu10k1/ \
index f8ccc9677c6f394ab85d9fe8bb134a0f75d55961..2ca6f4f85b412a18502ac0f6370d19cc604d7d56 100644 (file)
 #include <sound/tlv.h>
 #include <sound/hwdep.h>
 
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 
+#if defined CONFIG_SND_DEBUG
+/* copied from pcm_lib.c, hope later patch will make that version public
+and this copy can be removed */
+static void pcm_debug_name(struct snd_pcm_substream *substream,
+                          char *name, size_t len)
+{
+       snprintf(name, len, "pcmC%dD%d%c:%d",
+                substream->pcm->card->number,
+                substream->pcm->device,
+                substream->stream ? 'c' : 'p',
+                substream->number);
+}
+#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
+#else
+#define pcm_debug_name(s, n, l) do { } while (0)
+#define DEBUG_NAME(name, substream) do { } while (0)
+#endif
+
 #if defined CONFIG_SND_DEBUG_VERBOSE
 /**
  * snd_printddd - very verbose debug printk
@@ -58,7 +77,7 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 #define snd_printddd(format, args...) \
        __snd_printk(3, __FILE__, __LINE__, format, ##args)
 #else
-#define snd_printddd(format, args...)  do { } while (0)
+#define snd_printddd(format, args...) do { } while (0)
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* index 0-MAX */
@@ -101,13 +120,6 @@ static int adapter_fs = DEFAULT_SAMPLERATE;
 #define PERIOD_BYTES_MIN  2048
 #define BUFFER_BYTES_MAX (512 * 1024)
 
-/* convert stream to character */
-#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
-
-/*#define TIMER_MILLISECONDS 20
-#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
-*/
-
 #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
 
 struct clk_source {
@@ -136,7 +148,7 @@ struct snd_card_asihpi {
        u32 h_mixer;
        struct clk_cache cc;
 
-       u16 support_mmap;
+       u16 can_dma;
        u16 support_grouping;
        u16 support_mrx;
        u16 update_interval_frames;
@@ -155,6 +167,7 @@ struct snd_card_asihpi_pcm {
        unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
        unsigned int pcm_buf_dma_ofs;   /* DMA R/W offset in buffer */
        unsigned int pcm_buf_elapsed_dma_ofs;   /* DMA R/W offset in buffer */
+       unsigned int drained_count;
        struct snd_pcm_substream *substream;
        u32 h_stream;
        struct hpi_format format;
@@ -288,19 +301,26 @@ static u16 handle_error(u16 err, int line, char *filename)
 #define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
 
 /***************************** GENERAL PCM ****************/
-static void print_hwparams(struct snd_pcm_hw_params *p)
+
+static void print_hwparams(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *p)
 {
-       snd_printd("HWPARAMS \n");
-       snd_printd("samplerate %d \n", params_rate(p));
-       snd_printd("Channels %d \n", params_channels(p));
-       snd_printd("Format %d \n", params_format(p));
-       snd_printd("subformat %d \n", params_subformat(p));
-       snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
-       snd_printd("Period bytes %d \n", params_period_bytes(p));
-       snd_printd("access %d \n", params_access(p));
-       snd_printd("period_size %d \n", params_period_size(p));
-       snd_printd("periods %d \n", params_periods(p));
-       snd_printd("buffer_size %d \n", params_buffer_size(p));
+       DEBUG_NAME(substream, name);
+       snd_printd("%s HWPARAMS\n", name);
+       snd_printd(" samplerate %d Hz\n", params_rate(p));
+       snd_printd(" channels %d\n", params_channels(p));
+       snd_printd(" format %d\n", params_format(p));
+       snd_printd(" subformat %d\n", params_subformat(p));
+       snd_printd(" buffer %d B\n", params_buffer_bytes(p));
+       snd_printd(" period %d B\n", params_period_bytes(p));
+       snd_printd(" access %d\n", params_access(p));
+       snd_printd(" period_size %d\n", params_period_size(p));
+       snd_printd(" periods %d\n", params_periods(p));
+       snd_printd(" buffer_size %d\n", params_buffer_size(p));
+       snd_printd(" %d B/s\n", params_rate(p) *
+               params_channels(p) *
+               snd_pcm_format_width(params_format(p)) / 8);
+
 }
 
 static snd_pcm_format_t hpi_to_alsa_formats[] = {
@@ -451,7 +471,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
        int width;
        unsigned int bytes_per_sec;
 
-       print_hwparams(params);
+       print_hwparams(substream, params);
        err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
        if (err < 0)
                return err;
@@ -459,10 +479,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
        if (err)
                return err;
 
-       snd_printdd("format %d, %d chans, %d_hz\n",
-                               format, params_channels(params),
-                               params_rate(params));
-
        hpi_handle_error(hpi_format_create(&dpcm->format,
                        params_channels(params),
                        format, params_rate(params), 0, 0));
@@ -477,8 +493,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
        }
 
        dpcm->hpi_buffer_attached = 0;
-       if (card->support_mmap) {
-
+       if (card->can_dma) {
                err = hpi_stream_host_buffer_attach(dpcm->h_stream,
                        params_buffer_bytes(params),  runtime->dma_addr);
                if (err == 0) {
@@ -509,8 +524,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
        dpcm->bytes_per_sec = bytes_per_sec;
        dpcm->buffer_bytes = params_buffer_bytes(params);
        dpcm->period_bytes = params_period_bytes(params);
-       snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n",
-                       dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
 
        return 0;
 }
@@ -564,9 +577,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
        struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
        struct snd_pcm_substream *s;
        u16 e;
+       DEBUG_NAME(substream, name);
+
+       snd_printdd("%s trigger\n", name);
 
-       snd_printdd("%c%d trigger\n",
-                       SCHR(substream->stream), substream->number);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                snd_pcm_group_for_each_entry(s, substream) {
@@ -580,8 +594,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
                        if (substream->stream != s->stream)
                                continue;
 
-                       if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
-                               (card->support_mmap)) {
+                       ds->drained_count = 0;
+                       if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                                /* How do I know how much valid data is present
                                * in buffer? Must be at least one period!
                                * Guessing 2 periods, but if
@@ -599,9 +613,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
                        }
 
                        if (card->support_grouping) {
-                               snd_printdd("\t%c%d group\n",
-                                               SCHR(s->stream),
-                                               s->number);
+                               snd_printdd("%d group\n", s->number);
                                e = hpi_stream_group_add(
                                        dpcm->h_stream,
                                        ds->h_stream);
@@ -618,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
                /* start the master stream */
                snd_card_asihpi_pcm_timer_start(substream);
                if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
-                       !card->support_mmap)
+                       !card->can_dma)
                        hpi_handle_error(hpi_stream_start(dpcm->h_stream));
                break;
 
@@ -636,9 +648,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
                        s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
                        if (card->support_grouping) {
-                               snd_printdd("\t%c%d group\n",
-                               SCHR(s->stream),
-                                       s->number);
+                               snd_printdd("%d group\n", s->number);
                                snd_pcm_trigger_done(s, substream);
                        } else
                                break;
@@ -732,9 +742,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
        int loops = 0;
        u16 state;
        u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
+       DEBUG_NAME(substream, name);
 
-       snd_printdd("%c%d snd_card_asihpi_timer_function\n",
-                               SCHR(substream->stream), substream->number);
+       snd_printdd("%s snd_card_asihpi_timer_function\n", name);
 
        /* find minimum newdata and buffer pos in group */
        snd_pcm_group_for_each_entry(s, substream) {
@@ -756,6 +766,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                /* number of bytes in on-card buffer */
                runtime->delay = on_card_bytes;
 
+               if (!card->can_dma)
+                       on_card_bytes = bytes_avail;
+
                if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
                        if (state == HPI_STATE_STOPPED) {
@@ -763,12 +776,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                                    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
                                        hpi_handle_error(hpi_stream_start(ds->h_stream));
                                        snd_printdd("P%d start\n", s->number);
+                                       ds->drained_count = 0;
                                }
                        } else if (state == HPI_STATE_DRAINED) {
                                snd_printd(KERN_WARNING "P%d drained\n",
                                                s->number);
-                               /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
-                               continue; */
+                               ds->drained_count++;
+                               if (ds->drained_count > 2) {
+                                       snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
+                                       continue;
+                               }
+                       } else {
+                               ds->drained_count = 0;
                        }
                } else
                        pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
@@ -786,16 +805,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                                newdata);
                }
 
-               snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n",
+               snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
                        (unsigned long)frames_to_bytes(runtime,
                                                runtime->status->hw_ptr),
                        (unsigned long)frames_to_bytes(runtime,
                                                runtime->control->appl_ptr));
 
-               snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
-                       " aux=x%04X space=x%04X\n",
-                       loops, SCHR(s->stream), s->number,
-                       state,  ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
+               snd_printdd("%d S=%d, "
+                       "rw=0x%04X, dma=0x%04X, left=0x%04X, "
+                       "aux=0x%04X space=0x%04X\n",
+                       s->number, state,
+                       ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
+                       (int)bytes_avail,
                        (int)on_card_bytes, buffer_size-bytes_avail);
                loops++;
        }
@@ -814,7 +835,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
        next_jiffies = max(next_jiffies, 1U);
        dpcm->timer.expires = jiffies + next_jiffies;
-       snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
+       snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
                        next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
 
        snd_pcm_group_for_each_entry(s, substream) {
@@ -826,30 +847,63 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
                ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
 
-               if (xfercount && (on_card_bytes <= ds->period_bytes)) {
-                       if (card->support_mmap) {
-                               if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                                       snd_printddd("P%d write x%04x\n",
+               if (xfercount &&
+                       /* Limit use of on card fifo for playback */
+                       ((on_card_bytes <= ds->period_bytes) ||
+                       (s->stream == SNDRV_PCM_STREAM_CAPTURE)))
+
+               {
+
+                       unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
+                       unsigned int xfer1, xfer2;
+                       char *pd = &s->runtime->dma_area[buf_ofs];
+
+                       if (card->can_dma) { /* buffer wrap is handled at lower level */
+                               xfer1 = xfercount;
+                               xfer2 = 0;
+                       } else {
+                               xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
+                               xfer2 = xfercount - xfer1;
+                       }
+
+                       if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                               snd_printddd("P%d write1 0x%04X 0x%04X\n",
+                                       s->number, xfer1, buf_ofs);
+                               hpi_handle_error(
+                                       hpi_outstream_write_buf(
+                                               ds->h_stream, pd, xfer1,
+                                               &ds->format));
+
+                               if (xfer2) {
+                                       pd = s->runtime->dma_area;
+
+                                       snd_printddd("P%d write2 0x%04X 0x%04X\n",
                                                        s->number,
-                                                       ds->period_bytes);
+                                                       xfercount - xfer1, buf_ofs);
                                        hpi_handle_error(
                                                hpi_outstream_write_buf(
-                                                       ds->h_stream,
-                                                       &s->runtime->
-                                                               dma_area[0],
-                                                       xfercount,
+                                                       ds->h_stream, pd,
+                                                       xfercount - xfer1,
                                                        &ds->format));
-                               } else {
-                                       snd_printddd("C%d read x%04x\n",
-                                               s->number,
-                                               xfercount);
+                               }
+                       } else {
+                               snd_printddd("C%d read1 0x%04x\n",
+                                       s->number, xfer1);
+                               hpi_handle_error(
+                                       hpi_instream_read_buf(
+                                               ds->h_stream,
+                                               pd, xfer1));
+                               if (xfer2) {
+                                       pd = s->runtime->dma_area;
+                                       snd_printddd("C%d read2 0x%04x\n",
+                                               s->number, xfer2);
                                        hpi_handle_error(
                                                hpi_instream_read_buf(
                                                        ds->h_stream,
-                                                       NULL, xfercount));
+                                                       pd, xfer2));
                                }
-                               ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
-                       } /* else R/W will be handled by read/write callbacks */
+                       }
+                       ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
                        ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
                        snd_pcm_period_elapsed(s);
                }
@@ -863,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
                                          unsigned int cmd, void *arg)
 {
-       snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd);
+       snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
        return snd_pcm_lib_ioctl(substream, cmd, arg);
 }
 
@@ -873,7 +927,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
 
-       snd_printdd("playback prepare %d\n", substream->number);
+       snd_printdd("P%d prepare\n", substream->number);
 
        hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
        dpcm->pcm_buf_host_rw_ofs = 0;
@@ -890,7 +944,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
        snd_pcm_uframes_t ptr;
 
        ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
-       snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr);
+       snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
        return ptr;
 }
 
@@ -986,11 +1040,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
                                        SNDRV_PCM_INFO_DOUBLE |
                                        SNDRV_PCM_INFO_BATCH |
                                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                       SNDRV_PCM_INFO_PAUSE;
-
-       if (card->support_mmap)
-               snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
-                                               SNDRV_PCM_INFO_MMAP_VALID;
+                                       SNDRV_PCM_INFO_PAUSE |
+                                       SNDRV_PCM_INFO_MMAP |
+                                       SNDRV_PCM_INFO_MMAP_VALID;
 
        if (card->support_grouping)
                snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
@@ -998,7 +1050,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
        /* struct is copied, so can create initializer dynamically */
        runtime->hw = snd_card_asihpi_playback;
 
-       if (card->support_mmap)
+       if (card->can_dma)
                err = snd_pcm_hw_constraint_pow2(runtime, 0,
                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
        if (err < 0)
@@ -1028,58 +1080,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
-                                       int channel,
-                                       snd_pcm_uframes_t pos,
-                                       void __user *src,
-                                       snd_pcm_uframes_t count)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-       unsigned int len;
-
-       len = frames_to_bytes(runtime, count);
-
-       if (copy_from_user(runtime->dma_area, src, len))
-               return -EFAULT;
-
-       snd_printddd("playback copy%d %u bytes\n",
-                       substream->number, len);
-
-       hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
-                               runtime->dma_area, len, &dpcm->format));
-
-       dpcm->pcm_buf_host_rw_ofs += len;
-
-       return 0;
-}
-
-static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
-                                           substream, int channel,
-                                           snd_pcm_uframes_t pos,
-                                           snd_pcm_uframes_t count)
-{
-       /* Usually writes silence to DMA buffer, which should be overwritten
-       by real audio later.  Our fifos cannot be overwritten, and are not
-       free-running DMAs. Silence is output on fifo underflow.
-       This callback is still required to allow the copy callback to be used.
-       */
-       return 0;
-}
-
-static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
-       .open = snd_card_asihpi_playback_open,
-       .close = snd_card_asihpi_playback_close,
-       .ioctl = snd_card_asihpi_playback_ioctl,
-       .hw_params = snd_card_asihpi_pcm_hw_params,
-       .hw_free = snd_card_asihpi_hw_free,
-       .prepare = snd_card_asihpi_playback_prepare,
-       .trigger = snd_card_asihpi_trigger,
-       .pointer = snd_card_asihpi_playback_pointer,
-       .copy = snd_card_asihpi_playback_copy,
-       .silence = snd_card_asihpi_playback_silence,
-};
-
 static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
        .open = snd_card_asihpi_playback_open,
        .close = snd_card_asihpi_playback_close,
@@ -1211,18 +1211,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
        snd_card_asihpi_capture_format(card, dpcm->h_stream,
                                       &snd_card_asihpi_capture);
        snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
-       snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
-
-       if (card->support_mmap)
-               snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
-                                               SNDRV_PCM_INFO_MMAP_VALID;
+       snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
+                                       SNDRV_PCM_INFO_MMAP |
+                                       SNDRV_PCM_INFO_MMAP_VALID;
 
        if (card->support_grouping)
                snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
 
        runtime->hw = snd_card_asihpi_capture;
 
-       if (card->support_mmap)
+       if (card->can_dma)
                err = snd_pcm_hw_constraint_pow2(runtime, 0,
                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
        if (err < 0)
@@ -1246,28 +1244,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
-                               int channel, snd_pcm_uframes_t pos,
-                               void __user *dst, snd_pcm_uframes_t count)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-       u32 len;
-
-       len = frames_to_bytes(runtime, count);
-
-       snd_printddd("capture copy%d %d bytes\n", substream->number, len);
-       hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
-                               runtime->dma_area, len));
-
-       dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
-
-       if (copy_to_user(dst, runtime->dma_area, len))
-               return -EFAULT;
-
-       return 0;
-}
-
 static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
        .open = snd_card_asihpi_capture_open,
        .close = snd_card_asihpi_capture_close,
@@ -1279,18 +1255,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
        .pointer = snd_card_asihpi_capture_pointer,
 };
 
-static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
-       .open = snd_card_asihpi_capture_open,
-       .close = snd_card_asihpi_capture_close,
-       .ioctl = snd_card_asihpi_capture_ioctl,
-       .hw_params = snd_card_asihpi_pcm_hw_params,
-       .hw_free = snd_card_asihpi_hw_free,
-       .prepare = snd_card_asihpi_capture_prepare,
-       .trigger = snd_card_asihpi_trigger,
-       .pointer = snd_card_asihpi_capture_pointer,
-       .copy = snd_card_asihpi_capture_copy
-};
-
 static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
                                      int device, int substreams)
 {
@@ -1303,17 +1267,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
        if (err < 0)
                return err;
        /* pointer to ops struct is stored, dont change ops afterwards! */
-       if (asihpi->support_mmap) {
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                &snd_card_asihpi_playback_mmap_ops);
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &snd_card_asihpi_capture_mmap_ops);
-       } else {
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                               &snd_card_asihpi_playback_ops);
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-                               &snd_card_asihpi_capture_ops);
-       }
 
        pcm->private_data = asihpi;
        pcm->info_flags = 0;
@@ -1413,14 +1370,16 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
                                struct hpi_control *hpi_ctl,
                                char *name)
 {
-       char *dir = "";
+       char *dir;
        memset(snd_control, 0, sizeof(*snd_control));
        snd_control->name = hpi_ctl->name;
        snd_control->private_value = hpi_ctl->h_control;
        snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        snd_control->index = 0;
 
-       if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
+       if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
+               dir = ""; /* clock is neither capture nor playback */
+       else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
                dir = "Capture ";  /* On or towards a PCM capture destination*/
        else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
                (!hpi_ctl->dst_node_type))
@@ -1433,7 +1392,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
                dir = "Playback "; /* PCM Playback source, or  output node */
 
        if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
-               sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
+               sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
                        asihpi_src_names[hpi_ctl->src_node_type],
                        hpi_ctl->src_node_index,
                        asihpi_dst_names[hpi_ctl->dst_node_type],
@@ -2875,14 +2834,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
        if (err)
                asihpi->update_interval_frames = 512;
 
-       if (!asihpi->support_mmap)
+       if (!asihpi->can_dma)
                asihpi->update_interval_frames *= 2;
 
        hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
                             0, &h_stream));
 
        err = hpi_instream_host_buffer_free(h_stream);
-       asihpi->support_mmap = (!err);
+       asihpi->can_dma = (!err);
 
        hpi_handle_error(hpi_instream_close(h_stream));
 
@@ -2894,8 +2853,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
                asihpi->out_max_chans = 2;
        }
 
-       snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
-                       asihpi->support_mmap,
+       snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
+                       asihpi->can_dma,
                        asihpi->support_grouping,
                        asihpi->support_mrx
              );
@@ -2925,10 +2884,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
            by enable_hwdep  module param*/
        snd_asihpi_hpi_new(asihpi, 0, NULL);
 
-       if (asihpi->support_mmap)
-               strcpy(card->driver, "ASIHPI-MMAP");
-       else
-               strcpy(card->driver, "ASIHPI");
+       strcpy(card->driver, "ASIHPI");
 
        sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
        sprintf(card->longname, "%s %i",
index 8c8aac4c567ee45938049900d008d28935a55640..df4aed5295dddd33526c12051691456c8800a900 100644 (file)
@@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
 static void subsys_create_adapter(struct hpi_message *phm,
        struct hpi_response *phr);
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-       struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+       struct hpi_message *phm, struct hpi_response *phr);
 
 static void adapter_get_asserts(struct hpi_adapter_obj *pao,
        struct hpi_message *phm, struct hpi_response *phr);
@@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
        case HPI_SUBSYS_CREATE_ADAPTER:
                subsys_create_adapter(phm, phr);
                break;
-       case HPI_SUBSYS_DELETE_ADAPTER:
-               subsys_delete_adapter(phm, phr);
-               break;
        default:
                phr->error = HPI_ERROR_INVALID_FUNC;
                break;
@@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
                adapter_get_asserts(pao, phm, phr);
                break;
 
+       case HPI_ADAPTER_DELETE:
+               adapter_delete(pao, phm, phr);
+               break;
+
        default:
                hw_message(pao, phm, phr);
                break;
@@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
 {
        struct hpi_adapter_obj *pao = NULL;
 
-       /* subsytem messages get executed by every HPI. */
-       /* All other messages are ignored unless the adapter index matches */
-       /* an adapter in the HPI */
-       /*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
-
-       /* if Dsp has crashed then do not communicate with it any more */
        if (phm->object != HPI_OBJ_SUBSYSTEM) {
                pao = hpi_find_adapter(phm->adapter_index);
                if (!pao) {
-                       HPI_DEBUG_LOG(DEBUG,
-                               " %d,%d refused, for another HPI?\n",
-                               phm->object, phm->function);
+                       hpi_init_response(phr, phm->object, phm->function,
+                               HPI_ERROR_BAD_ADAPTER_NUMBER);
+                       HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",
+                               phm->adapter_index);
                        return;
                }
 
+               /* Don't even try to communicate with crashed DSP */
                if (pao->dsp_crashed >= 10) {
                        hpi_init_response(phr, phm->object, phm->function,
                                HPI_ERROR_DSP_HARDWARE);
-                       HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n",
-                               phm->object, phm->function);
+                       HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",
+                               phm->adapter_index);
                        return;
                }
        }
@@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm,
        phr->error = 0;
 }
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-       struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+       struct hpi_message *phm, struct hpi_response *phr)
 {
-       struct hpi_adapter_obj *pao = NULL;
-
-       pao = hpi_find_adapter(phm->obj_index);
-       if (!pao)
-               return;
-
        delete_adapter_obj(pao);
        hpi_delete_adapter(pao);
        phr->error = 0;
index 22e9f08dea6de8e94b774d4d3276b99f0ed7644f..9d5df54a6b46f4e67c99dd8d2cbdc47ba479f0e0 100644 (file)
@@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
 
 static void subsys_create_adapter(struct hpi_message *phm,
        struct hpi_response *phr);
-static void subsys_delete_adapter(struct hpi_message *phm,
-       struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+       struct hpi_message *phm, struct hpi_response *phr);
 
 static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
        u32 *pos_error_code);
@@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
 
 /*****************************************************************************/
 
-static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+static void subsys_message(struct hpi_adapter_obj *pao,
+       struct hpi_message *phm, struct hpi_response *phr)
 {
        switch (phm->function) {
        case HPI_SUBSYS_CREATE_ADAPTER:
                subsys_create_adapter(phm, phr);
                break;
-       case HPI_SUBSYS_DELETE_ADAPTER:
-               subsys_delete_adapter(phm, phr);
-               break;
        default:
                phr->error = HPI_ERROR_INVALID_FUNC;
                break;
@@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
        struct hpi_message *phm, struct hpi_response *phr)
 {
        switch (phm->function) {
+       case HPI_ADAPTER_DELETE:
+               adapter_delete(pao, phm, phr);
+               break;
+
        default:
                hw_message(pao, phm, phr);
                break;
@@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao,
 /** Entry point to this HPI backend
  * All calls to the HPI start here
  */
-void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+       struct hpi_response *phr)
 {
-       struct hpi_adapter_obj *pao = NULL;
-
-       /* subsytem messages are processed by every HPI.
-        * All other messages are ignored unless the adapter index matches
-        * an adapter in the HPI
-        */
-       /* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
-          phm->wFunction); */
-
-       /* if Dsp has crashed then do not communicate with it any more */
-       if (phm->object != HPI_OBJ_SUBSYSTEM) {
-               pao = hpi_find_adapter(phm->adapter_index);
-               if (!pao) {
-                       HPI_DEBUG_LOG(DEBUG,
-                               " %d,%d refused, for another HPI?\n",
-                               phm->object, phm->function);
-                       return;
-               }
-
-               if ((pao->dsp_crashed >= 10)
-                       && (phm->function != HPI_ADAPTER_DEBUG_READ)) {
-                       /* allow last resort debug read even after crash */
-                       hpi_init_response(phr, phm->object, phm->function,
-                               HPI_ERROR_DSP_HARDWARE);
-                       HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
-                               phm->object, phm->function);
-                       return;
-               }
+       if (pao && (pao->dsp_crashed >= 10)
+               && (phm->function != HPI_ADAPTER_DEBUG_READ)) {
+               /* allow last resort debug read even after crash */
+               hpi_init_response(phr, phm->object, phm->function,
+                       HPI_ERROR_DSP_HARDWARE);
+               HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
+                       phm->function);
+               return;
        }
 
        /* Init default response  */
@@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
        case HPI_TYPE_MESSAGE:
                switch (phm->object) {
                case HPI_OBJ_SUBSYSTEM:
-                       subsys_message(phm, phr);
+                       subsys_message(pao, phm, phr);
                        break;
 
                case HPI_OBJ_ADAPTER:
@@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
        }
 }
 
+void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+{
+       struct hpi_adapter_obj *pao = NULL;
+
+       if (phm->object != HPI_OBJ_SUBSYSTEM) {
+               /* normal messages must have valid adapter index */
+               pao = hpi_find_adapter(phm->adapter_index);
+       } else {
+               /* subsys messages don't address an adapter */
+               _HPI_6205(NULL, phm, phr);
+               return;
+       }
+
+       if (pao)
+               _HPI_6205(pao, phm, phr);
+       else
+               hpi_init_response(phr, phm->object, phm->function,
+                       HPI_ERROR_BAD_ADAPTER_NUMBER);
+}
+
 /*****************************************************************************/
 /* SUBSYSTEM */
 
@@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm,
 }
 
 /** delete an adapter - required by WDM driver */
-static void subsys_delete_adapter(struct hpi_message *phm,
-       struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+       struct hpi_message *phm, struct hpi_response *phr)
 {
-       struct hpi_adapter_obj *pao;
        struct hpi_hw_obj *phw;
 
-       pao = hpi_find_adapter(phm->obj_index);
        if (!pao) {
                phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
                return;
@@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
        }
 
        err = adapter_boot_load_dsp(pao, pos_error_code);
-       if (err)
+       if (err) {
+               HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
                /* no need to clean up as SubSysCreateAdapter */
                /* calls DeleteAdapter on error. */
                return err;
-
+       }
        HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
 
        /* allow boot load even if mem alloc wont work */
@@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                                control_cache.number_of_controls,
                                interface->control_cache.size_in_bytes,
                                p_control_cache_virtual);
+
                        if (!phw->p_cache)
                                err = HPI_ERROR_MEMORY_ALLOC;
                }
@@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 }
 
 /** Free memory areas allocated by adapter
- * this routine is called from SubSysDeleteAdapter,
+ * this routine is called from AdapterDelete,
   * and SubSysCreateAdapter if duplicate index
 */
 static void delete_adapter_obj(struct hpi_adapter_obj *pao)
 {
-       struct hpi_hw_obj *phw;
+       struct hpi_hw_obj *phw = pao->priv;
        int i;
 
-       phw = pao->priv;
-
        if (hpios_locked_mem_valid(&phw->h_control_cache)) {
                hpios_locked_mem_free(&phw->h_control_cache);
                hpi_free_control_cache(phw->p_cache);
@@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        case HPI_ADAPTER_FAMILY_ASI(0x6300):
                boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
                break;
+       case HPI_ADAPTER_FAMILY_ASI(0x5500):
        case HPI_ADAPTER_FAMILY_ASI(0x5600):
        case HPI_ADAPTER_FAMILY_ASI(0x6500):
                boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
@@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
 static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
 {
        struct bus_master_interface *interface = phw->p_interface_buffer;
-
        u32 r;
 
        interface->host_cmd = cmd;
index 3b9fd115da36fc2cf121d47274baf1425b82d5a9..bf5eced76bacefb4b5d077a75134fc76ded8c65e 100644 (file)
@@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 
 /* These defines are used to fill in protocol information for an Ethernet packet
     sent using HMI on CS18102 */
-/** ID supplied by Cirrius for ASI packets. */
+/** ID supplied by Cirrus for ASI packets. */
 #define HPI_ETHERNET_PACKET_ID                  0x85
 /** Simple packet - no special routing required */
 #define HPI_ETHERNET_PACKET_V1                  0x01
@@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 /** This packet must make its way to the host across the HPI interface */
 #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1   0x41
 
-#define HPI_ETHERNET_UDP_PORT (44600)  /*!< UDP messaging port */
+#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */
 
 /** Default network timeout in milli-seconds. */
 #define HPI_ETHERNET_TIMEOUT_MS 500
@@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS {
        HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
        HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
        HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
-       HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4),
+       /* HPI_SUBSYS_FIND_ADAPTERS     = HPI_FUNC_ID(SUBSYSTEM, 4), */
        HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
        HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
-       HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7),
+       /* HPI_SUBSYS_DELETE_ADAPTER    = HPI_FUNC_ID(SUBSYSTEM, 7), */
        HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
        HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
-       HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10),
-       HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11),
+       /* HPI_SUBSYS_READ_PORT_8               = HPI_FUNC_ID(SUBSYSTEM, 10), */
+       /* HPI_SUBSYS_WRITE_PORT_8              = HPI_FUNC_ID(SUBSYSTEM, 11), */
        HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
        HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
        HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
@@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS {
        HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
        HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
        HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
-#define HPI_ADAPTER_FUNCTION_COUNT 20
+       HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21),
+#define HPI_ADAPTER_FUNCTION_COUNT 21
 
        HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
        HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
@@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
 u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
        u16 *pw_adapter_index);
 
-u16 hpi_subsys_delete_adapter(u16 adapter_index);
-
 u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
        struct hpi_hostbuffer_status **pp_status);
 
@@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR);
 
 /*////////////////////////////////////////////////////////////////////////// */
 /* declarations for individual HPI entry points */
-hpi_handler_func HPI_1000;
 hpi_handler_func HPI_6000;
 hpi_handler_func HPI_6205;
-hpi_handler_func HPI_COMMON;
 
 #endif                         /* _HPI_INTERNAL_H_ */
index 3e9c5c289764d7bc1923169853950028f95e129d..b15a02e91f824aac1d68b50851bd8a0091ebd6c8 100644 (file)
@@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
                        if (info->control_type) {
                                pC->p_info[info->control_index] = info;
                                cached++;
-                       } else  /* dummy cache entry */
+                       } else {        /* dummy cache entry */
                                pC->p_info[info->control_index] = NULL;
+                       }
 
                        byte_count += info->size_in32bit_words * 4;
 
@@ -298,7 +299,7 @@ struct pad_ofs_size {
        unsigned int field_size;
 };
 
-static struct pad_ofs_size pad_desc[] = {
+static const struct pad_ofs_size pad_desc[] = {
        HPICMN_PAD_OFS_AND_SIZE(c_channel),     /* HPI_PAD_CHANNEL_NAME */
        HPICMN_PAD_OFS_AND_SIZE(c_artist),      /* HPI_PAD_ARTIST */
        HPICMN_PAD_OFS_AND_SIZE(c_title),       /* HPI_PAD_TITLE */
@@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
        }
 }
 
+/** Allocate control cache.
+
+\return Cache pointer, or NULL if allocation fails.
+*/
 struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
        const u32 size_in_bytes, u8 *p_dsp_control_buffer)
 {
@@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
                phr->u.s.num_adapters = adapters.gw_num_adapters;
                break;
        case HPI_SUBSYS_CREATE_ADAPTER:
-       case HPI_SUBSYS_DELETE_ADAPTER:
                break;
        default:
                phr->error = HPI_ERROR_INVALID_FUNC;
index 590f0b69e655ae57e0b63f442f6dbb1809af941c..d53cdf6e535f51d877bee38925d26a6c7e9c99e1 100644 (file)
@@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
        struct hpi_message *phm, struct hpi_response *phr);
 
 u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
+
+hpi_handler_func HPI_COMMON;
index c38fc9487560cea2a235e0ba829c43b197e7f9e9..7397b169b89f2b626f8dca427006dc96d260a2ce 100644 (file)
@@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex)
        return hr.error;
 }
 
-u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
-       u16 *pw_adapter_index)
-{
-       struct hpi_message hm;
-       struct hpi_response hr;
-
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-               HPI_SUBSYS_CREATE_ADAPTER);
-       hm.u.s.resource = *p_resource;
-
-       hpi_send_recv(&hm, &hr);
-
-       *pw_adapter_index = hr.u.s.adapter_index;
-       return hr.error;
-}
-
-u16 hpi_subsys_delete_adapter(u16 adapter_index)
-{
-       struct hpi_message hm;
-       struct hpi_response hr;
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-               HPI_SUBSYS_DELETE_ADAPTER);
-       hm.obj_index = adapter_index;
-       hpi_send_recv(&hm, &hr);
-       return hr.error;
-}
-
 u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
 {
        struct hpi_message hm;
index 360028b9abf59ea3564735a6ba29992e80a426a9..7352a5f7b4f7ca50fa048d63cf730e1a804a8206 100644 (file)
@@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
                HPIMSGX__init(phm, phr);
                break;
 
-       case HPI_SUBSYS_DELETE_ADAPTER:
-               HPIMSGX__cleanup(phm->obj_index, h_owner);
-               {
-                       struct hpi_message hm;
-                       struct hpi_response hr;
-                       hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
-                               HPI_ADAPTER_CLOSE);
-                       hm.adapter_index = phm->obj_index;
-                       hw_entry_point(&hm, &hr);
-               }
-               if ((phm->obj_index < HPI_MAX_ADAPTERS)
-                       && hpi_entry_points[phm->obj_index]) {
-                       hpi_entry_points[phm->obj_index] (phm, phr);
-                       hpi_entry_points[phm->obj_index] = NULL;
-               } else
-                       phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
-
-               break;
        default:
                /* Must explicitly handle every subsys message in this switch */
                hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
@@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
        case HPI_ADAPTER_CLOSE:
                adapter_close(phm, phr);
                break;
+       case HPI_ADAPTER_DELETE:
+               HPIMSGX__cleanup(phm->adapter_index, h_owner);
+               {
+                       struct hpi_message hm;
+                       struct hpi_response hr;
+                       hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+                               HPI_ADAPTER_CLOSE);
+                       hm.adapter_index = phm->adapter_index;
+                       hw_entry_point(&hm, &hr);
+               }
+               hw_entry_point(phm, phr);
+               break;
+
        default:
                hw_entry_point(phm, phr);
                break;
index cd624f13ff8e4755ca7d094bf0b9c6e2d212cc27..d8e7047512f8748cfaa90df9597ff64b4859babe 100644 (file)
@@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
 #include "hpidebug.h"
 #include "hpimsgx.h"
 #include "hpioctl.h"
+#include "hpicmn.h"
 
 #include <linux/fs.h>
 #include <linux/slab.h>
@@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                goto out;
        }
 
-       pa = &adapters[hm->h.adapter_index];
+       switch (hm->h.function) {
+       case HPI_SUBSYS_CREATE_ADAPTER:
+       case HPI_ADAPTER_DELETE:
+               /* Application must not use these functions! */
+               hr->h.size = sizeof(hr->h);
+               hr->h.error = HPI_ERROR_INVALID_OPERATION;
+               hr->h.function = hm->h.function;
+               uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
+               if (uncopied_bytes)
+                       err = -EFAULT;
+               else
+                       err = 0;
+               goto out;
+       }
+
        hr->h.size = res_max_size;
        if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
-               switch (hm->h.function) {
-               case HPI_SUBSYS_CREATE_ADAPTER:
-               case HPI_SUBSYS_DELETE_ADAPTER:
-                       /* Application must not use these functions! */
-                       hr->h.size = sizeof(hr->h);
-                       hr->h.error = HPI_ERROR_INVALID_OPERATION;
-                       hr->h.function = hm->h.function;
-                       uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
-                       if (uncopied_bytes)
-                               err = -EFAULT;
-                       else
-                               err = 0;
-                       goto out;
-
-               default:
-                       hpi_send_recv_f(&hm->m0, &hr->r0, file);
-               }
+               hpi_send_recv_f(&hm->m0, &hr->r0, file);
        } else {
                u16 __user *ptr = NULL;
                u32 size = 0;
@@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                /* -1=no data 0=read from user mem, 1=write to user mem */
                int wrflag = -1;
                u32 adapter = hm->h.adapter_index;
+               pa = &adapters[adapter];
 
-               if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
+               if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
                        hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
                                HPI_ADAPTER_OPEN,
                                HPI_ERROR_BAD_ADAPTER_NUMBER);
@@ -317,7 +317,7 @@ out:
 int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
        const struct pci_device_id *pci_id)
 {
-       int err, idx, nm;
+       int idx, nm;
        unsigned int memlen;
        struct hpi_message hm;
        struct hpi_response hr;
@@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
        nm = HPI_MAX_ADAPTER_MEM_SPACES;
 
        for (idx = 0; idx < nm; idx++) {
-               HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
-                       idx, pci_dev->resource[idx].name,
-                       (unsigned long long)pci_resource_start(pci_dev, idx),
-                       (unsigned long long)pci_resource_end(pci_dev, idx),
-                       (unsigned long long)pci_resource_flags(pci_dev, idx));
+               HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
+                       &pci_dev->resource[idx]);
 
                if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
                        memlen = pci_resource_len(pci_dev, idx);
@@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 
        adapter.index = hr.u.s.adapter_index;
        adapter.type = hr.u.s.adapter_type;
+
+       hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+               HPI_ADAPTER_OPEN);
        hm.adapter_index = adapter.index;
+       hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
-       err = hpi_adapter_open(adapter.index);
-       if (err)
+       if (hr.error)
                goto err;
 
        adapter.snd_card_asihpi = NULL;
        /* WARNING can't init mutex in 'adapter'
         * and then copy it to adapters[] ?!?!
         */
-       adapters[hr.u.s.adapter_index] = adapter;
+       adapters[adapter.index] = adapter;
        mutex_init(&adapters[adapter.index].mutex);
        pci_set_drvdata(pci_dev, &adapters[adapter.index]);
 
@@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
        struct hpi_adapter *pa;
        pa = pci_get_drvdata(pci_dev);
 
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-               HPI_SUBSYS_DELETE_ADAPTER);
-       hm.obj_index = pa->index;
-       hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
+       hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+               HPI_ADAPTER_DELETE);
+       hm.adapter_index = pa->index;
        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
        /* unmap PCI memory space, mapped during device init. */
index 5d69c31fe3f474ace0ef2da5c6ab4a117c24036f..79fbee3845ebb4f1b8a471620308c821ac44e9c1 100644 (file)
@@ -4,7 +4,7 @@
 
 #define CHIP_AU8810
 
-#define CARD_NAME "Aureal Advantage 3D Sound Processor"
+#define CARD_NAME "Aureal Advantage"
 #define CARD_NAME_SHORT "au8810"
 
 #define NR_ADB         0x10
index abbe85e4f7a9abb3427b502d2f3c5462ce5b88aa..cafdb9668a341de9c7ec75816b7edd65e06e584d 100644 (file)
@@ -11,7 +11,7 @@
 
 #define CHIP_AU8820
 
-#define CARD_NAME "Aureal Vortex 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex"
 #define CARD_NAME_SHORT "au8820"
 
 /* Number of ADB and WT channels */
index 04ece1b1c2183646bfc008855cc07e3053bc8ecc..999b29ab34ad4d7ad38db5e7e720b0dd201d5a7b 100644 (file)
@@ -11,7 +11,7 @@
 
 #define CHIP_AU8830
 
-#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex 2"
 #define CARD_NAME_SHORT "au8830"
 
 #define NR_ADB 0x20
index 62e959120c44cc82542ccca98f0df7791e99b022..c5f7ae46afefca324b1e31b8100fb0cd80afdf2b 100644 (file)
@@ -426,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = {
 */
 
 static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
-       "AU88x0 ADB",
-       "AU88x0 SPDIF",
-       "AU88x0 A3D",
-       "AU88x0 WT",
-       "AU88x0 I2S",
+       CARD_NAME " ADB",
+       CARD_NAME " SPDIF",
+       CARD_NAME " A3D",
+       CARD_NAME " WT",
+       CARD_NAME " I2S",
 };
 static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
        "adb",
@@ -527,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
                          nr_capt, &pcm);
        if (err < 0)
                return err;
-       strcpy(pcm->name, vortex_pcm_name[idx]);
+       snprintf(pcm->name, sizeof(pcm->name),
+               "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
        chip->pcm[idx] = pcm;
        // This is an evil hack, but it saves a lot of duplicated code.
        VORTEX_PCM_TYPE(pcm) = idx;
index 7a9401462c1c698a0a8f21e2135a613d1efb5a0b..dae4050ede5cc96f4dd3b070da01b4bbebfff591 100644 (file)
@@ -303,6 +303,9 @@ static const u32 db_table[101] = {
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
 static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 
+/* EMU10K1 bass/treble db gain */
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
+
 static const u32 onoff_table[2] = {
        0x00000000, 0x00000001
 };
@@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
        ctl->min = 0;
        ctl->max = 40;
        ctl->value[0] = ctl->value[1] = 20;
+       ctl->tlv = snd_emu10k1_bass_treble_db_scale;
        ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
        ctl = &controls[i + 1];
        ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
        ctl->min = 0;
        ctl->max = 40;
        ctl->value[0] = ctl->value[1] = 20;
+       ctl->tlv = snd_emu10k1_bass_treble_db_scale;
        ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
 
 #define BASS_GPR       0x8c
index 05afe06e353ae0b37c8ba36bea67345d430b7b5b..9d890a5aec5afd5ad9aded994fe247b71644684e 100644 (file)
@@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                "Master Mono Playback Volume",
                "PCM Out Path & Mute",
                "Mono Output Select",
-               "Front Playback Switch",
-               "Front Playback Volume",
                "Surround Playback Switch",
                "Surround Playback Volume",
                "Center Playback Switch",
@@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                                emu->rear_ac97 = 1;
                                snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
                                snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
+                               remove_ctl(card,"Front Playback Volume");
+                               remove_ctl(card,"Front Playback Switch");
                        }
                        /* remove unused AC97 controls */
                        snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
        for (; *c; c += 2)
                rename_ctl(card, c[0], c[1]);
 
+       if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
+               remove_ctl(card, "Center Playback Volume");
+               remove_ctl(card, "LFE Playback Volume");
+               remove_ctl(card, "Wave Center Playback Volume");
+               remove_ctl(card, "Wave LFE Playback Volume");
+       }
        if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
                rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
                rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
index 7c17f45d876dfdd4a7ba9283bdbf440b08374eb8..ab0a6156a704b4c01dc339c06f09f4637367943c 100644 (file)
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#include <sound/tea575x-tuner.h>
+#endif
+
 #define CARD_NAME "ESS Maestro1/2"
 #define DRIVER_NAME "ES1968"
 
@@ -553,6 +557,10 @@ struct es1968 {
        spinlock_t ac97_lock;
        struct tasklet_struct hwvol_tq;
 #endif
+
+#ifdef CONFIG_SND_ES1968_RADIO
+       struct snd_tea575x tea;
+#endif
 };
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
@@ -2571,6 +2579,63 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip)
 }
 #endif /* CONFIG_SND_ES1968_INPUT */
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#define GPIO_DATA      0x60
+#define IO_MASK                4      /* mask      register offset from GPIO_DATA
+                               bits 1=unmask write to given bit */
+#define IO_DIR         8      /* direction register offset from GPIO_DATA
+                               bits 0/1=read/write direction */
+/* mask bits for GPIO lines */
+#define STR_DATA       0x0040 /* GPIO6 */
+#define STR_CLK                0x0080 /* GPIO7 */
+#define STR_WREN       0x0100 /* GPIO8 */
+#define STR_MOST       0x0200 /* GPIO9 */
+
+static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+{
+       struct es1968 *chip = tea->private_data;
+       unsigned long io = chip->io_port + GPIO_DATA;
+       u16 val = 0;
+
+       val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
+       val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
+       val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+
+       outw(val, io);
+}
+
+static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
+{
+       struct es1968 *chip = tea->private_data;
+       unsigned long io = chip->io_port + GPIO_DATA;
+       u16 val = inw(io);
+
+       return  (val & STR_DATA) ? TEA575X_DATA : 0 |
+               (val & STR_MOST) ? TEA575X_MOST : 0;
+}
+
+static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output)
+{
+       struct es1968 *chip = tea->private_data;
+       unsigned long io = chip->io_port + GPIO_DATA;
+       u16 odir = inw(io + IO_DIR);
+
+       if (output) {
+               outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+               outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+       } else {
+               outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
+               outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+       }
+}
+
+static struct snd_tea575x_ops snd_es1968_tea_ops = {
+       .set_pins = snd_es1968_tea575x_set_pins,
+       .get_pins = snd_es1968_tea575x_get_pins,
+       .set_direction = snd_es1968_tea575x_set_direction,
+};
+#endif
+
 static int snd_es1968_free(struct es1968 *chip)
 {
 #ifdef CONFIG_SND_ES1968_INPUT
@@ -2585,6 +2650,10 @@ static int snd_es1968_free(struct es1968 *chip)
                outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
        }
 
+#ifdef CONFIG_SND_ES1968_RADIO
+       snd_tea575x_exit(&chip->tea);
+#endif
+
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
        snd_es1968_free_gameport(chip);
@@ -2723,6 +2792,15 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 
        snd_card_set_dev(card, &pci->dev);
 
+#ifdef CONFIG_SND_ES1968_RADIO
+       chip->tea.private_data = chip;
+       chip->tea.ops = &snd_es1968_tea_ops;
+       strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
+       sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
+       if (!snd_tea575x_init(&chip->tea))
+               printk(KERN_INFO "es1968: detected TEA575x radio\n");
+#endif
+
        *chip_ret = chip;
 
        return 0;
index e1baad74ea4b4f8a2ae80894c330c0a46026694d..eacd4901a308d8b0b3c6a269ccd8c38bbf4f4f67 100644 (file)
@@ -38,7 +38,6 @@
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #include <sound/tea575x-tuner.h>
-#define TEA575X_RADIO 1
 #endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -53,7 +52,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card *
 /*
  *  Enable TEA575x tuner
  *    1 = MediaForte 256-PCS
- *    2 = MediaForte 256-PCPR
+ *    2 = MediaForte 256-PCP
  *    3 = MediaForte 64-PCR
  *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
 
 #define TUNER_ONLY             (1<<4)
 #define TUNER_TYPE_MASK                (~TUNER_ONLY & 0xFFFF)
@@ -196,7 +195,7 @@ struct fm801 {
        spinlock_t reg_lock;
        struct snd_info_entry *proc_entry;
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
        struct snd_tea575x tea;
 #endif
 
@@ -715,310 +714,89 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
  *  TEA5757 radio
  */
 
-#ifdef TEA575X_RADIO
-
-/* 256PCS GPIO numbers */
-#define TEA_256PCS_DATA                        1
-#define TEA_256PCS_WRITE_ENABLE                2       /* inverted */
-#define TEA_256PCS_BUS_CLOCK           3
-
-static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val)
-{
-       struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       int i = 25;
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       /* use GPIO lines and set write enable bit */
-       reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-              FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK);
-       /* all of lines are in the write direction */
-       /* clear data and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) |
-                FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCS_DATA) |
-                FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE));
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
-       udelay(1);
-
-       while (i--) {
-               if (val & (1 << i))
-                       reg |= FM801_GPIO_GP(TEA_256PCS_DATA);
-               else
-                       reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-       }
+/* GPIO to TEA575x maps */
+struct snd_fm801_tea575x_gpio {
+       u8 data, clk, wren, most;
+       char *name;
+};
 
-       /* and reset the write enable bit */
-       reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) |
-              FM801_GPIO_GP(TEA_256PCS_DATA);
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
-       spin_unlock_irq(&chip->reg_lock);
-}
+static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
+       { .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" },
+       { .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" },
+       { .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
+};
 
-static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea)
+static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       unsigned int val = 0;
-       int i;
-       
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       /* use GPIO lines, set data direction to input */
-       reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-              FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) |
-              FM801_GPIO_GD(TEA_256PCS_DATA) |
-              FM801_GPIO_GP(TEA_256PCS_DATA) |
-              FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE);
-       /* all of lines are in the write direction, except data */
-       /* clear data, write enable and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK));
-
-       for (i = 0; i < 24; i++) {
-               reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               val <<= 1;
-               if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA))
-                       val |= 1;
-       }
+       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-       spin_unlock_irq(&chip->reg_lock);
+       reg &= ~(FM801_GPIO_GP(gpio.data) |
+                FM801_GPIO_GP(gpio.clk) |
+                FM801_GPIO_GP(gpio.wren));
 
-       return val;
-}
+       reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0;
+       reg |= (pins & TEA575X_CLK)  ? FM801_GPIO_GP(gpio.clk) : 0;
+       /* WRITE_ENABLE is inverted */
+       reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
 
-/* 256PCPR GPIO numbers */
-#define TEA_256PCPR_BUS_CLOCK          0
-#define TEA_256PCPR_DATA               1
-#define TEA_256PCPR_WRITE_ENABLE       2       /* inverted */
-
-static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val)
-{
-       struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       int i = 25;
-
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       /* use GPIO lines and set write enable bit */
-       reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-              FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK);
-       /* all of lines are in the write direction */
-       /* clear data and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) |
-                FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCPR_DATA) |
-                FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE));
        outw(reg, FM801_REG(chip, GPIO_CTRL));
-       udelay(1);
-
-       while (i--) {
-               if (val & (1 << i))
-                       reg |= FM801_GPIO_GP(TEA_256PCPR_DATA);
-               else
-                       reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-       }
-
-       /* and reset the write enable bit */
-       reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) |
-              FM801_GPIO_GP(TEA_256PCPR_DATA);
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
-       spin_unlock_irq(&chip->reg_lock);
 }
 
-static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea)
+static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       unsigned int val = 0;
-       int i;
-       
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       /* use GPIO lines, set data direction to input */
-       reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-              FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) |
-              FM801_GPIO_GD(TEA_256PCPR_DATA) |
-              FM801_GPIO_GP(TEA_256PCPR_DATA) |
-              FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE);
-       /* all of lines are in the write direction, except data */
-       /* clear data, write enable and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK));
-
-       for (i = 0; i < 24; i++) {
-               reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               val <<= 1;
-               if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA))
-                       val |= 1;
-       }
+       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-       spin_unlock_irq(&chip->reg_lock);
-
-       return val;
+       return  (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
+               (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
 }
 
-/* 64PCR GPIO numbers */
-#define TEA_64PCR_BUS_CLOCK            0
-#define TEA_64PCR_WRITE_ENABLE         1       /* inverted */
-#define TEA_64PCR_DATA                 2
-
-static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val)
+static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
        struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       int i = 25;
+       unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+       struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
        /* use GPIO lines and set write enable bit */
-       reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-              FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK);
-       /* all of lines are in the write direction */
-       /* clear data and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) |
-                FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_64PCR_DATA) |
-                FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE));
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
-       udelay(1);
-
-       while (i--) {
-               if (val & (1 << i))
-                       reg |= FM801_GPIO_GP(TEA_64PCR_DATA);
-               else
-                       reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
+       reg |= FM801_GPIO_GS(gpio.data) |
+              FM801_GPIO_GS(gpio.wren) |
+              FM801_GPIO_GS(gpio.clk) |
+              FM801_GPIO_GS(gpio.most);
+       if (output) {
+               /* all of lines are in the write direction */
+               /* clear data and clock lines */
+               reg &= ~(FM801_GPIO_GD(gpio.data) |
+                        FM801_GPIO_GD(gpio.wren) |
+                        FM801_GPIO_GD(gpio.clk) |
+                        FM801_GPIO_GP(gpio.data) |
+                        FM801_GPIO_GP(gpio.clk) |
+                        FM801_GPIO_GP(gpio.wren));
+       } else {
+               /* use GPIO lines, set data direction to input */
+               reg |= FM801_GPIO_GD(gpio.data) |
+                      FM801_GPIO_GD(gpio.most) |
+                      FM801_GPIO_GP(gpio.data) |
+                      FM801_GPIO_GP(gpio.most) |
+                      FM801_GPIO_GP(gpio.wren);
+               /* all of lines are in the write direction, except data */
+               /* clear data, write enable and clock lines */
+               reg &= ~(FM801_GPIO_GD(gpio.wren) |
+                        FM801_GPIO_GD(gpio.clk) |
+                        FM801_GPIO_GP(gpio.clk));
        }
 
-       /* and reset the write enable bit */
-       reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) |
-              FM801_GPIO_GP(TEA_64PCR_DATA);
        outw(reg, FM801_REG(chip, GPIO_CTRL));
-       spin_unlock_irq(&chip->reg_lock);
-}
-
-static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea)
-{
-       struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-       unsigned int val = 0;
-       int i;
-       
-       spin_lock_irq(&chip->reg_lock);
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       /* use GPIO lines, set data direction to input */
-       reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-              FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-              FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) |
-              FM801_GPIO_GD(TEA_64PCR_DATA) |
-              FM801_GPIO_GP(TEA_64PCR_DATA) |
-              FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-       /* all of lines are in the write direction, except data */
-       /* clear data, write enable and clock lines */
-       reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-                FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-                FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK));
-
-       for (i = 0; i < 24; i++) {
-               reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-               outw(reg, FM801_REG(chip, GPIO_CTRL));
-               udelay(1);
-               val <<= 1;
-               if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA))
-                       val |= 1;
-       }
-
-       spin_unlock_irq(&chip->reg_lock);
-
-       return val;
 }
 
-static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea,
-                                         unsigned int mute)
-{
-       struct fm801 *chip = tea->private_data;
-       unsigned short reg;
-
-       spin_lock_irq(&chip->reg_lock);
-
-       reg = inw(FM801_REG(chip, GPIO_CTRL));
-       if (mute)
-               /* 0xf800 (mute) */
-               reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-       else
-               /* 0xf802 (unmute) */
-               reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-       outw(reg, FM801_REG(chip, GPIO_CTRL));
-       udelay(1);
-
-       spin_unlock_irq(&chip->reg_lock);
-}
-
-static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
-       {
-               /* 1 = MediaForte 256-PCS */
-               .write = snd_fm801_tea575x_256pcs_write,
-               .read = snd_fm801_tea575x_256pcs_read,
-       },
-       {
-               /* 2 = MediaForte 256-PCPR */
-               .write = snd_fm801_tea575x_256pcpr_write,
-               .read = snd_fm801_tea575x_256pcpr_read,
-       },
-       {
-               /* 3 = MediaForte 64-PCR */
-               .write = snd_fm801_tea575x_64pcr_write,
-               .read = snd_fm801_tea575x_64pcr_read,
-               .mute = snd_fm801_tea575x_64pcr_mute,
-       }
+static struct snd_tea575x_ops snd_fm801_tea_ops = {
+       .set_pins = snd_fm801_tea575x_set_pins,
+       .get_pins = snd_fm801_tea575x_get_pins,
+       .set_direction = snd_fm801_tea575x_set_direction,
 };
 #endif
 
@@ -1371,7 +1149,7 @@ static int snd_fm801_free(struct fm801 *chip)
        outw(cmdw, FM801_REG(chip, IRQ_MASK));
 
       __end_hw:
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
        snd_tea575x_exit(&chip->tea);
 #endif
        if (chip->irq >= 0)
@@ -1450,16 +1228,25 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 
        snd_card_set_dev(card, &pci->dev);
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+       chip->tea.private_data = chip;
+       chip->tea.ops = &snd_fm801_tea_ops;
+       sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
        if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
            (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-               chip->tea.dev_nr = tea575x_tuner >> 16;
-               chip->tea.card = card;
-               chip->tea.freq_fixup = 10700;
-               chip->tea.private_data = chip;
-               chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
-               snd_tea575x_init(&chip->tea);
-       }
+               if (snd_tea575x_init(&chip->tea))
+                       snd_printk(KERN_ERR "TEA575x radio not found\n");
+       } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0)
+               /* autodetect tuner connection */
+               for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
+                       chip->tea575x_tuner = tea575x_tuner;
+                       if (!snd_tea575x_init(&chip->tea)) {
+                               snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
+                                       snd_fm801_tea575x_gpios[tea575x_tuner - 1].name);
+                               break;
+                       }
+               }
+       strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
 #endif
 
        *rchip = chip;
index 27709f0cd2a648a04a7b41d5cc309d738cbc9a36..f3353b49c78539fb5deb60830a3cd915f1639799 100644 (file)
@@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = {
        { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
        { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
        { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL },     /* AMD8111 */
 #if 0
-       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
        { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
        { 0, }
@@ -1261,9 +1261,9 @@ static struct shortname_table {
        { PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" },
        { PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" },
        { PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" },
+       { 0x746e, "AMD AMD8111" },
 #if 0
        { 0x5455, "ALi M5455" },
-       { 0x746d, "AMD AMD8111" },
 #endif
        { 0 },
 };
diff --git a/sound/pci/lola/Makefile b/sound/pci/lola/Makefile
new file mode 100644 (file)
index 0000000..8178a2a
--- /dev/null
@@ -0,0 +1,4 @@
+snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o
+snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o
+
+obj-$(CONFIG_SND_LOLA) += snd-lola.o
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
new file mode 100644 (file)
index 0000000..34b2428
--- /dev/null
@@ -0,0 +1,791 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "lola.h"
+
+/* Standard options */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Digigram Lola driver.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Digigram Lola driver.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Digigram Lola driver.");
+
+/* Lola-specific options */
+
+/* for instance use always max granularity which is compatible
+ * with all sample rates
+ */
+static int granularity[SNDRV_CARDS] = {
+       [0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX
+};
+
+/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */
+static int sample_rate_min[SNDRV_CARDS] = {
+       [0 ... (SNDRV_CARDS - 1) ] = 16000
+};
+
+module_param_array(granularity, int, NULL, 0444);
+MODULE_PARM_DESC(granularity, "Granularity value");
+module_param_array(sample_rate_min, int, NULL, 0444);
+MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate");
+
+/*
+ */
+
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}");
+MODULE_DESCRIPTION("Digigram Lola driver");
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+static int debug;
+module_param(debug, int, 0644);
+#define verbose_debug(fmt, args...)                    \
+       do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0)
+#else
+#define verbose_debug(fmt, args...)
+#endif
+
+/*
+ * pseudo-codec read/write via CORB/RIRB
+ */
+
+static int corb_send_verb(struct lola *chip, unsigned int nid,
+                         unsigned int verb, unsigned int data,
+                         unsigned int extdata)
+{
+       unsigned long flags;
+       int ret = -EIO;
+
+       chip->last_cmd_nid = nid;
+       chip->last_verb = verb;
+       chip->last_data = data;
+       chip->last_extdata = extdata;
+       data |= (nid << 20) | (verb << 8);
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
+               unsigned int wp = chip->corb.wp + 1;
+               wp %= LOLA_CORB_ENTRIES;
+               chip->corb.wp = wp;
+               chip->corb.buf[wp * 2] = cpu_to_le32(data);
+               chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata);
+               lola_writew(chip, BAR0, CORBWP, wp);
+               chip->rirb.cmds++;
+               smp_wmb();
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return ret;
+}
+
+static void lola_queue_unsol_event(struct lola *chip, unsigned int res,
+                                  unsigned int res_ex)
+{
+       lola_update_ext_clock_freq(chip, res);
+}
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void lola_update_rirb(struct lola *chip)
+{
+       unsigned int rp, wp;
+       u32 res, res_ex;
+
+       wp = lola_readw(chip, BAR0, RIRBWP);
+       if (wp == chip->rirb.wp)
+               return;
+       chip->rirb.wp = wp;
+
+       while (chip->rirb.rp != wp) {
+               chip->rirb.rp++;
+               chip->rirb.rp %= LOLA_CORB_ENTRIES;
+
+               rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+               res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+               res = le32_to_cpu(chip->rirb.buf[rp]);
+               if (res_ex & LOLA_RIRB_EX_UNSOL_EV)
+                       lola_queue_unsol_event(chip, res, res_ex);
+               else if (chip->rirb.cmds) {
+                       chip->res = res;
+                       chip->res_ex = res_ex;
+                       smp_wmb();
+                       chip->rirb.cmds--;
+               }
+       }
+}
+
+static int rirb_get_response(struct lola *chip, unsigned int *val,
+                            unsigned int *extval)
+{
+       unsigned long timeout;
+
+ again:
+       timeout = jiffies + msecs_to_jiffies(1000);
+       for (;;) {
+               if (chip->polling_mode) {
+                       spin_lock_irq(&chip->reg_lock);
+                       lola_update_rirb(chip);
+                       spin_unlock_irq(&chip->reg_lock);
+               }
+               if (!chip->rirb.cmds) {
+                       *val = chip->res;
+                       if (extval)
+                               *extval = chip->res_ex;
+                       verbose_debug("get_response: %x, %x\n",
+                                     chip->res, chip->res_ex);
+                       if (chip->res_ex & LOLA_RIRB_EX_ERROR) {
+                               printk(KERN_WARNING SFX "RIRB ERROR: "
+                                      "NID=%x, verb=%x, data=%x, ext=%x\n",
+                                      chip->last_cmd_nid,
+                                      chip->last_verb, chip->last_data,
+                                      chip->last_extdata);
+                               return -EIO;
+                       }
+                       return 0;
+               }
+               if (time_after(jiffies, timeout))
+                       break;
+               udelay(20);
+               cond_resched();
+       }
+       printk(KERN_WARNING SFX "RIRB response error\n");
+       if (!chip->polling_mode) {
+               printk(KERN_WARNING SFX "switching to polling mode\n");
+               chip->polling_mode = 1;
+               goto again;
+       }
+       return -EIO;
+}
+
+/* aynchronous write of a codec verb with data */
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+                    unsigned int data, unsigned int extdata)
+{
+       verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n",
+                     nid, verb, data, extdata);
+       return corb_send_verb(chip, nid, verb, data, extdata);
+}
+
+/* write a codec verb with data and read the returned status */
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+                   unsigned int data, unsigned int extdata,
+                   unsigned int *val, unsigned int *extval)
+{
+       int err;
+
+       verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n",
+                     nid, verb, data, extdata);
+       err = corb_send_verb(chip, nid, verb, data, extdata);
+       if (err < 0)
+               return err;
+       err = rirb_get_response(chip, val, extval);
+       return err;
+}
+
+/* flush all pending codec writes */
+int lola_codec_flush(struct lola *chip)
+{
+       unsigned int tmp;
+       return rirb_get_response(chip, &tmp, NULL);
+}
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t lola_interrupt(int irq, void *dev_id)
+{
+       struct lola *chip = dev_id;
+       unsigned int notify_ins, notify_outs, error_ins, error_outs;
+       int handled = 0;
+       int i;
+
+       notify_ins = notify_outs = error_ins = error_outs = 0;
+       spin_lock(&chip->reg_lock);
+       for (;;) {
+               unsigned int status, in_sts, out_sts;
+               unsigned int reg;
+
+               status = lola_readl(chip, BAR1, DINTSTS);
+               if (!status || status == -1)
+                       break;
+
+               in_sts = lola_readl(chip, BAR1, DIINTSTS);
+               out_sts = lola_readl(chip, BAR1, DOINTSTS);
+
+               /* clear Input Interrupts */
+               for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) {
+                       if (!(in_sts & (1 << i)))
+                               continue;
+                       in_sts &= ~(1 << i);
+                       reg = lola_dsd_read(chip, i, STS);
+                       if (reg & LOLA_DSD_STS_DESE) /* error */
+                               error_ins |= (1 << i);
+                       if (reg & LOLA_DSD_STS_BCIS) /* notify */
+                               notify_ins |= (1 << i);
+                       /* clear */
+                       lola_dsd_write(chip, i, STS, reg);
+               }
+
+               /* clear Output Interrupts */
+               for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) {
+                       if (!(out_sts & (1 << i)))
+                               continue;
+                       out_sts &= ~(1 << i);
+                       reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS);
+                       if (reg & LOLA_DSD_STS_DESE) /* error */
+                               error_outs |= (1 << i);
+                       if (reg & LOLA_DSD_STS_BCIS) /* notify */
+                               notify_outs |= (1 << i);
+                       lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg);
+               }
+
+               if (status & LOLA_DINT_CTRL) {
+                       unsigned char rbsts; /* ring status is byte access */
+                       rbsts = lola_readb(chip, BAR0, RIRBSTS);
+                       rbsts &= LOLA_RIRB_INT_MASK;
+                       if (rbsts)
+                               lola_writeb(chip, BAR0, RIRBSTS, rbsts);
+                       rbsts = lola_readb(chip, BAR0, CORBSTS);
+                       rbsts &= LOLA_CORB_INT_MASK;
+                       if (rbsts)
+                               lola_writeb(chip, BAR0, CORBSTS, rbsts);
+
+                       lola_update_rirb(chip);
+               }
+
+               if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) {
+                       /* clear global fifo error interrupt */
+                       lola_writel(chip, BAR1, DINTSTS,
+                                   (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)));
+               }
+               handled = 1;
+       }
+       spin_unlock(&chip->reg_lock);
+
+       lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins);
+       lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs);
+
+       return IRQ_RETVAL(handled);
+}
+
+
+/*
+ * controller
+ */
+static int reset_controller(struct lola *chip)
+{
+       unsigned int gctl = lola_readl(chip, BAR0, GCTL);
+       unsigned long end_time;
+
+       if (gctl) {
+               /* to be sure */
+               lola_writel(chip, BAR1, BOARD_MODE, 0);
+               return 0;
+       }
+
+       chip->cold_reset = 1;
+       lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET);
+       end_time = jiffies + msecs_to_jiffies(200);
+       do {
+               msleep(1);
+               gctl = lola_readl(chip, BAR0, GCTL);
+               if (gctl)
+                       break;
+       } while (time_before(jiffies, end_time));
+       if (!gctl) {
+               printk(KERN_ERR SFX "cannot reset controller\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static void lola_irq_enable(struct lola *chip)
+{
+       unsigned int val;
+
+       /* enalbe all I/O streams */
+       val = (1 << chip->pcm[PLAY].num_streams) - 1;
+       lola_writel(chip, BAR1, DOINTCTL, val);
+       val = (1 << chip->pcm[CAPT].num_streams) - 1;
+       lola_writel(chip, BAR1, DIINTCTL, val);
+
+       /* enable global irqs */
+       val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR |
+               LOLA_DINT_MUERR;
+       lola_writel(chip, BAR1, DINTCTL, val);
+}
+
+static void lola_irq_disable(struct lola *chip)
+{
+       lola_writel(chip, BAR1, DINTCTL, 0);
+       lola_writel(chip, BAR1, DIINTCTL, 0);
+       lola_writel(chip, BAR1, DOINTCTL, 0);
+}
+
+static int setup_corb_rirb(struct lola *chip)
+{
+       int err;
+       unsigned char tmp;
+       unsigned long end_time;
+
+       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                 snd_dma_pci_data(chip->pci),
+                                 PAGE_SIZE, &chip->rb);
+       if (err < 0)
+               return err;
+
+       chip->corb.addr = chip->rb.addr;
+       chip->corb.buf = (u32 *)chip->rb.area;
+       chip->rirb.addr = chip->rb.addr + 2048;
+       chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+
+       /* disable ringbuffer DMAs */
+       lola_writeb(chip, BAR0, RIRBCTL, 0);
+       lola_writeb(chip, BAR0, CORBCTL, 0);
+
+       end_time = jiffies + msecs_to_jiffies(200);
+       do {
+               if (!lola_readb(chip, BAR0, RIRBCTL) &&
+                   !lola_readb(chip, BAR0, CORBCTL))
+                       break;
+               msleep(1);
+       } while (time_before(jiffies, end_time));
+
+       /* CORB set up */
+       lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr);
+       lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr));
+       /* set the corb size to 256 entries */
+       lola_writeb(chip, BAR0, CORBSIZE, 0x02);
+       /* set the corb write pointer to 0 */
+       lola_writew(chip, BAR0, CORBWP, 0);
+       /* reset the corb hw read pointer */
+       lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR);
+       /* enable corb dma */
+       lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN);
+       /* clear flags if set */
+       tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK;
+       if (tmp)
+               lola_writeb(chip, BAR0, CORBSTS, tmp);
+       chip->corb.wp = 0;
+
+       /* RIRB set up */
+       lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr);
+       lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+       /* set the rirb size to 256 entries */
+       lola_writeb(chip, BAR0, RIRBSIZE, 0x02);
+       /* reset the rirb hw write pointer */
+       lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR);
+       /* set N=1, get RIRB response interrupt for new entry */
+       lola_writew(chip, BAR0, RINTCNT, 1);
+       /* enable rirb dma and response irq */
+       lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN);
+       /* clear flags if set */
+       tmp =  lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK;
+       if (tmp)
+               lola_writeb(chip, BAR0, RIRBSTS, tmp);
+       chip->rirb.rp = chip->rirb.cmds = 0;
+
+       return 0;
+}
+
+static void stop_corb_rirb(struct lola *chip)
+{
+       /* disable ringbuffer DMAs */
+       lola_writeb(chip, BAR0, RIRBCTL, 0);
+       lola_writeb(chip, BAR0, CORBCTL, 0);
+}
+
+static void lola_reset_setups(struct lola *chip)
+{
+       /* update the granularity */
+       lola_set_granularity(chip, chip->granularity, true);
+       /* update the sample clock */
+       lola_set_clock_index(chip, chip->clock.cur_index);
+       /* enable unsolicited events of the clock widget */
+       lola_enable_clock_events(chip);
+       /* update the analog gains */
+       lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */
+       /* update SRC configuration if applicable */
+       lola_set_src_config(chip, chip->input_src_mask, false);
+       /* update the analog outputs */
+       lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */
+}
+
+static int lola_parse_tree(struct lola *chip)
+{
+       unsigned int val;
+       int nid, err;
+
+       err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read VENDOR_ID\n");
+               return err;
+       }
+       val >>= 16;
+       if (val != 0x1369) {
+               printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val);
+               return -EINVAL;
+       }
+
+       err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid);
+               return err;
+       }
+       if (val != 1) {
+               printk(KERN_ERR SFX "Unknown function type %d\n", val);
+               return -EINVAL;
+       }
+
+       err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read SPECCAPS\n");
+               return err;
+       }
+       chip->lola_caps = val;
+       chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps);
+       chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps);
+       snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n",
+                   chip->lola_caps,
+                   chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+
+       if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT ||
+           chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) {
+               printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val);
+               return -EINVAL;
+       }
+
+       nid = 0x02;
+       err = lola_init_pcm(chip, CAPT, &nid);
+       if (err < 0)
+               return err;
+       err = lola_init_pcm(chip, PLAY, &nid);
+       if (err < 0)
+               return err;
+
+       err = lola_init_pins(chip, CAPT, &nid);
+       if (err < 0)
+               return err;
+       err = lola_init_pins(chip, PLAY, &nid);
+       if (err < 0)
+               return err;
+
+       if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+               err = lola_init_clock_widget(chip, nid);
+               if (err < 0)
+                       return err;
+               nid++;
+       }
+       if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+               err = lola_init_mixer_widget(chip, nid);
+               if (err < 0)
+                       return err;
+               nid++;
+       }
+
+       /* enable unsolicited events of the clock widget */
+       err = lola_enable_clock_events(chip);
+       if (err < 0)
+               return err;
+
+       /* if last ResetController was not a ColdReset, we don't know
+        * the state of the card; initialize here again
+        */
+       if (!chip->cold_reset) {
+               lola_reset_setups(chip);
+               chip->cold_reset = 1;
+       } else {
+               /* set the granularity if it is not the default */
+               if (chip->granularity != LOLA_GRANULARITY_MIN)
+                       lola_set_granularity(chip, chip->granularity, true);
+       }
+
+       return 0;
+}
+
+static void lola_stop_hw(struct lola *chip)
+{
+       stop_corb_rirb(chip);
+       lola_irq_disable(chip);
+}
+
+static void lola_free(struct lola *chip)
+{
+       if (chip->initialized)
+               lola_stop_hw(chip);
+       lola_free_pcm(chip);
+       lola_free_mixer(chip);
+       if (chip->irq >= 0)
+               free_irq(chip->irq, (void *)chip);
+       if (chip->bar[0].remap_addr)
+               iounmap(chip->bar[0].remap_addr);
+       if (chip->bar[1].remap_addr)
+               iounmap(chip->bar[1].remap_addr);
+       if (chip->rb.area)
+               snd_dma_free_pages(&chip->rb);
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+       kfree(chip);
+}
+
+static int lola_dev_free(struct snd_device *device)
+{
+       lola_free(device->device_data);
+       return 0;
+}
+
+static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
+                                int dev, struct lola **rchip)
+{
+       struct lola *chip;
+       int err;
+       unsigned int dever;
+       static struct snd_device_ops ops = {
+               .dev_free = lola_dev_free,
+       };
+
+       *rchip = NULL;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip) {
+               snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+               pci_disable_device(pci);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&chip->reg_lock);
+       mutex_init(&chip->open_mutex);
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+
+       chip->granularity = granularity[dev];
+       switch (chip->granularity) {
+       case 8:
+               chip->sample_rate_max = 48000;
+               break;
+       case 16:
+               chip->sample_rate_max = 96000;
+               break;
+       case 32:
+               chip->sample_rate_max = 192000;
+               break;
+       default:
+               snd_printk(KERN_WARNING SFX
+                          "Invalid granularity %d, reset to %d\n",
+                          chip->granularity, LOLA_GRANULARITY_MAX);
+               chip->granularity = LOLA_GRANULARITY_MAX;
+               chip->sample_rate_max = 192000;
+               break;
+       }
+       chip->sample_rate_min = sample_rate_min[dev];
+       if (chip->sample_rate_min > chip->sample_rate_max) {
+               snd_printk(KERN_WARNING SFX
+                          "Invalid sample_rate_min %d, reset to 16000\n",
+                          chip->sample_rate_min);
+               chip->sample_rate_min = 16000;
+       }
+
+       err = pci_request_regions(pci, DRVNAME);
+       if (err < 0) {
+               kfree(chip);
+               pci_disable_device(pci);
+               return err;
+       }
+
+       chip->bar[0].addr = pci_resource_start(pci, 0);
+       chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0);
+       chip->bar[1].addr = pci_resource_start(pci, 2);
+       chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2);
+       if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) {
+               snd_printk(KERN_ERR SFX "ioremap error\n");
+               err = -ENXIO;
+               goto errout;
+       }
+
+       pci_set_master(pci);
+
+       err = reset_controller(chip);
+       if (err < 0)
+               goto errout;
+
+       if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
+                       DRVNAME, chip)) {
+               printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+               err = -EBUSY;
+               goto errout;
+       }
+       chip->irq = pci->irq;
+       synchronize_irq(chip->irq);
+
+       dever = lola_readl(chip, BAR1, DEVER);
+       chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff;
+       chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff;
+       chip->version = (dever >> 24) & 0xff;
+       snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n",
+                   chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams,
+                   chip->version);
+
+       /* Test LOLA_BAR1_DEVER */
+       if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT ||
+           chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT ||
+           (!chip->pcm[CAPT].num_streams &&
+            !chip->pcm[PLAY].num_streams)) {
+               printk(KERN_ERR SFX "invalid DEVER = %x\n", dever);
+               err = -EINVAL;
+               goto errout;
+       }
+
+       err = setup_corb_rirb(chip);
+       if (err < 0)
+               goto errout;
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+               goto errout;
+       }
+
+       strcpy(card->driver, "Lola");
+       strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
+       snprintf(card->longname, sizeof(card->longname),
+                "%s at 0x%lx irq %i",
+                card->shortname, chip->bar[0].addr, chip->irq);
+       strcpy(card->mixername, card->shortname);
+
+       lola_irq_enable(chip);
+
+       chip->initialized = 1;
+       *rchip = chip;
+       return 0;
+
+ errout:
+       lola_free(chip);
+       return err;
+}
+
+static int __devinit lola_probe(struct pci_dev *pci,
+                               const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct lola *chip;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       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 err;
+       }
+
+       snd_card_set_dev(card, &pci->dev);
+
+       err = lola_create(card, pci, dev, &chip);
+       if (err < 0)
+               goto out_free;
+       card->private_data = chip;
+
+       err = lola_parse_tree(chip);
+       if (err < 0)
+               goto out_free;
+
+       err = lola_create_pcm(chip);
+       if (err < 0)
+               goto out_free;
+
+       err = lola_create_mixer(chip);
+       if (err < 0)
+               goto out_free;
+
+       lola_proc_debug_new(chip);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto out_free;
+
+       pci_set_drvdata(pci, card);
+       dev++;
+       return err;
+out_free:
+       snd_card_free(card);
+       return err;
+}
+
+static void __devexit lola_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+/* PCI IDs */
+static DEFINE_PCI_DEVICE_TABLE(lola_ids) = {
+       { PCI_VDEVICE(DIGIGRAM, 0x0001) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, lola_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+       .name = DRVNAME,
+       .id_table = lola_ids,
+       .probe = lola_probe,
+       .remove = __devexit_p(lola_remove),
+};
+
+static int __init alsa_card_lola_init(void)
+{
+       return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_lola_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_lola_init)
+module_exit(alsa_card_lola_exit)
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
new file mode 100644 (file)
index 0000000..d5708e2
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _LOLA_H
+#define _LOLA_H
+
+#define DRVNAME        "snd-lola"
+#define SFX    DRVNAME ": "
+
+/*
+ * Lola HD Audio Registers BAR0
+ */
+#define LOLA_BAR0_GCAP         0x00
+#define LOLA_BAR0_VMIN         0x02
+#define LOLA_BAR0_VMAJ         0x03
+#define LOLA_BAR0_OUTPAY       0x04
+#define LOLA_BAR0_INPAY                0x06
+#define LOLA_BAR0_GCTL         0x08
+#define LOLA_BAR0_WAKEEN       0x0c
+#define LOLA_BAR0_STATESTS     0x0e
+#define LOLA_BAR0_GSTS         0x10
+#define LOLA_BAR0_OUTSTRMPAY   0x18
+#define LOLA_BAR0_INSTRMPAY    0x1a
+#define LOLA_BAR0_INTCTL       0x20
+#define LOLA_BAR0_INTSTS       0x24
+#define LOLA_BAR0_WALCLK       0x30
+#define LOLA_BAR0_SSYNC                0x38
+
+#define LOLA_BAR0_CORBLBASE    0x40
+#define LOLA_BAR0_CORBUBASE    0x44
+#define LOLA_BAR0_CORBWP       0x48    /* no ULONG access */
+#define LOLA_BAR0_CORBRP       0x4a    /* no ULONG access */
+#define LOLA_BAR0_CORBCTL      0x4c    /* no ULONG access */
+#define LOLA_BAR0_CORBSTS      0x4d    /* UCHAR access only */
+#define LOLA_BAR0_CORBSIZE     0x4e    /* no ULONG access */
+
+#define LOLA_BAR0_RIRBLBASE    0x50
+#define LOLA_BAR0_RIRBUBASE    0x54
+#define LOLA_BAR0_RIRBWP       0x58
+#define LOLA_BAR0_RINTCNT      0x5a    /* no ULONG access */
+#define LOLA_BAR0_RIRBCTL      0x5c
+#define LOLA_BAR0_RIRBSTS      0x5d    /* UCHAR access only */
+#define LOLA_BAR0_RIRBSIZE     0x5e    /* no ULONG access */
+
+#define LOLA_BAR0_ICW          0x60
+#define LOLA_BAR0_IRR          0x64
+#define LOLA_BAR0_ICS          0x68
+#define LOLA_BAR0_DPLBASE      0x70
+#define LOLA_BAR0_DPUBASE      0x74
+
+/* stream register offsets from stream base 0x80 */
+#define LOLA_BAR0_SD0_OFFSET   0x80
+#define LOLA_REG0_SD_CTL       0x00
+#define LOLA_REG0_SD_STS       0x03
+#define LOLA_REG0_SD_LPIB      0x04
+#define LOLA_REG0_SD_CBL       0x08
+#define LOLA_REG0_SD_LVI       0x0c
+#define LOLA_REG0_SD_FIFOW     0x0e
+#define LOLA_REG0_SD_FIFOSIZE  0x10
+#define LOLA_REG0_SD_FORMAT    0x12
+#define LOLA_REG0_SD_BDLPL     0x18
+#define LOLA_REG0_SD_BDLPU     0x1c
+
+/*
+ * Lola Digigram Registers BAR1
+ */
+#define LOLA_BAR1_FPGAVER      0x00
+#define LOLA_BAR1_DEVER                0x04
+#define LOLA_BAR1_UCBMV                0x08
+#define LOLA_BAR1_JTAG         0x0c
+#define LOLA_BAR1_UARTRX       0x10
+#define LOLA_BAR1_UARTTX       0x14
+#define LOLA_BAR1_UARTCR       0x18
+#define LOLA_BAR1_NVRAMVER     0x1c
+#define LOLA_BAR1_CTRLSPI      0x20
+#define LOLA_BAR1_DSPI         0x24
+#define LOLA_BAR1_AISPI                0x28
+#define LOLA_BAR1_GRAN         0x2c
+
+#define LOLA_BAR1_DINTCTL      0x80
+#define LOLA_BAR1_DIINTCTL     0x84
+#define LOLA_BAR1_DOINTCTL     0x88
+#define LOLA_BAR1_LRC          0x90
+#define LOLA_BAR1_DINTSTS      0x94
+#define LOLA_BAR1_DIINTSTS     0x98
+#define LOLA_BAR1_DOINTSTS     0x9c
+
+#define LOLA_BAR1_DSD0_OFFSET  0xa0
+#define LOLA_BAR1_DSD_SIZE     0x18
+
+#define LOLA_BAR1_DSDnSTS       0x00
+#define LOLA_BAR1_DSDnLPIB      0x04
+#define LOLA_BAR1_DSDnCTL       0x08
+#define LOLA_BAR1_DSDnLVI       0x0c
+#define LOLA_BAR1_DSDnBDPL      0x10
+#define LOLA_BAR1_DSDnBDPU      0x14
+
+#define LOLA_BAR1_SSYNC                0x03e8
+
+#define LOLA_BAR1_BOARD_CTRL   0x0f00
+#define LOLA_BAR1_BOARD_MODE   0x0f02
+
+#define LOLA_BAR1_SOURCE_GAIN_ENABLE           0x1000
+#define LOLA_BAR1_DEST00_MIX_GAIN_ENABLE       0x1004
+#define LOLA_BAR1_DEST31_MIX_GAIN_ENABLE       0x1080
+#define LOLA_BAR1_SOURCE00_01_GAIN             0x1084
+#define LOLA_BAR1_SOURCE30_31_GAIN             0x10c0
+#define LOLA_BAR1_SOURCE_GAIN(src) \
+       (LOLA_BAR1_SOURCE00_01_GAIN + (src) * 2)
+#define LOLA_BAR1_DEST00_MIX00_01_GAIN         0x10c4
+#define LOLA_BAR1_DEST00_MIX30_31_GAIN         0x1100
+#define LOLA_BAR1_DEST01_MIX00_01_GAIN         0x1104
+#define LOLA_BAR1_DEST01_MIX30_31_GAIN         0x1140
+#define LOLA_BAR1_DEST31_MIX00_01_GAIN         0x1884
+#define LOLA_BAR1_DEST31_MIX30_31_GAIN         0x18c0
+#define LOLA_BAR1_MIX_GAIN(dest, mix) \
+       (LOLA_BAR1_DEST00_MIX00_01_GAIN + (dest) * 0x40 + (mix) * 2)
+#define LOLA_BAR1_ANALOG_CLIP_IN               0x18c4
+#define LOLA_BAR1_PEAKMETERS_SOURCE00_01       0x18c8
+#define LOLA_BAR1_PEAKMETERS_SOURCE30_31       0x1904
+#define LOLA_BAR1_PEAKMETERS_SOURCE(src) \
+       (LOLA_BAR1_PEAKMETERS_SOURCE00_01 + (src) * 2)
+#define LOLA_BAR1_PEAKMETERS_DEST00_01         0x1908
+#define LOLA_BAR1_PEAKMETERS_DEST30_31         0x1944
+#define LOLA_BAR1_PEAKMETERS_DEST(dest) \
+       (LOLA_BAR1_PEAKMETERS_DEST00_01 + (dest) * 2)
+#define LOLA_BAR1_PEAKMETERS_AGC00_01          0x1948
+#define LOLA_BAR1_PEAKMETERS_AGC14_15          0x1964
+#define LOLA_BAR1_PEAKMETERS_AGC(x) \
+       (LOLA_BAR1_PEAKMETERS_AGC00_01 + (x) * 2)
+
+/* GCTL reset bit */
+#define LOLA_GCTL_RESET                (1 << 0)
+/* GCTL unsolicited response enable bit */
+#define LOLA_GCTL_UREN         (1 << 8)
+
+/* CORB/RIRB control, read/write pointer */
+#define LOLA_RBCTL_DMA_EN      0x02    /* enable DMA */
+#define LOLA_RBCTL_IRQ_EN      0x01    /* enable IRQ */
+#define LOLA_RBRWP_CLR         0x8000  /* read/write pointer clear */
+
+#define LOLA_RIRB_EX_UNSOL_EV  0x40000000
+#define LOLA_RIRB_EX_ERROR     0x80000000
+
+/* CORB int mask: CMEI[0] */
+#define LOLA_CORB_INT_CMEI     0x01
+#define LOLA_CORB_INT_MASK     LOLA_CORB_INT_CMEI
+
+/* RIRB int mask: overrun[2], response[0] */
+#define LOLA_RIRB_INT_RESPONSE 0x01
+#define LOLA_RIRB_INT_OVERRUN  0x04
+#define LOLA_RIRB_INT_MASK     (LOLA_RIRB_INT_RESPONSE | LOLA_RIRB_INT_OVERRUN)
+
+/* DINTCTL and DINTSTS */
+#define LOLA_DINT_GLOBAL       0x80000000 /* global interrupt enable bit */
+#define LOLA_DINT_CTRL         0x40000000 /* controller interrupt enable bit */
+#define LOLA_DINT_FIFOERR      0x20000000 /* global fifo error enable bit */
+#define LOLA_DINT_MUERR                0x10000000 /* global microcontroller underrun error */
+
+/* DSDnCTL bits */
+#define LOLA_DSD_CTL_SRST      0x01    /* stream reset bit */
+#define LOLA_DSD_CTL_SRUN      0x02    /* stream DMA start bit */
+#define LOLA_DSD_CTL_IOCE      0x04    /* interrupt on completion enable */
+#define LOLA_DSD_CTL_DEIE      0x10    /* descriptor error interrupt enable */
+#define LOLA_DSD_CTL_VLRCV     0x20    /* valid LRCountValue information in bits 8..31 */
+#define LOLA_LRC_MASK          0xffffff00
+
+/* DSDnSTS */
+#define LOLA_DSD_STS_BCIS      0x04    /* buffer completion interrupt status */
+#define LOLA_DSD_STS_DESE      0x10    /* descriptor error interrupt */
+#define LOLA_DSD_STS_FIFORDY   0x20    /* fifo ready */
+
+#define LOLA_CORB_ENTRIES      256
+
+#define MAX_STREAM_IN_COUNT    16
+#define MAX_STREAM_OUT_COUNT   16
+#define MAX_STREAM_COUNT       16
+#define MAX_PINS               MAX_STREAM_COUNT
+#define MAX_STREAM_BUFFER_COUNT        16
+#define MAX_AUDIO_INOUT_COUNT  16
+
+#define LOLA_CLOCK_TYPE_INTERNAL    0
+#define LOLA_CLOCK_TYPE_AES         1
+#define LOLA_CLOCK_TYPE_AES_SYNC    2
+#define LOLA_CLOCK_TYPE_WORDCLOCK   3
+#define LOLA_CLOCK_TYPE_ETHERSOUND  4
+#define LOLA_CLOCK_TYPE_VIDEO       5
+
+#define LOLA_CLOCK_FORMAT_NONE      0
+#define LOLA_CLOCK_FORMAT_NTSC      1
+#define LOLA_CLOCK_FORMAT_PAL       2
+
+#define MAX_SAMPLE_CLOCK_COUNT  48
+
+/* parameters used with mixer widget's mixer capabilities */
+#define LOLA_PEAK_METER_CAN_AGC_MASK           1
+#define LOLA_PEAK_METER_CAN_ANALOG_CLIP_MASK   2
+
+struct lola_bar {
+       unsigned long addr;
+       void __iomem *remap_addr;
+};
+
+/* CORB/RIRB */
+struct lola_rb {
+       u32 *buf;               /* CORB/RIRB buffer, 8 byte per each entry */
+       dma_addr_t addr;        /* physical address of CORB/RIRB buffer */
+       unsigned short rp, wp;  /* read/write pointers */
+       int cmds;               /* number of pending requests */
+};
+
+/* Pin widget setup */
+struct lola_pin {
+       unsigned int nid;
+       bool is_analog;
+       unsigned int amp_mute;
+       unsigned int amp_step_size;
+       unsigned int amp_num_steps;
+       unsigned int amp_offset;
+       unsigned int max_level;
+       unsigned int config_default_reg;
+       unsigned int fixed_gain_list_len;
+       unsigned int cur_gain_step;
+};
+
+struct lola_pin_array {
+       unsigned int num_pins;
+       unsigned int num_analog_pins;
+       struct lola_pin pins[MAX_PINS];
+};
+
+/* Clock widget setup */
+struct lola_sample_clock {
+       unsigned int type;
+       unsigned int format;
+       unsigned int freq;
+};
+
+struct lola_clock_widget {
+       unsigned int nid;
+       unsigned int items;
+       unsigned int cur_index;
+       unsigned int cur_freq;
+       bool cur_valid;
+       struct lola_sample_clock sample_clock[MAX_SAMPLE_CLOCK_COUNT];
+       unsigned int idx_lookup[MAX_SAMPLE_CLOCK_COUNT];
+};
+
+#define LOLA_MIXER_DIM      32
+struct lola_mixer_array {
+       u32 src_gain_enable;
+       u32 dest_mix_gain_enable[LOLA_MIXER_DIM];
+       u16 src_gain[LOLA_MIXER_DIM];
+       u16 dest_mix_gain[LOLA_MIXER_DIM][LOLA_MIXER_DIM];
+};
+
+/* Mixer widget setup */
+struct lola_mixer_widget {
+       unsigned int nid;
+       unsigned int caps;
+       struct lola_mixer_array __user *array;
+       struct lola_mixer_array *array_saved;
+       unsigned int src_stream_outs;
+       unsigned int src_phys_ins;
+       unsigned int dest_stream_ins;
+       unsigned int dest_phys_outs;
+       unsigned int src_stream_out_ofs;
+       unsigned int dest_phys_out_ofs;
+       unsigned int src_mask;
+       unsigned int dest_mask;
+};
+
+/* Audio stream */
+struct lola_stream {
+       unsigned int nid;       /* audio widget NID */
+       unsigned int index;     /* array index */
+       unsigned int dsd;       /* DSD index */
+       bool can_float;
+       struct snd_pcm_substream *substream; /* assigned PCM substream */
+       struct lola_stream *master;     /* master stream (for multi-channel) */
+
+       /* buffer setup */
+       unsigned int bufsize;
+       unsigned int period_bytes;
+       unsigned int frags;
+
+       /* format + channel setup */
+       unsigned int format_verb;
+
+       /* flags */
+       unsigned int opened:1;
+       unsigned int prepared:1;
+       unsigned int paused:1;
+       unsigned int running:1;
+};
+
+#define PLAY   SNDRV_PCM_STREAM_PLAYBACK
+#define CAPT   SNDRV_PCM_STREAM_CAPTURE
+
+struct lola_pcm {
+       unsigned int num_streams;
+       struct snd_dma_buffer bdl; /* BDL buffer */
+       struct lola_stream streams[MAX_STREAM_COUNT];
+};
+
+/* card instance */
+struct lola {
+       struct snd_card *card;
+       struct pci_dev *pci;
+
+       /* pci resources */
+       struct lola_bar bar[2];
+       int irq;
+
+       /* locks */
+       spinlock_t reg_lock;
+       struct mutex open_mutex;
+
+       /* CORB/RIRB */
+       struct lola_rb corb;
+       struct lola_rb rirb;
+       unsigned int res, res_ex;       /* last read values */
+       /* last command (for debugging) */
+       unsigned int last_cmd_nid, last_verb, last_data, last_extdata;
+
+       /* CORB/RIRB buffers */
+       struct snd_dma_buffer rb;
+
+       /* unsolicited events */
+       unsigned int last_unsol_res;
+
+       /* streams */
+       struct lola_pcm pcm[2];
+
+       /* input src */
+       unsigned int input_src_caps_mask;
+       unsigned int input_src_mask;
+
+       /* pins */
+       struct lola_pin_array pin[2];
+
+       /* clock */
+       struct lola_clock_widget clock;
+       int ref_count_rate;
+       unsigned int sample_rate;
+
+       /* mixer */
+       struct lola_mixer_widget mixer;
+
+       /* hw info */
+       unsigned int version;
+       unsigned int lola_caps;
+
+       /* parameters */
+       unsigned int granularity;
+       unsigned int sample_rate_min;
+       unsigned int sample_rate_max;
+
+       /* flags */
+       unsigned int initialized:1;
+       unsigned int cold_reset:1;
+       unsigned int polling_mode:1;
+
+       /* for debugging */
+       unsigned int debug_res;
+       unsigned int debug_res_ex;
+};
+
+#define BAR0   0
+#define BAR1   1
+
+/* Helper macros */
+#define lola_readl(chip, idx, name) \
+       readl((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readw(chip, idx, name) \
+       readw((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readb(chip, idx, name) \
+       readb((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writel(chip, idx, name, val) \
+       writel((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writew(chip, idx, name, val) \
+       writew((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writeb(chip, idx, name, val) \
+       writeb((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+
+#define lola_dsd_read(chip, dsd, name) \
+       readl((chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+             (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+#define lola_dsd_write(chip, dsd, name, val) \
+       writel((val), (chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+              (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+
+/* GET verbs HDAudio */
+#define LOLA_VERB_GET_STREAM_FORMAT            0xa00
+#define LOLA_VERB_GET_AMP_GAIN_MUTE            0xb00
+#define LOLA_VERB_PARAMETERS                   0xf00
+#define LOLA_VERB_GET_POWER_STATE              0xf05
+#define LOLA_VERB_GET_CONV                     0xf06
+#define LOLA_VERB_GET_UNSOLICITED_RESPONSE     0xf08
+#define LOLA_VERB_GET_DIGI_CONVERT_1           0xf0d
+#define LOLA_VERB_GET_CONFIG_DEFAULT           0xf1c
+#define LOLA_VERB_GET_SUBSYSTEM_ID             0xf20
+/* GET verbs Digigram */
+#define LOLA_VERB_GET_FIXED_GAIN               0xfc0
+#define LOLA_VERB_GET_GAIN_SELECT              0xfc1
+#define LOLA_VERB_GET_MAX_LEVEL                        0xfc2
+#define LOLA_VERB_GET_CLOCK_LIST               0xfc3
+#define LOLA_VERB_GET_CLOCK_SELECT             0xfc4
+#define LOLA_VERB_GET_CLOCK_STATUS             0xfc5
+
+/* SET verbs HDAudio */
+#define LOLA_VERB_SET_STREAM_FORMAT            0x200
+#define LOLA_VERB_SET_AMP_GAIN_MUTE            0x300
+#define LOLA_VERB_SET_POWER_STATE              0x705
+#define LOLA_VERB_SET_CHANNEL_STREAMID         0x706
+#define LOLA_VERB_SET_UNSOLICITED_ENABLE       0x708
+#define LOLA_VERB_SET_DIGI_CONVERT_1           0x70d
+/* SET verbs Digigram */
+#define LOLA_VERB_SET_GAIN_SELECT              0xf81
+#define LOLA_VERB_SET_CLOCK_SELECT             0xf84
+#define LOLA_VERB_SET_GRANULARITY_STEPS                0xf86
+#define LOLA_VERB_SET_SOURCE_GAIN              0xf87
+#define LOLA_VERB_SET_MIX_GAIN                 0xf88
+#define LOLA_VERB_SET_DESTINATION_GAIN         0xf89
+#define LOLA_VERB_SET_SRC                      0xf8a
+
+/* Parameter IDs used with LOLA_VERB_PARAMETERS */
+#define LOLA_PAR_VENDOR_ID                     0x00
+#define LOLA_PAR_FUNCTION_TYPE                 0x05
+#define LOLA_PAR_AUDIO_WIDGET_CAP              0x09
+#define LOLA_PAR_PCM                           0x0a
+#define LOLA_PAR_STREAM_FORMATS                        0x0b
+#define LOLA_PAR_PIN_CAP                       0x0c
+#define LOLA_PAR_AMP_IN_CAP                    0x0d
+#define LOLA_PAR_CONNLIST_LEN                  0x0e
+#define LOLA_PAR_POWER_STATE                   0x0f
+#define LOLA_PAR_GPIO_CAP                      0x11
+#define LOLA_PAR_AMP_OUT_CAP                   0x12
+#define LOLA_PAR_SPECIFIC_CAPS                 0x80
+#define LOLA_PAR_FIXED_GAIN_LIST               0x81
+
+/* extract results of LOLA_PAR_SPECIFIC_CAPS */
+#define LOLA_AFG_MIXER_WIDGET_PRESENT(res)     ((res & (1 << 21)) != 0)
+#define LOLA_AFG_CLOCK_WIDGET_PRESENT(res)     ((res & (1 << 20)) != 0)
+#define LOLA_AFG_INPUT_PIN_COUNT(res)          ((res >> 10) & 0x2ff)
+#define LOLA_AFG_OUTPUT_PIN_COUNT(res)         ((res) & 0x2ff)
+
+/* extract results of LOLA_PAR_AMP_IN_CAP / LOLA_PAR_AMP_OUT_CAP */
+#define LOLA_AMP_MUTE_CAPABLE(res)             ((res & (1 << 31)) != 0)
+#define LOLA_AMP_STEP_SIZE(res)                        ((res >> 24) & 0x7f)
+#define LOLA_AMP_NUM_STEPS(res)                        ((res >> 12) & 0x3ff)
+#define LOLA_AMP_OFFSET(res)                   ((res) & 0x3ff)
+
+#define LOLA_GRANULARITY_MIN           8
+#define LOLA_GRANULARITY_MAX           32
+#define LOLA_GRANULARITY_STEP          8
+
+/* parameters used with unsolicited command/response */
+#define LOLA_UNSOLICITED_TAG_MASK      0x3f
+#define LOLA_UNSOLICITED_TAG           0x1a
+#define LOLA_UNSOLICITED_ENABLE                0x80
+#define LOLA_UNSOL_RESP_TAG_OFFSET     26
+
+/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
+#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res)   ((res >> 2) & 0x1f)
+#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res)  ((res >> 7) & 0x1f)
+
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+                    unsigned int data, unsigned int extdata);
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+                   unsigned int data, unsigned int extdata,
+                   unsigned int *val, unsigned int *extval);
+int lola_codec_flush(struct lola *chip);
+#define lola_read_param(chip, nid, param, val) \
+       lola_codec_read(chip, nid, LOLA_VERB_PARAMETERS, param, 0, val, NULL)
+
+/* PCM */
+int lola_create_pcm(struct lola *chip);
+void lola_free_pcm(struct lola *chip);
+int lola_init_pcm(struct lola *chip, int dir, int *nidp);
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits);
+
+/* clock */
+int lola_init_clock_widget(struct lola *chip, int nid);
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force);
+int lola_enable_clock_events(struct lola *chip);
+int lola_set_clock_index(struct lola *chip, unsigned int idx);
+int lola_set_clock(struct lola *chip, int idx);
+int lola_set_sample_rate(struct lola *chip, int rate);
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val);
+unsigned int lola_sample_rate_convert(unsigned int coded);
+
+/* mixer */
+int lola_init_pins(struct lola *chip, int dir, int *nidp);
+int lola_init_mixer_widget(struct lola *chip, int nid);
+void lola_free_mixer(struct lola *chip);
+int lola_create_mixer(struct lola *chip);
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute);
+void lola_save_mixer(struct lola *chip);
+void lola_restore_mixer(struct lola *chip);
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update);
+
+/* proc */
+#ifdef CONFIG_SND_DEBUG
+void lola_proc_debug_new(struct lola *chip);
+#else
+#define lola_proc_debug_new(chip)
+#endif
+
+#endif /* _LOLA_H */
diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c
new file mode 100644 (file)
index 0000000..72f8ef0
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+unsigned int lola_sample_rate_convert(unsigned int coded)
+{
+       unsigned int freq;
+
+       /* base frequency */
+       switch (coded & 0x3) {
+       case 0:     freq = 48000; break;
+       case 1:     freq = 44100; break;
+       case 2:     freq = 32000; break;
+       default:    return 0;   /* error */
+       }
+
+       /* multiplier / devisor */
+       switch (coded & 0x1c) {
+       case (0 << 2):    break;
+       case (4 << 2):    break;
+       case (1 << 2):    freq *= 2; break;
+       case (2 << 2):    freq *= 4; break;
+       case (5 << 2):    freq /= 2; break;
+       case (6 << 2):    freq /= 4; break;
+       default:        return 0;   /* error */
+       }
+
+       /* ajustement */
+       switch (coded & 0x60) {
+       case (0 << 5):    break;
+       case (1 << 5):    freq = (freq * 999) / 1000; break;
+       case (2 << 5):    freq = (freq * 1001) / 1000; break;
+       default:        return 0;   /* error */
+       }
+       return freq;
+}
+
+/*
+ * Granualrity
+ */
+
+#define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
+#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
+
+static bool check_gran_clock_compatibility(struct lola *chip,
+                                          unsigned int val,
+                                          unsigned int freq)
+{
+       if (!chip->granularity)
+               return true;
+
+       if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
+           (val % LOLA_GRANULARITY_STEP) != 0)
+               return false;
+
+       if (val == LOLA_GRANULARITY_MIN) {
+               if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
+                       return false;
+       } else if (val < LOLA_GRANULARITY_MAX) {
+               if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
+                       return false;
+       }
+       return true;
+}
+
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
+{
+       int err;
+
+       if (!force) {
+               if (val == chip->granularity)
+                       return 0;
+#if 0
+               /* change Gran only if there are no streams allocated ! */
+               if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
+                       return -EBUSY;
+#endif
+               if (!check_gran_clock_compatibility(chip, val,
+                                                   chip->clock.cur_freq))
+                       return -EINVAL;
+       }
+
+       chip->granularity = val;
+       val /= LOLA_GRANULARITY_STEP;
+
+       /* audio function group */
+       err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
+                              val, 0);
+       if (err < 0)
+               return err;
+       /* this can be a very slow function !!! */
+       usleep_range(400 * val, 20000);
+       return lola_codec_flush(chip);
+}
+
+/*
+ * Clock widget handling
+ */
+
+int __devinit lola_init_clock_widget(struct lola *chip, int nid)
+{
+       unsigned int val;
+       int i, j, nitems, nb_verbs, idx, idx_list;
+       int err;
+
+       err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               return err;
+       }
+
+       if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
+               snd_printdd("No valid clock widget\n");
+               return 0;
+       }
+
+       chip->clock.nid = nid;
+       chip->clock.items = val & 0xff;
+       snd_printdd("clock_list nid=%x, entries=%d\n", nid,
+                   chip->clock.items);
+       if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
+               printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
+                      chip->clock.items);
+               return -EINVAL;
+       }
+
+       nitems = chip->clock.items;
+       nb_verbs = (nitems + 3) / 4;
+       idx = 0;
+       idx_list = 0;
+       for (i = 0; i < nb_verbs; i++) {
+               unsigned int res_ex;
+               unsigned short items[4];
+
+               err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+                                     idx, 0, &val, &res_ex);
+               if (err < 0) {
+                       printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
+                       return -EINVAL;
+               }
+
+               items[0] = val & 0xfff;
+               items[1] = (val >> 16) & 0xfff;
+               items[2] = res_ex & 0xfff;
+               items[3] = (res_ex >> 16) & 0xfff;
+
+               for (j = 0; j < 4; j++) {
+                       unsigned char type = items[j] >> 8;
+                       unsigned int freq = items[j] & 0xff;
+                       int format = LOLA_CLOCK_FORMAT_NONE;
+                       bool add_clock = true;
+                       if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+                               freq = lola_sample_rate_convert(freq);
+                               if (freq < chip->sample_rate_min)
+                                       add_clock = false;
+                               else if (freq == 48000) {
+                                       chip->clock.cur_index = idx_list;
+                                       chip->clock.cur_freq = 48000;
+                                       chip->clock.cur_valid = true;
+                               }
+                       } else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+                               freq = lola_sample_rate_convert(freq);
+                               if (freq < chip->sample_rate_min)
+                                       add_clock = false;
+                               /* video clock has a format (0:NTSC, 1:PAL)*/
+                               if (items[j] & 0x80)
+                                       format = LOLA_CLOCK_FORMAT_NTSC;
+                               else
+                                       format = LOLA_CLOCK_FORMAT_PAL;
+                       }
+                       if (add_clock) {
+                               struct lola_sample_clock *sc;
+                               sc = &chip->clock.sample_clock[idx_list];
+                               sc->type = type;
+                               sc->format = format;
+                               sc->freq = freq;
+                               /* keep the index used with the board */
+                               chip->clock.idx_lookup[idx_list] = idx;
+                               idx_list++;
+                       } else {
+                               chip->clock.items--;
+                       }
+                       if (++idx >= nitems)
+                               break;
+               }
+       }
+       return 0;
+}
+
+/* enable unsolicited events of the clock widget */
+int lola_enable_clock_events(struct lola *chip)
+{
+       unsigned int res;
+       int err;
+
+       err = lola_codec_read(chip, chip->clock.nid,
+                             LOLA_VERB_SET_UNSOLICITED_ENABLE,
+                             LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
+                             0, &res, NULL);
+       if (err < 0)
+               return err;
+       if (res) {
+               printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
+                      res);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int lola_set_clock_index(struct lola *chip, unsigned int idx)
+{
+       unsigned int res;
+       int err;
+
+       err = lola_codec_read(chip, chip->clock.nid,
+                             LOLA_VERB_SET_CLOCK_SELECT,
+                             chip->clock.idx_lookup[idx],
+                             0, &res, NULL);
+       if (err < 0)
+               return err;
+       if (res) {
+               printk(KERN_WARNING SFX "error in set_clock %d\n", res);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
+{
+       unsigned int tag;
+
+       /* the current EXTERNAL clock information gets updated by interrupt
+        * with an unsolicited response
+        */
+       if (!val)
+               return false;
+       tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
+       if (tag != LOLA_UNSOLICITED_TAG)
+               return false;
+
+       /* only for current = external clocks */
+       if (chip->clock.sample_clock[chip->clock.cur_index].type !=
+           LOLA_CLOCK_TYPE_INTERNAL) {
+               chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
+               chip->clock.cur_valid = (val & 0x100) != 0;
+       }
+       return true;
+}
+
+int lola_set_clock(struct lola *chip, int idx)
+{
+       int freq = 0;
+       bool valid = false;
+
+       if (idx == chip->clock.cur_index) {
+               /* current clock is allowed */
+               freq = chip->clock.cur_freq;
+               valid = chip->clock.cur_valid;
+       } else if (chip->clock.sample_clock[idx].type ==
+                  LOLA_CLOCK_TYPE_INTERNAL) {
+               /* internal clocks allowed */
+               freq = chip->clock.sample_clock[idx].freq;
+               valid = true;
+       }
+
+       if (!freq || !valid)
+               return -EINVAL;
+
+       if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
+               return -EINVAL;
+
+       if (idx != chip->clock.cur_index) {
+               int err = lola_set_clock_index(chip, idx);
+               if (err < 0)
+                       return err;
+               /* update new settings */
+               chip->clock.cur_index = idx;
+               chip->clock.cur_freq = freq;
+               chip->clock.cur_valid = true;
+       }
+       return 0;
+}
+
+int lola_set_sample_rate(struct lola *chip, int rate)
+{
+       int i;
+
+       if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
+               return 0;
+       /* search for new dwClockIndex */
+       for (i = 0; i < chip->clock.items; i++) {
+               if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
+                   chip->clock.sample_clock[i].freq == rate)
+                       break;
+       }
+       if (i >= chip->clock.items)
+               return -EINVAL;
+       return lola_set_clock(chip, i);
+}
+
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
new file mode 100644 (file)
index 0000000..5d518f1
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lola.h"
+
+static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin,
+                                  int dir, int nid)
+{
+       unsigned int val;
+       int err;
+
+       pin->nid = nid;
+       err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               return err;
+       }
+       val &= 0x00f00fff; /* test TYPE and bits 0..11 */
+       if (val == 0x00400200)    /* Type = 4, Digital = 1 */
+               pin->is_analog = false;
+       else if (val == 0x0040000a && dir == CAPT) /* Dig=0, InAmp/ovrd */
+               pin->is_analog = true;
+       else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */
+               pin->is_analog = true;
+       else {
+               printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid);
+               return -EINVAL;
+       }
+
+       /* analog parameters only following, so continue in case of Digital pin
+        */
+       if (!pin->is_analog)
+               return 0;
+
+       if (dir == PLAY)
+               err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val);
+       else
+               err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid);
+               return err;
+       }
+
+       pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val);
+       pin->amp_step_size = LOLA_AMP_STEP_SIZE(val);
+       pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val);
+       if (pin->amp_num_steps) {
+               /* zero as mute state */
+               pin->amp_num_steps++;
+               pin->amp_step_size++;
+       }
+       pin->amp_offset = LOLA_AMP_OFFSET(val);
+
+       err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
+                             NULL);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid);
+               return err;
+       }
+       pin->max_level = val & 0x3ff;   /* 10 bits */
+
+       pin->config_default_reg = 0;
+       pin->fixed_gain_list_len = 0;
+       pin->cur_gain_step = 0;
+
+       return 0;
+}
+
+int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp)
+{
+       int i, err, nid;
+       nid = *nidp;
+       for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) {
+               err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid);
+               if (err < 0)
+                       return err;
+               if (chip->pin[dir].pins[i].is_analog)
+                       chip->pin[dir].num_analog_pins++;
+       }
+       *nidp = nid;
+       return 0;
+}
+
+void lola_free_mixer(struct lola *chip)
+{
+       if (chip->mixer.array_saved)
+               vfree(chip->mixer.array_saved);
+}
+
+int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
+{
+       unsigned int val;
+       int err;
+
+       err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               return err;
+       }
+
+       if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */
+               snd_printdd("No valid mixer widget\n");
+               return 0;
+       }
+
+       chip->mixer.nid = nid;
+       chip->mixer.caps = val;
+       chip->mixer.array = (struct lola_mixer_array __iomem *)
+               (chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE);
+
+       /* reserve memory to copy mixer data for sleep mode transitions */
+       chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array));
+
+       /* mixer matrix sources are physical input data and play streams */
+       chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams;
+       chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins;
+
+       /* mixer matrix destinations are record streams and physical output */
+       chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
+       chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
+
+       /* mixer matrix can have unused areas between PhysIn and
+        * Play or Record and PhysOut zones
+        */
+       chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
+               LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
+       chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
+               LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
+
+       /* example : MixerMatrix of LoLa881
+        * 0-------8------16-------8------16
+        * |       |       |       |       |
+        * | INPUT |       | INPUT |       |
+        * | ->    |unused | ->    |unused |
+        * | RECORD|       | OUTPUT|       |
+        * |       |       |       |       |
+        * 8--------------------------------
+        * |       |       |       |       |
+        * |       |       |       |       |
+        * |unused |unused |unused |unused |
+        * |       |       |       |       |
+        * |       |       |       |       |
+        * 16-------------------------------
+        * |       |       |       |       |
+        * | PLAY  |       | PLAY  |       |
+        * |  ->   |unused | ->    |unused |
+        * | RECORD|       | OUTPUT|       |
+        * |       |       |       |       |
+        * 8--------------------------------
+        * |       |       |       |       |
+        * |       |       |       |       |
+        * |unused |unused |unused |unused |
+        * |       |       |       |       |
+        * |       |       |       |       |
+        * 16-------------------------------
+        */
+       if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
+           chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
+               printk(KERN_ERR SFX "Invalid mixer widget size\n");
+               return -EINVAL;
+       }
+
+       chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) |
+               (((1U << chip->mixer.src_stream_outs) - 1)
+                << chip->mixer.src_stream_out_ofs);
+       chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) |
+               (((1U << chip->mixer.dest_phys_outs) - 1)
+                << chip->mixer.dest_phys_out_ofs);
+
+       return 0;
+}
+
+static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
+                                  unsigned short gain, bool on)
+{
+       unsigned int oldval, val;
+
+       if (!(chip->mixer.src_mask & (1 << id)))
+               return -EINVAL;
+       writew(gain, &chip->mixer.array->src_gain[id]);
+       oldval = val = readl(&chip->mixer.array->src_gain_enable);
+       if (on)
+               val |= (1 << id);
+       else
+               val &= ~(1 << id);
+       writel(val, &chip->mixer.array->src_gain_enable);
+       lola_codec_flush(chip);
+       /* inform micro-controller about the new source gain */
+       return lola_codec_write(chip, chip->mixer.nid,
+                               LOLA_VERB_SET_SOURCE_GAIN, id, 0);
+}
+
+#if 0 /* not used */
+static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask,
+                                   unsigned short *gains)
+{
+       int i;
+
+       if ((chip->mixer.src_mask & mask) != mask)
+               return -EINVAL;
+       for (i = 0; i < LOLA_MIXER_DIM; i++) {
+               if (mask & (1 << i)) {
+                       writew(*gains, &chip->mixer.array->src_gain[i]);
+                       gains++;
+               }
+       }
+       writel(mask, &chip->mixer.array->src_gain_enable);
+       lola_codec_flush(chip);
+       if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) {
+               /* update for all srcs at once */
+               return lola_codec_write(chip, chip->mixer.nid,
+                                       LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0);
+       }
+       /* update manually */
+       for (i = 0; i < LOLA_MIXER_DIM; i++) {
+               if (mask & (1 << i)) {
+                       lola_codec_write(chip, chip->mixer.nid,
+                                        LOLA_VERB_SET_SOURCE_GAIN, i, 0);
+               }
+       }
+       return 0;
+}
+#endif /* not used */
+
+static int lola_mixer_set_mapping_gain(struct lola *chip,
+                                      unsigned int src, unsigned int dest,
+                                      unsigned short gain, bool on)
+{
+       unsigned int val;
+
+       if (!(chip->mixer.src_mask & (1 << src)) ||
+           !(chip->mixer.dest_mask & (1 << dest)))
+               return -EINVAL;
+       if (on)
+               writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]);
+       val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]);
+       if (on)
+               val |= (1 << src);
+       else
+               val &= ~(1 << src);
+       writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]);
+       lola_codec_flush(chip);
+       return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN,
+                               src, dest);
+}
+
+static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
+                                    unsigned int mask, unsigned short *gains)
+{
+       int i;
+
+       if (!(chip->mixer.dest_mask & (1 << id)) ||
+           (chip->mixer.src_mask & mask) != mask)
+               return -EINVAL;
+       for (i = 0; i < LOLA_MIXER_DIM; i++) {
+               if (mask & (1 << i)) {
+                       writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]);
+                       gains++;
+               }
+       }
+       writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]);
+       lola_codec_flush(chip);
+       /* update for all dests at once */
+       return lola_codec_write(chip, chip->mixer.nid,
+                               LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+                            unsigned int idx, unsigned int val,
+                            bool external_call);
+
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute)
+{
+       struct lola_pin *pin;
+       int idx, max_idx;
+
+       pin = chip->pin[dir].pins;
+       max_idx = chip->pin[dir].num_pins;
+       for (idx = 0; idx < max_idx; idx++) {
+               if (pin[idx].is_analog) {
+                       unsigned int val = mute ? 0 : pin[idx].cur_gain_step;
+                       /* set volume and do not save the value */
+                       set_analog_volume(chip, dir, idx, val, false);
+               }
+       }
+       return lola_codec_flush(chip);
+}
+
+void lola_save_mixer(struct lola *chip)
+{
+       /* mute analog output */
+       if (chip->mixer.array_saved) {
+               /* store contents of mixer array */
+               memcpy_fromio(chip->mixer.array_saved, chip->mixer.array,
+                             sizeof(*chip->mixer.array));
+       }
+       lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */
+}
+
+void lola_restore_mixer(struct lola *chip)
+{
+       int i;
+
+       /*lola_reset_setups(chip);*/
+       if (chip->mixer.array_saved) {
+               /* restore contents of mixer array */
+               memcpy_toio(chip->mixer.array, chip->mixer.array_saved,
+                           sizeof(*chip->mixer.array));
+               /* inform micro-controller about all restored values
+                * and ignore return values
+                */
+               for (i = 0; i < chip->mixer.src_phys_ins; i++)
+                       lola_codec_write(chip, chip->mixer.nid,
+                                        LOLA_VERB_SET_SOURCE_GAIN,
+                                        i, 0);
+               for (i = 0; i < chip->mixer.src_stream_outs; i++)
+                       lola_codec_write(chip, chip->mixer.nid,
+                                        LOLA_VERB_SET_SOURCE_GAIN,
+                                        chip->mixer.src_stream_out_ofs + i, 0);
+               for (i = 0; i < chip->mixer.dest_stream_ins; i++)
+                       lola_codec_write(chip, chip->mixer.nid,
+                                        LOLA_VERB_SET_DESTINATION_GAIN,
+                                        i, 0);
+               for (i = 0; i < chip->mixer.dest_phys_outs; i++)
+                       lola_codec_write(chip, chip->mixer.nid,
+                                        LOLA_VERB_SET_DESTINATION_GAIN,
+                                        chip->mixer.dest_phys_out_ofs + i, 0);
+               lola_codec_flush(chip);
+       }
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+                            unsigned int idx, unsigned int val,
+                            bool external_call)
+{
+       struct lola_pin *pin;
+       int err;
+
+       if (idx >= chip->pin[dir].num_pins)
+               return -EINVAL;
+       pin = &chip->pin[dir].pins[idx];
+       if (!pin->is_analog || pin->amp_num_steps <= val)
+               return -EINVAL;
+       if (external_call && pin->cur_gain_step == val)
+               return 0;
+       if (external_call)
+               lola_codec_flush(chip);
+       err = lola_codec_write(chip, pin->nid,
+                              LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
+       if (err < 0)
+               return err;
+       if (external_call)
+               pin->cur_gain_step = val;
+       return 0;
+}
+
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update)
+{
+       int ret = 0;
+       int success = 0;
+       int n, err;
+
+       /* SRC can be activated and the dwInputSRCMask is valid? */
+       if ((chip->input_src_caps_mask & src_mask) != src_mask)
+               return -EINVAL;
+       /* handle all even Inputs - SRC is a stereo setting !!! */
+       for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) {
+               unsigned int mask = 3U << n; /* handle the stereo case */
+               unsigned int new_src, src_state;
+               if (!(chip->input_src_caps_mask & mask))
+                       continue;
+               /* if one IO needs SRC, both stereo IO will get SRC */
+               new_src = (src_mask & mask) != 0;
+               if (update) {
+                       src_state = (chip->input_src_mask & mask) != 0;
+                       if (src_state == new_src)
+                               continue;   /* nothing to change for this IO */
+               }
+               err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid,
+                                      LOLA_VERB_SET_SRC, new_src, 0);
+               if (!err)
+                       success++;
+               else
+                       ret = err;
+       }
+       if (success)
+               ret = lola_codec_flush(chip);
+       if (!ret)
+               chip->input_src_mask = src_mask;
+       return ret;
+}
+
+/*
+ */
+static int init_mixer_values(struct lola *chip)
+{
+       int i;
+
+       /* all src on */
+       lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
+
+       /* clear all matrix */
+       memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
+       /* set src gain to 0dB */
+       for (i = 0; i < chip->mixer.src_phys_ins; i++)
+               lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
+       for (i = 0; i < chip->mixer.src_stream_outs; i++)
+               lola_mixer_set_src_gain(chip,
+                                       i + chip->mixer.src_stream_out_ofs,
+                                       336, true); /* 0dB */
+       /* set 1:1 dest gain */
+       for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
+               int src = i % chip->mixer.src_phys_ins;
+               lola_mixer_set_mapping_gain(chip, src, i, 336, true);
+       }
+       for (i = 0; i < chip->mixer.src_stream_outs; i++) {
+               int src = chip->mixer.src_stream_out_ofs + i;
+               int dst = chip->mixer.dest_phys_out_ofs +
+                       i % chip->mixer.dest_phys_outs;
+               lola_mixer_set_mapping_gain(chip, src, dst, 336, true);
+       }
+       return 0;
+}
+
+/*
+ * analog mixer control element
+ */
+static int lola_analog_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int dir = kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chip->pin[dir].num_pins;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps;
+       return 0;
+}
+
+static int lola_analog_vol_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int dir = kcontrol->private_value;
+       int i;
+
+       for (i = 0; i < chip->pin[dir].num_pins; i++)
+               ucontrol->value.integer.value[i] =
+                       chip->pin[dir].pins[i].cur_gain_step;
+       return 0;
+}
+
+static int lola_analog_vol_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int dir = kcontrol->private_value;
+       int i, err;
+
+       for (i = 0; i < chip->pin[dir].num_pins; i++) {
+               err = set_analog_volume(chip, dir, i,
+                                       ucontrol->value.integer.value[i],
+                                       true);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                              unsigned int size, unsigned int __user *tlv)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int dir = kcontrol->private_value;
+       unsigned int val1, val2;
+       struct lola_pin *pin;
+
+       if (size < 4 * sizeof(unsigned int))
+               return -ENOMEM;
+       pin = &chip->pin[dir].pins[0];
+
+       val2 = pin->amp_step_size * 25;
+       val1 = -1 * (int)pin->amp_offset * (int)val2;
+#ifdef TLV_DB_SCALE_MUTE
+       val2 |= TLV_DB_SCALE_MUTE;
+#endif
+       if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv))
+               return -EFAULT;
+       if (put_user(2 * sizeof(unsigned int), tlv + 1))
+               return -EFAULT;
+       if (put_user(val1, tlv + 2))
+               return -EFAULT;
+       if (put_user(val2, tlv + 3))
+               return -EFAULT;
+       return 0;
+}
+
+static struct snd_kcontrol_new lola_analog_mixer __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
+       .info = lola_analog_vol_info,
+       .get = lola_analog_vol_get,
+       .put = lola_analog_vol_put,
+       .tlv.c = lola_analog_vol_tlv,
+};
+
+static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name)
+{
+       if (!chip->pin[dir].num_pins)
+               return 0;
+       /* no analog volumes on digital only adapters */
+       if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins)
+               return 0;
+       lola_analog_mixer.name = name;
+       lola_analog_mixer.private_value = dir;
+       return snd_ctl_add(chip->card,
+                          snd_ctl_new1(&lola_analog_mixer, chip));
+}
+
+/*
+ * Hardware sample rate converter on digital input
+ */
+static int lola_input_src_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = chip->pin[CAPT].num_pins;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int lola_input_src_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int i;
+
+       for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+               ucontrol->value.integer.value[i] =
+                       !!(chip->input_src_mask & (1 << i));
+       return 0;
+}
+
+static int lola_input_src_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       int i;
+       unsigned int mask;
+
+       mask = 0;
+       for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+               if (ucontrol->value.integer.value[i])
+                       mask |= 1 << i;
+       return lola_set_src_config(chip, mask, true);
+}
+
+static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = {
+       .name = "Digital SRC Capture Switch",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = lola_input_src_info,
+       .get = lola_input_src_get,
+       .put = lola_input_src_put,
+};
+
+/*
+ * Lola16161 or Lola881 can have Hardware sample rate converters
+ * on its digital input pins
+ */
+static int __devinit create_input_src_mixer(struct lola *chip)
+{
+       if (!chip->input_src_caps_mask)
+               return 0;
+
+       return snd_ctl_add(chip->card,
+                          snd_ctl_new1(&lola_input_src_mixer, chip));
+}
+
+/*
+ * src gain mixer
+ */
+static int lola_src_gain_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = count;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 409;
+       return 0;
+}
+
+static int lola_src_gain_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int ofs = kcontrol->private_value & 0xff;
+       unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+       unsigned int mask, i;
+
+       mask = readl(&chip->mixer.array->src_gain_enable);
+       for (i = 0; i < count; i++) {
+               unsigned int idx = ofs + i;
+               unsigned short val;
+               if (!(chip->mixer.src_mask & (1 << idx)))
+                       return -EINVAL;
+               if (mask & (1 << idx))
+                       val = readw(&chip->mixer.array->src_gain[idx]) + 1;
+               else
+                       val = 0;
+               ucontrol->value.integer.value[i] = val;
+       }
+       return 0;
+}
+
+static int lola_src_gain_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int ofs = kcontrol->private_value & 0xff;
+       unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+       int i, err;
+
+       for (i = 0; i < count; i++) {
+               unsigned int idx = ofs + i;
+               unsigned short val = ucontrol->value.integer.value[i];
+               if (val)
+                       val--;
+               err = lola_mixer_set_src_gain(chip, idx, val, !!val);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */
+static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .info = lola_src_gain_info,
+       .get = lola_src_gain_get,
+       .put = lola_src_gain_put,
+       .tlv.p = lola_src_gain_tlv,
+};
+
+static int __devinit create_src_gain_mixer(struct lola *chip,
+                                          int num, int ofs, char *name)
+{
+       lola_src_gain_mixer.name = name;
+       lola_src_gain_mixer.private_value = ofs + (num << 8);
+       return snd_ctl_add(chip->card,
+                          snd_ctl_new1(&lola_src_gain_mixer, chip));
+}
+
+/*
+ * destination gain (matrix-like) mixer
+ */
+static int lola_dest_gain_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = src_num;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 433;
+       return 0;
+}
+
+static int lola_dest_gain_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int src_ofs = kcontrol->private_value & 0xff;
+       unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+       unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+       unsigned int dst, mask, i;
+
+       dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+       mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]);
+       for (i = 0; i < src_num; i++) {
+               unsigned int src = src_ofs + i;
+               unsigned short val;
+               if (!(chip->mixer.src_mask & (1 << src)))
+                       return -EINVAL;
+               if (mask & (1 << dst))
+                       val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1;
+               else
+                       val = 0;
+               ucontrol->value.integer.value[i] = val;
+       }
+       return 0;
+}
+
+static int lola_dest_gain_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct lola *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int src_ofs = kcontrol->private_value & 0xff;
+       unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+       unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+       unsigned int dst, mask;
+       unsigned short gains[MAX_STREAM_COUNT];
+       int i, num;
+
+       mask = 0;
+       num = 0;
+       for (i = 0; i < src_num; i++) {
+               unsigned short val = ucontrol->value.integer.value[i];
+               if (val) {
+                       gains[num++] = val - 1;
+                       mask |= 1 << i;
+               }
+       }
+       mask <<= src_ofs;
+       dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+       return lola_mixer_set_dest_gains(chip, dst, mask, gains);
+}
+
+static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .info = lola_dest_gain_info,
+       .get = lola_dest_gain_get,
+       .put = lola_dest_gain_put,
+       .tlv.p = lola_dest_gain_tlv,
+};
+
+static int __devinit create_dest_gain_mixer(struct lola *chip,
+                                           int src_num, int src_ofs,
+                                           int num, int ofs, char *name)
+{
+       lola_dest_gain_mixer.count = num;
+       lola_dest_gain_mixer.name = name;
+       lola_dest_gain_mixer.private_value =
+               src_ofs + (src_num << 8) + (ofs << 16) + (num << 24);
+       return snd_ctl_add(chip->card,
+                         snd_ctl_new1(&lola_dest_gain_mixer, chip));
+}
+
+/*
+ */
+int __devinit lola_create_mixer(struct lola *chip)
+{
+       int err;
+
+       err = create_analog_mixer(chip, PLAY, "Analog Playback Volume");
+       if (err < 0)
+               return err;
+       err = create_analog_mixer(chip, CAPT, "Analog Capture Volume");
+       if (err < 0)
+               return err;
+       err = create_input_src_mixer(chip);
+       if (err < 0)
+               return err;
+       err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
+                                   "Line Source Gain Volume");
+       if (err < 0)
+               return err;
+       err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
+                                   chip->mixer.src_stream_out_ofs,
+                                   "Stream Source Gain Volume");
+       if (err < 0)
+               return err;
+       err = create_dest_gain_mixer(chip,
+                                    chip->mixer.src_phys_ins, 0,
+                                    chip->mixer.dest_stream_ins, 0,
+                                    "Line Capture Volume");
+       if (err < 0)
+               return err;
+       err = create_dest_gain_mixer(chip,
+                                    chip->mixer.src_stream_outs,
+                                    chip->mixer.src_stream_out_ofs,
+                                    chip->mixer.dest_stream_ins, 0,
+                                    "Stream-Loopback Capture Volume");
+       if (err < 0)
+               return err;
+       err = create_dest_gain_mixer(chip,
+                                    chip->mixer.src_phys_ins, 0,
+                                    chip->mixer.dest_phys_outs,
+                                    chip->mixer.dest_phys_out_ofs,
+                                    "Line-Loopback Playback Volume");
+       if (err < 0)
+               return err;
+       err = create_dest_gain_mixer(chip,
+                                    chip->mixer.src_stream_outs,
+                                    chip->mixer.src_stream_out_ofs,
+                                    chip->mixer.dest_phys_outs,
+                                    chip->mixer.dest_phys_out_ofs,
+                                    "Stream Playback Volume");
+       if (err < 0)
+               return err;
+
+       return init_mixer_values(chip);
+}
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
new file mode 100644 (file)
index 0000000..c44db68
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+#define LOLA_MAX_BDL_ENTRIES   8
+#define LOLA_MAX_BUF_SIZE      (1024*1024*1024)
+#define LOLA_BDL_ENTRY_SIZE    (16 * 16)
+
+static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       return &chip->pcm[substream->stream];
+}
+
+static struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream)
+{
+       struct lola_pcm *pcm = lola_get_pcm(substream);
+       unsigned int idx = substream->number;
+       return &pcm->streams[idx];
+}
+
+static unsigned int lola_get_lrc(struct lola *chip)
+{
+       return lola_readl(chip, BAR1, LRC);
+}
+
+static unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync)
+{
+       unsigned int tstamp = lola_get_lrc(chip) >> 8;
+       if (chip->granularity) {
+               unsigned int wait_banks = quick_no_sync ? 0 : 8;
+               tstamp += (wait_banks + 1) * chip->granularity - 1;
+               tstamp -= tstamp % chip->granularity;
+       }
+       return tstamp << 8;
+}
+
+/* clear any pending interrupt status */
+static void lola_stream_clear_pending_irq(struct lola *chip,
+                                         struct lola_stream *str)
+{
+       unsigned int val = lola_dsd_read(chip, str->dsd, STS);
+       val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS;
+       if (val)
+               lola_dsd_write(chip, str->dsd, STS, val);
+}
+
+static void lola_stream_start(struct lola *chip, struct lola_stream *str,
+                             unsigned int tstamp)
+{
+       lola_stream_clear_pending_irq(chip, str);
+       lola_dsd_write(chip, str->dsd, CTL,
+                      LOLA_DSD_CTL_SRUN |
+                      LOLA_DSD_CTL_IOCE |
+                      LOLA_DSD_CTL_DEIE |
+                      LOLA_DSD_CTL_VLRCV |
+                      tstamp);
+}
+
+static void lola_stream_stop(struct lola *chip, struct lola_stream *str,
+                            unsigned int tstamp)
+{
+       lola_dsd_write(chip, str->dsd, CTL,
+                      LOLA_DSD_CTL_IOCE |
+                      LOLA_DSD_CTL_DEIE |
+                      LOLA_DSD_CTL_VLRCV |
+                      tstamp);
+       lola_stream_clear_pending_irq(chip, str);
+}
+
+static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
+{
+       unsigned long end_time = jiffies + msecs_to_jiffies(200);
+       while (time_before(jiffies, end_time)) {
+               unsigned int val;
+               val = lola_dsd_read(chip, str->dsd, CTL);
+               if (!(val & LOLA_DSD_CTL_SRST))
+                       return;
+               msleep(1);
+       }
+       printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
+}
+
+static int lola_stream_wait_for_fifo(struct lola *chip,
+                                    struct lola_stream *str,
+                                    bool ready)
+{
+       unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+       unsigned long end_time = jiffies + msecs_to_jiffies(200);
+       while (time_before(jiffies, end_time)) {
+               unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
+               if ((reg & LOLA_DSD_STS_FIFORDY) == val)
+                       return 0;
+               msleep(1);
+       }
+       printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd);
+       return -EIO;
+}
+
+/* sync for FIFO ready/empty for all linked streams;
+ * clear paused flag when FIFO gets ready again
+ */
+static int lola_sync_wait_for_fifo(struct lola *chip,
+                                  struct snd_pcm_substream *substream,
+                                  bool ready)
+{
+       unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+       unsigned long end_time = jiffies + msecs_to_jiffies(200);
+       struct snd_pcm_substream *s;
+       int pending = 0;
+
+       while (time_before(jiffies, end_time)) {
+               pending = 0;
+               snd_pcm_group_for_each_entry(s, substream) {
+                       struct lola_stream *str;
+                       if (s->pcm->card != substream->pcm->card)
+                               continue;
+                       str = lola_get_stream(s);
+                       if (str->prepared && str->paused) {
+                               unsigned int reg;
+                               reg = lola_dsd_read(chip, str->dsd, STS);
+                               if ((reg & LOLA_DSD_STS_FIFORDY) != val) {
+                                       pending = str->dsd + 1;
+                                       break;
+                               }
+                               if (ready)
+                                       str->paused = 0;
+                       }
+               }
+               if (!pending)
+                       return 0;
+               msleep(1);
+       }
+       printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+       return -EIO;
+}
+
+/* finish pause - prepare for a new resume */
+static void lola_sync_pause(struct lola *chip,
+                           struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_substream *s;
+
+       lola_sync_wait_for_fifo(chip, substream, false);
+       snd_pcm_group_for_each_entry(s, substream) {
+               struct lola_stream *str;
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               str = lola_get_stream(s);
+               if (str->paused && str->prepared)
+                       lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN |
+                                      LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+       }
+       lola_sync_wait_for_fifo(chip, substream, true);
+}
+
+static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
+{
+       if (str->prepared) {
+               if (str->paused)
+                       lola_sync_pause(chip, str->substream);
+               str->prepared = 0;
+               lola_dsd_write(chip, str->dsd, CTL,
+                              LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+               lola_stream_wait_for_fifo(chip, str, false);
+               lola_stream_clear_pending_irq(chip, str);
+               lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
+               lola_dsd_write(chip, str->dsd, LVI, 0);
+               lola_dsd_write(chip, str->dsd, BDPU, 0);
+               lola_dsd_write(chip, str->dsd, BDPL, 0);
+               wait_for_srst_clear(chip, str);
+       }
+}
+
+static struct snd_pcm_hardware lola_pcm_hw = {
+       .info =                 (SNDRV_PCM_INFO_MMAP |
+                                SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_MMAP_VALID |
+                                SNDRV_PCM_INFO_PAUSE),
+       .formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+                                SNDRV_PCM_FMTBIT_S24_LE |
+                                SNDRV_PCM_FMTBIT_S32_LE |
+                                SNDRV_PCM_FMTBIT_FLOAT_LE),
+       .rates =                SNDRV_PCM_RATE_8000_192000,
+       .rate_min =             8000,
+       .rate_max =             192000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     LOLA_MAX_BUF_SIZE,
+       .period_bytes_min =     128,
+       .period_bytes_max =     LOLA_MAX_BUF_SIZE / 2,
+       .periods_min =          2,
+       .periods_max =          LOLA_MAX_BDL_ENTRIES,
+       .fifo_size =            0,
+};
+
+static int lola_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_pcm *pcm = lola_get_pcm(substream);
+       struct lola_stream *str = lola_get_stream(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       mutex_lock(&chip->open_mutex);
+       if (str->opened) {
+               mutex_unlock(&chip->open_mutex);
+               return -EBUSY;
+       }
+       str->substream = substream;
+       str->master = NULL;
+       str->opened = 1;
+       runtime->hw = lola_pcm_hw;
+       runtime->hw.channels_max = pcm->num_streams - str->index;
+       if (chip->sample_rate) {
+               /* sample rate is locked */
+               runtime->hw.rate_min = chip->sample_rate;
+               runtime->hw.rate_max = chip->sample_rate;
+       } else {
+               runtime->hw.rate_min = chip->sample_rate_min;
+               runtime->hw.rate_max = chip->sample_rate_max;
+       }
+       chip->ref_count_rate++;
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       /* period size = multiple of chip->granularity (8, 16 or 32 frames)*/
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                  chip->granularity);
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                  chip->granularity);
+       mutex_unlock(&chip->open_mutex);
+       return 0;
+}
+
+static void lola_cleanup_slave_streams(struct lola_pcm *pcm,
+                                      struct lola_stream *str)
+{
+       int i;
+       for (i = str->index + 1; i < pcm->num_streams; i++) {
+               struct lola_stream *s = &pcm->streams[i];
+               if (s->master != str)
+                       break;
+               s->master = NULL;
+               s->opened = 0;
+       }
+}
+
+static int lola_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_stream *str = lola_get_stream(substream);
+
+       mutex_lock(&chip->open_mutex);
+       if (str->substream == substream) {
+               str->substream = NULL;
+               str->opened = 0;
+       }
+       if (--chip->ref_count_rate == 0) {
+               /* release sample rate */
+               chip->sample_rate = 0;
+       }
+       mutex_unlock(&chip->open_mutex);
+       return 0;
+}
+
+static int lola_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *hw_params)
+{
+       struct lola_stream *str = lola_get_stream(substream);
+
+       str->bufsize = 0;
+       str->period_bytes = 0;
+       str->format_verb = 0;
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_pcm *pcm = lola_get_pcm(substream);
+       struct lola_stream *str = lola_get_stream(substream);
+
+       mutex_lock(&chip->open_mutex);
+       lola_stream_reset(chip, str);
+       lola_cleanup_slave_streams(pcm, str);
+       mutex_unlock(&chip->open_mutex);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct snd_pcm_substream *substream,
+                     struct lola_stream *str, u32 **bdlp,
+                     int ofs, int size)
+{
+       u32 *bdl = *bdlp;
+
+       while (size > 0) {
+               dma_addr_t addr;
+               int chunk;
+
+               if (str->frags >= LOLA_MAX_BDL_ENTRIES)
+                       return -EINVAL;
+
+               addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+               /* program the address field of the BDL entry */
+               bdl[0] = cpu_to_le32((u32)addr);
+               bdl[1] = cpu_to_le32(upper_32_bits(addr));
+               /* program the size field of the BDL entry */
+               chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+               bdl[2] = cpu_to_le32(chunk);
+               /* program the IOC to enable interrupt
+                * only when the whole fragment is processed
+                */
+               size -= chunk;
+               bdl[3] = size ? 0 : cpu_to_le32(0x01);
+               bdl += 4;
+               str->frags++;
+               ofs += chunk;
+       }
+       *bdlp = bdl;
+       return ofs;
+}
+
+/*
+ * set up BDL entries
+ */
+static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
+                             struct snd_pcm_substream *substream,
+                             struct lola_stream *str)
+{
+       u32 *bdl;
+       int i, ofs, periods, period_bytes;
+
+       period_bytes = str->period_bytes;
+       periods = str->bufsize / period_bytes;
+
+       /* program the initial BDL entries */
+       bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
+       ofs = 0;
+       str->frags = 0;
+       for (i = 0; i < periods; i++) {
+               ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes);
+               if (ofs < 0)
+                       goto error;
+       }
+       return 0;
+
+ error:
+       snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
+                  str->bufsize, period_bytes);
+       return -EINVAL;
+}
+
+static unsigned int lola_get_format_verb(struct snd_pcm_substream *substream)
+{
+       unsigned int verb;
+
+       switch (substream->runtime->format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               verb = 0x00000000;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               verb = 0x00000200;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               verb = 0x00000300;
+               break;
+       case SNDRV_PCM_FORMAT_FLOAT_LE:
+               verb = 0x00001300;
+               break;
+       default:
+               return 0;
+       }
+       verb |= substream->runtime->channels;
+       return verb;
+}
+
+static int lola_set_stream_config(struct lola *chip,
+                                 struct lola_stream *str,
+                                 int channels)
+{
+       int i, err;
+       unsigned int verb, val;
+
+       /* set format info for all channels
+        * (with only one command for the first channel)
+        */
+       err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
+                             str->format_verb, 0, &val, NULL);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Cannot set stream format 0x%x\n",
+                      str->format_verb);
+               return err;
+       }
+
+       /* update stream - channel config */
+       for (i = 0; i < channels; i++) {
+               verb = (str->index << 6) | i;
+               err = lola_codec_read(chip, str[i].nid,
+                                     LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
+                                     &val, NULL);
+               if (err < 0) {
+                       printk(KERN_ERR SFX "Cannot set stream channel %d\n", i);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
+                                struct lola_stream *str)
+{
+       dma_addr_t bdl;
+
+       if (str->prepared)
+               return -EINVAL;
+
+       /* set up BDL */
+       bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
+       lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl);
+       lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
+       /* program the stream LVI (last valid index) of the BDL */
+       lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
+       lola_stream_clear_pending_irq(chip, str);
+
+       lola_dsd_write(chip, str->dsd, CTL,
+                      LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN);
+
+       str->prepared = 1;
+
+       return lola_stream_wait_for_fifo(chip, str, true);
+}
+
+static int lola_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_pcm *pcm = lola_get_pcm(substream);
+       struct lola_stream *str = lola_get_stream(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int bufsize, period_bytes, format_verb;
+       int i, err;
+
+       mutex_lock(&chip->open_mutex);
+       lola_stream_reset(chip, str);
+       lola_cleanup_slave_streams(pcm, str);
+       if (str->index + runtime->channels > pcm->num_streams) {
+               mutex_unlock(&chip->open_mutex);
+               return -EINVAL;
+       }
+       for (i = 1; i < runtime->channels; i++) {
+               str[i].master = str;
+               str[i].opened = 1;
+       }
+       mutex_unlock(&chip->open_mutex);
+
+       bufsize = snd_pcm_lib_buffer_bytes(substream);
+       period_bytes = snd_pcm_lib_period_bytes(substream);
+       format_verb = lola_get_format_verb(substream);
+
+       str->bufsize = bufsize;
+       str->period_bytes = period_bytes;
+       str->format_verb = format_verb;
+
+       err = lola_setup_periods(chip, pcm, substream, str);
+       if (err < 0)
+               return err;
+
+       err = lola_set_sample_rate(chip, runtime->rate);
+       if (err < 0)
+               return err;
+       chip->sample_rate = runtime->rate;      /* sample rate gets locked */
+
+       err = lola_set_stream_config(chip, str, runtime->channels);
+       if (err < 0)
+               return err;
+
+       err = lola_setup_controller(chip, pcm, str);
+       if (err < 0) {
+               lola_stream_reset(chip, str);
+               return err;
+       }
+
+       return 0;
+}
+
+static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_stream *str;
+       struct snd_pcm_substream *s;
+       unsigned int start;
+       unsigned int tstamp;
+       bool sync_streams;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               start = 1;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               start = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * sample correct synchronization is only needed starting several
+        * streams. On stop or if only one stream do as quick as possible
+        */
+       sync_streams = (start && snd_pcm_stream_linked(substream));
+       tstamp = lola_get_tstamp(chip, !sync_streams);
+       spin_lock(&chip->reg_lock);
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               str = lola_get_stream(s);
+               if (start)
+                       lola_stream_start(chip, str, tstamp);
+               else
+                       lola_stream_stop(chip, str, tstamp);
+               str->running = start;
+               str->paused = !start;
+               snd_pcm_trigger_done(s, substream);
+       }
+       spin_unlock(&chip->reg_lock);
+       return 0;
+}
+
+static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct lola *chip = snd_pcm_substream_chip(substream);
+       struct lola_stream *str = lola_get_stream(substream);
+       unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB);
+
+       if (pos >= str->bufsize)
+               pos = 0;
+       return bytes_to_frames(substream->runtime, pos);
+}
+
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits)
+{
+       int i;
+
+       for (i = 0; bits && i < pcm->num_streams; i++) {
+               if (bits & (1 << i)) {
+                       struct lola_stream *str = &pcm->streams[i];
+                       if (str->substream && str->running)
+                               snd_pcm_period_elapsed(str->substream);
+                       bits &= ~(1 << i);
+               }
+       }
+}
+
+static struct snd_pcm_ops lola_pcm_ops = {
+       .open = lola_pcm_open,
+       .close = lola_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = lola_pcm_hw_params,
+       .hw_free = lola_pcm_hw_free,
+       .prepare = lola_pcm_prepare,
+       .trigger = lola_pcm_trigger,
+       .pointer = lola_pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+
+int __devinit lola_create_pcm(struct lola *chip)
+{
+       struct snd_pcm *pcm;
+       int i, err;
+
+       for (i = 0; i < 2; i++) {
+               err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                         snd_dma_pci_data(chip->pci),
+                                         PAGE_SIZE, &chip->pcm[i].bdl);
+               if (err < 0)
+                       return err;
+       }
+
+       err = snd_pcm_new(chip->card, "Digigram Lola", 0,
+                         chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
+                         chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
+                         &pcm);
+       if (err < 0)
+               return err;
+       strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
+       pcm->private_data = chip;
+       for (i = 0; i < 2; i++) {
+               if (chip->pcm[i].num_streams)
+                       snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
+       }
+       /* buffer pre-allocation */
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             snd_dma_pci_data(chip->pci),
+                                             1024 * 64, 32 * 1024 * 1024);
+       return 0;
+}
+
+void lola_free_pcm(struct lola *chip)
+{
+       snd_dma_free_pages(&chip->pcm[0].bdl);
+       snd_dma_free_pages(&chip->pcm[1].bdl);
+}
+
+/*
+ */
+
+static int lola_init_stream(struct lola *chip, struct lola_stream *str,
+                           int idx, int nid, int dir)
+{
+       unsigned int val;
+       int err;
+
+       str->nid = nid;
+       str->index = idx;
+       str->dsd = idx;
+       if (dir == PLAY)
+               str->dsd += MAX_STREAM_IN_COUNT;
+       err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               return err;
+       }
+       if (dir == PLAY) {
+               /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
+               if ((val & 0x00f00dff) != 0x00000010) {
+                       printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+                              val, nid);
+                       return -EINVAL;
+               }
+       } else {
+               /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1)
+                * (bug : ignore bit8: Conn list = 0/1)
+                */
+               if ((val & 0x00f00cff) != 0x00100010) {
+                       printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+                              val, nid);
+                       return -EINVAL;
+               }
+               /* test bit9:DIGITAL and bit12:SRC_PRESENT*/
+               if ((val & 0x00001200) == 0x00001200)
+                       chip->input_src_caps_mask |= (1 << idx);
+       }
+
+       err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+       if (err < 0) {
+               printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid);
+               return err;
+       }
+       val &= 3;
+       if (val == 3)
+               str->can_float = true;
+       if (!(val & 1)) {
+               printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp)
+{
+       struct lola_pcm *pcm = &chip->pcm[dir];
+       int i, nid, err;
+
+       nid = *nidp;
+       for (i = 0; i < pcm->num_streams; i++, nid++) {
+               err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir);
+               if (err < 0)
+                       return err;
+       }
+       *nidp = nid;
+       return 0;
+}
diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c
new file mode 100644 (file)
index 0000000..9d7daf8
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+static void print_audio_widget(struct snd_info_buffer *buffer,
+                              struct lola *chip, int nid, const char *name)
+{
+       unsigned int val;
+
+       lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+       lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+       snd_iprintf(buffer, "  Formats: 0x%x\n", val);
+}
+
+static void print_pin_widget(struct snd_info_buffer *buffer,
+                            struct lola *chip, int nid, unsigned int ampcap,
+                            const char *name)
+{
+       unsigned int val;
+
+       lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+       if (val == 0x00400200)
+               return;
+       lola_read_param(chip, nid, ampcap, &val);
+       snd_iprintf(buffer, "  Amp-Caps: 0x%x\n", val);
+       snd_iprintf(buffer, "    mute=%d, step-size=%d, steps=%d, ofs=%d\n",
+                   LOLA_AMP_MUTE_CAPABLE(val),
+                   LOLA_AMP_STEP_SIZE(val),
+                   LOLA_AMP_NUM_STEPS(val),
+                   LOLA_AMP_OFFSET(val));
+       lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL);
+       snd_iprintf(buffer, "  Max-level: 0x%x\n", val);
+}
+
+static void print_clock_widget(struct snd_info_buffer *buffer,
+                              struct lola *chip, int nid)
+{
+       int i, j, num_clocks;
+       unsigned int val;
+
+       lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val);
+       num_clocks = val & 0xff;
+       for (i = 0; i < num_clocks; i += 4) {
+               unsigned int res_ex;
+               unsigned short items[4];
+               const char *name;
+
+               lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+                               i, 0, &val, &res_ex);
+               items[0] = val & 0xfff;
+               items[1] = (val >> 16) & 0xfff;
+               items[2] = res_ex & 0xfff;
+               items[3] = (res_ex >> 16) & 0xfff;
+               for (j = 0; j < 4; j++) {
+                       unsigned char type = items[j] >> 8;
+                       unsigned int freq = items[j] & 0xff;
+                       if (i + j >= num_clocks)
+                               break;
+                       if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+                               name = "Internal";
+                               freq = lola_sample_rate_convert(freq);
+                       } else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+                               name = "Video";
+                               freq = lola_sample_rate_convert(freq);
+                       } else {
+                               name = "Other";
+                       }
+                       snd_iprintf(buffer, "  Clock %d: Type %d:%s, freq=%d\n",
+                                   i + j, type, name, freq);
+               }
+       }
+}
+
+static void print_mixer_widget(struct snd_info_buffer *buffer,
+                              struct lola *chip, int nid)
+{
+       unsigned int val;
+
+       lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+       snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val);
+}
+
+static void lola_proc_codec_read(struct snd_info_entry *entry,
+                                struct snd_info_buffer *buffer)
+{
+       struct lola *chip = entry->private_data;
+       unsigned int val;
+       int i, nid;
+
+       lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+       snd_iprintf(buffer, "Vendor: 0x%08x\n", val);
+       lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+       snd_iprintf(buffer, "Function Type: %d\n", val);
+       lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+       snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val);
+       snd_iprintf(buffer, "  Pins-In %d, Pins-Out %d\n",
+                   chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+       nid = 2;
+       for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++)
+               print_audio_widget(buffer, chip, nid, "[Audio-In]");
+       for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++)
+               print_audio_widget(buffer, chip, nid, "[Audio-Out]");
+       for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++)
+               print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP,
+                                "[Pin-In]");
+       for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++)
+               print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP,
+                                "[Pin-Out]");
+       if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+               print_clock_widget(buffer, chip, nid);
+               nid++;
+       }
+       if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+               print_mixer_widget(buffer, chip, nid);
+               nid++;
+       }
+}
+
+/* direct codec access for debugging */
+static void lola_proc_codec_rw_write(struct snd_info_entry *entry,
+                                    struct snd_info_buffer *buffer)
+{
+       struct lola *chip = entry->private_data;
+       char line[64];
+       unsigned int id, verb, data, extdata;
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4)
+                       continue;
+               lola_codec_read(chip, id, verb, data, extdata,
+                               &chip->debug_res,
+                               &chip->debug_res_ex);
+       }
+}
+
+static void lola_proc_codec_rw_read(struct snd_info_entry *entry,
+                                   struct snd_info_buffer *buffer)
+{
+       struct lola *chip = entry->private_data;
+       snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex);
+}
+
+/*
+ * dump some registers
+ */
+static void lola_proc_regs_read(struct snd_info_entry *entry,
+                               struct snd_info_buffer *buffer)
+{
+       struct lola *chip = entry->private_data;
+       int i;
+
+       for (i = 0; i < 0x40; i += 4) {
+               snd_iprintf(buffer, "BAR0 %02x: %08x\n", i,
+                           readl(chip->bar[BAR0].remap_addr + i));
+       }
+       snd_iprintf(buffer, "\n");
+       for (i = 0; i < 0x30; i += 4) {
+               snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+                           readl(chip->bar[BAR1].remap_addr + i));
+       }
+       snd_iprintf(buffer, "\n");
+       for (i = 0x80; i < 0xa0; i += 4) {
+               snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+                           readl(chip->bar[BAR1].remap_addr + i));
+       }
+       snd_iprintf(buffer, "\n");
+       for (i = 0; i < 32; i++) {
+               snd_iprintf(buffer, "DSD %02x STS  %08x\n", i,
+                           lola_dsd_read(chip, i, STS));
+               snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i,
+                           lola_dsd_read(chip, i, LPIB));
+               snd_iprintf(buffer, "DSD %02x CTL  %08x\n", i,
+                           lola_dsd_read(chip, i, CTL));
+               snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i,
+                           lola_dsd_read(chip, i, LVI));
+               snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i,
+                           lola_dsd_read(chip, i, BDPL));
+               snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i,
+                           lola_dsd_read(chip, i, BDPU));
+       }
+}
+
+void __devinit lola_proc_debug_new(struct lola *chip)
+{
+       struct snd_info_entry *entry;
+
+       if (!snd_card_proc_new(chip->card, "codec", &entry))
+               snd_info_set_text_ops(entry, chip, lola_proc_codec_read);
+       if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) {
+               snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read);
+               entry->mode |= S_IWUSR;
+               entry->c.text.write = lola_proc_codec_rw_write;
+       }
+       if (!snd_card_proc_new(chip->card, "regs", &entry))
+               snd_info_set_text_ops(entry, chip, lola_proc_regs_read);
+}
index 961d982976958aaaf0c4dae4906210ad3df0bfb4..9cea84c3e0c65e8d557618a4f82ecc2aa97d06db 100644 (file)
@@ -1000,7 +1000,7 @@ static void device_change_handler(struct work_struct *work)
                                   chip->lineout_sw_ctl);
                if (mix->anded_reset)
                        msleep(10);
-               check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+               check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify,
                           chip->speaker_sw_ctl);
        } else {
                /* unmute speaker, mute others */
index af3c73053ee4f55f58a2e35888761e71396f2e6d..28afbbf69ce00d30c76754eb6f8bb0c5adea519e 100644 (file)
@@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .codec_dai_name = "wm8731-hifi",
        .init = at91sam9g20ek_wm8731_init,
        .platform_name = "atmel-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .ops = &at91sam9g20ek_ops,
 };
 
index cb99f04abe88aaed8d42dc90e264c0137a5276a0..1d3e258c9ea8ec861cf19c88a9bd7c99e5384940 100644 (file)
@@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
        .codec_dai_name = "wm8731-hifi",
        .cpu_dai_name   = "au1xpsc_i2s.1",
        .platform_name  = "au1xpsc-pcm.1",
-       .codec_name     = "wm8731-codec.0-001b",
+       .codec_name     = "wm8731.0-001b",
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
index 5a2fd8abaefaee65e5509e4c98adf252c06293df..98b44b316e786de9abe6a8c1b05c5dd3d9e644b4 100644 (file)
@@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        int ret;
 
@@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
        size_t size = bf5xx_pcm_hardware.buffer_bytes_max
@@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        struct snd_dma_buffer *buf;
        int stream;
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
                sizeof(struct ac97_frame) / 4;
 #endif
@@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 #endif
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bf5xx_pcm_driver = {
        .driver = {
-                       .name = "bf5xx-pcm-audio",
+                       .name = "bfin-ac97-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index ffbac26b9bce5882e662e3dfc1a7a26081cbf91d..6d216259088935633c598bb72d0ce516fc31df96 100644 (file)
  *             anomaly does not affect blackfin sound drivers.
 */
 
-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] = {
-#ifdef SPORT0_TCR1
-       SPORT_REQ(0),
-#endif
-#ifdef SPORT1_TCR1
-       SPORT_REQ(1),
-#endif
-#ifdef SPORT2_TCR1
-       SPORT_REQ(2),
-#endif
-#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] = {
-#ifdef SPORT0_TCR1
-       SPORT_PARAMS(0),
-#endif
-#ifdef SPORT1_TCR1
-       SPORT_PARAMS(1),
-#endif
-#ifdef SPORT2_TCR1
-       SPORT_PARAMS(2),
-#endif
-#ifdef SPORT3_TCR1
-       SPORT_PARAMS(3),
-#endif
-};
+static struct sport_device *ac97_sport_handle;
 
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
                size_t count, unsigned int chan_mask)
@@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 {
-       struct sport_device *sport = sport_handle;
+       struct sport_device *sport = ac97_sport_handle;
+       int *cmd_count = sport->private_data;
        int nextfrag = sport_tx_curr_frag(sport);
        struct ac97_frame *nextwrite;
 
@@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
        unsigned short reg)
 {
+       struct sport_device *sport_handle = ac97_sport_handle;
        struct ac97_frame out_frame[2], in_frame[2];
 
        pr_debug("%s enter 0x%x\n", __func__, reg);
@@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        unsigned short val)
 {
+       struct sport_device *sport_handle = ac97_sport_handle;
+
        pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 
        if (sport_handle->tx_run) {
@@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
- (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
-
-#define CONCAT(a, b, c) a ## b ## c
-#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
-
-       u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
-       u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+       struct sport_device *sport_handle = ac97_sport_handle;
+       u16 gpio = P_IDENT(sport_handle->pin_req[3]);
 
        pr_debug("%s enter\n", __func__);
 
-       peripheral_free(per);
+       peripheral_free_list(sport_handle->pin_req);
        gpio_request(gpio, "bf5xx-ac97");
        gpio_direction_output(gpio, 1);
        udelay(2);
        gpio_set_value(gpio, 0);
        udelay(1);
        gpio_free(gpio);
-       peripheral_request(per, "soc-audio");
-#else
-       pr_info("%s: Not implemented\n", __func__);
-#endif
+       peripheral_request_list(sport_handle->pin_req, "soc-audio");
 }
 
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
@@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume      NULL
 #endif
 
-static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
+static struct snd_soc_dai_driver bfin_ac97_dai = {
+       .ac97_control = 1,
+       .suspend = bf5xx_ac97_suspend,
+       .resume = bf5xx_ac97_resume,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+               .channels_max = 6,
+#else
+               .channels_max = 2,
+#endif
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-       cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
-       if (cmd_count == NULL)
-               return -ENOMEM;
-
-       if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               ret =  -EFAULT;
-               goto peripheral_err;
-       }
+       struct sport_device *sport_handle;
+       int ret;
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        /* Request PB3 as reset pin */
@@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
        }
        gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
-       sport_handle = sport_init(&sport_params[sport_num], 2, \
-                       sizeof(struct ac97_frame), NULL);
+
+       sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
+               PAGE_SIZE);
        if (!sport_handle) {
                ret = -ENODEV;
                goto sport_err;
        }
+
        /*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
        ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
@@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
                goto sport_config_err;
        }
 
+       ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+       if (ret) {
+               pr_err("Failed to register DAI: %d\n", ret);
+               goto sport_config_err;
+       }
+
+       ac97_sport_handle = sport_handle;
+
        return 0;
 
 sport_config_err:
-       kfree(sport_handle);
+       sport_done(sport_handle);
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 gpio_err:
 #endif
-       peripheral_free_list(sport_req[sport_num]);
-peripheral_err:
-       free_page((unsigned long)cmd_count);
-       cmd_count = NULL;
 
        return ret;
 }
 
-static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
-       free_page((unsigned long)cmd_count);
-       cmd_count = NULL;
-       peripheral_free_list(sport_req[sport_num]);
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
-       return 0;
-}
-
-struct snd_soc_dai_driver bfin_ac97_dai = {
-       .ac97_control = 1,
-       .probe = bf5xx_ac97_probe,
-       .remove = bf5xx_ac97_remove,
-       .suspend = bf5xx_ac97_suspend,
-       .resume = bf5xx_ac97_resume,
-       .playback = {
-               .stream_name = "AC97 Playback",
-               .channels_min = 2,
-#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-               .channels_max = 6,
-#else
-               .channels_max = 2,
-#endif
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
-       .capture = {
-               .stream_name = "AC97 Capture",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
-};
-EXPORT_SYMBOL_GPL(bfin_ac97_dai);
-
-static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
-}
 
-static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
index 83012da9dfc24969c14d01de5ccd1e0bc047cbd7..ea4951cf5526d5871af7441430d583d81fd3749c 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad1836.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad1836;
 
-static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad1836_ops = {
-       .startup = bf5xx_ad1836_startup,
        .hw_params = bf5xx_ad1836_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai = {
-       .name = "ad1836",
-       .stream_name = "AD1836",
-       .cpu_dai_name = "bf5xx-tdm",
-       .codec_dai_name = "ad1836-hifi",
-       .platform_name = "bf5xx-tdm-pcm-audio",
-       .codec_name = "ad1836-codec.0",
-       .ops = &bf5xx_ad1836_ops,
+static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
+       {
+               .name = "ad1836",
+               .stream_name = "AD1836",
+               .cpu_dai_name = "bfin-tdm.0",
+               .codec_dai_name = "ad1836-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad1836.0",
+               .ops = &bf5xx_ad1836_ops,
+       },
+       {
+               .name = "ad1836",
+               .stream_name = "AD1836",
+               .cpu_dai_name = "bfin-tdm.1",
+               .codec_dai_name = "ad1836-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad1836.0",
+               .ops = &bf5xx_ad1836_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
-       .name = "bf5xx_ad1836",
-       .dai_link = &bf5xx_ad1836_dai,
+       .name = "bfin-ad1836",
+       .dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index d3ccb926b5e43c9004a6bf6e35e2606bdfa28629..d6651c033cb711a35c69dcde2320c213e50a5f5b 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad193x.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad193x;
 
-static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int clk = 0;
        unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
        int ret = 0;
+
+       switch (params_rate(params)) {
+       case 48000:
+               clk = 12288000;
+               break;
+       }
+
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
                SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
@@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
        /* set codec DAI slots, 8 channels, all channels are enabled */
        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
        if (ret < 0)
@@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad193x_ops = {
-       .startup = bf5xx_ad193x_startup,
        .hw_params = bf5xx_ad193x_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad193x_dai = {
-       .name = "ad193x",
-       .stream_name = "AD193X",
-       .cpu_dai_name = "bf5xx-tdm",
-       .codec_dai_name ="ad193x-hifi",
-       .platform_name = "bf5xx-tdm-pcm-audio",
-       .codec_name = "ad193x-codec.5",
-       .ops = &bf5xx_ad193x_ops,
+static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
+       {
+               .name = "ad193x",
+               .stream_name = "AD193X",
+               .cpu_dai_name = "bfin-tdm.0",
+               .codec_dai_name ="ad193x-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad193x.5",
+               .ops = &bf5xx_ad193x_ops,
+       },
+       {
+               .name = "ad193x",
+               .stream_name = "AD193X",
+               .cpu_dai_name = "bfin-tdm.1",
+               .codec_dai_name ="ad193x-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad193x.5",
+               .ops = &bf5xx_ad193x_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
-       .name = "bf5xx_ad193x",
-       .dai_link = &bf5xx_ad193x_dai,
+       .name = "bfin-ad193x",
+       .dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index d57c9c9c9883207039174b71cdfa490b64109dfa..06a84b211b52bcdcb08783ae9623e9ab2ecb9f35 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad1980.h"
-#include "bf5xx-sport.h"
+
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
 static struct snd_soc_card bf5xx_board;
 
-static int bf5xx_board_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
-static struct snd_soc_ops bf5xx_board_ops = {
-       .startup = bf5xx_board_startup,
-};
-
-static struct snd_soc_dai_link bf5xx_board_dai = {
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "bfin-ac97",
-       .codec_dai_name = "ad1980-hifi",
-       .platform_name = "bfin-pcm-audio",
-       .codec_name = "ad1980-codec",
-       .ops = &bf5xx_board_ops,
+static struct snd_soc_dai_link bf5xx_board_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai_name = "bfin-ac97.0",
+               .codec_dai_name = "ad1980-hifi",
+               .platform_name = "bfin-ac97-pcm-audio",
+               .codec_name = "ad1980",
+       },
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai_name = "bfin-ac97.1",
+               .codec_dai_name = "ad1980-hifi",
+               .platform_name = "bfin-ac97-pcm-audio",
+               .codec_name = "ad1980",
+       },
 };
 
 static struct snd_soc_card bf5xx_board = {
-       .name = "bf5xx-board",
-       .dai_link = &bf5xx_board_dai,
+       .name = "bfin-ad1980",
+       .dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 732fb8bad076b6785b5a7572ef34652aa4ba465f..732a247f25278cf7b2356e12d52d773a73cb7548 100644 (file)
@@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 
 
 static struct snd_soc_ops bf5xx_ad73311_ops = {
-       .startup = bf5xx_ad73311_startup,
        .hw_params = bf5xx_ad73311_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad73311_dai = {
-       .name = "ad73311",
-       .stream_name = "AD73311",
-       .cpu_dai_name = "bf5xx-i2s",
-       .codec_dai_name = "ad73311-hifi",
-       .platform_name = "bfin-pcm-audio",
-       .codec_name = "ad73311-codec",
-       .ops = &bf5xx_ad73311_ops,
+static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
+       {
+               .name = "ad73311",
+               .stream_name = "AD73311",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "ad73311-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ad73311",
+               .ops = &bf5xx_ad73311_ops,
+       },
+       {
+               .name = "ad73311",
+               .stream_name = "AD73311",
+               .cpu_dai_name = "bfin-i2s.1",
+               .codec_dai_name = "ad73311-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ad73311",
+               .ops = &bf5xx_ad73311_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
-       .name = "bf5xx_ad73311",
+       .name = "bfin-ad73311",
        .probe = bf5xx_probe,
-       .dai_link = &bf5xx_ad73311_dai,
+       .dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 890a0dccf902a4fc14922cd11565406df86ec0b7..b5101efd1c8733bd002cf5ae700f5807b665ebed 100644 (file)
@@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
        int ret;
 
        pr_debug("%s enter\n", __func__);
+
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
        ret = snd_pcm_hw_constraint_integer(runtime, \
@@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        if (ret < 0)
                goto out;
 
-       if (sport_handle != NULL)
+       if (sport_handle != NULL) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_handle->tx_buf = buf->area;
+               else
+                       sport_handle->rx_buf = buf->area;
+
                runtime->private_data = sport_handle;
-       else {
+       else {
                pr_err("sport_handle is NULL\n");
                return -1;
        }
@@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
                buf->area, buf->bytes);
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               sport_handle->tx_buf = buf->area;
-       else
-               sport_handle->rx_buf = buf->area;
-
        return 0;
 }
 
@@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
                dma_free_coherent(NULL, buf->bytes, buf->area, 0);
                buf->area = NULL;
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_i2s_pcm_driver = {
        .driver = {
-                       .name = "bfin-pcm-audio",
+                       .name = "bfin-i2s-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index d453b1e9d607d0d0e9d712bf981a3e6dda4ae17f..00cc3e00b2fead767ca60cbc54e603b3521f960a 100644 (file)
@@ -51,59 +51,24 @@ struct bf5xx_i2s_port {
        int configured;
 };
 
-static struct bf5xx_i2s_port bf5xx_i2s;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       }
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-               P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-               {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-               P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret = 0;
 
        /* interface format:support I2S,slave mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               bf5xx_i2s.tcr1 |= TFSR | TCKFE;
-               bf5xx_i2s.rcr1 |= RFSR | RCKFE;
-               bf5xx_i2s.tcr2 |= TSFSE;
-               bf5xx_i2s.rcr2 |= RSFSE;
+               bf5xx_i2s->tcr1 |= TFSR | TCKFE;
+               bf5xx_i2s->rcr1 |= RFSR | RCKFE;
+               bf5xx_i2s->tcr2 |= TSFSE;
+               bf5xx_i2s->rcr2 |= RSFSE;
                break;
        case SND_SOC_DAIFMT_DSP_A:
-               bf5xx_i2s.tcr1 |= TFSR;
-               bf5xx_i2s.rcr1 |= RFSR;
+               bf5xx_i2s->tcr1 |= TFSR;
+               bf5xx_i2s->rcr1 |= RFSR;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
                ret = -EINVAL;
@@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret = 0;
 
-       bf5xx_i2s.tcr2 &= ~0x1f;
-       bf5xx_i2s.rcr2 &= ~0x1f;
+       bf5xx_i2s->tcr2 &= ~0x1f;
+       bf5xx_i2s->rcr2 &= ~0x1f;
        switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               bf5xx_i2s->tcr2 |= 7;
+               bf5xx_i2s->rcr2 |= 7;
+               sport_handle->wdsize = 1;
        case SNDRV_PCM_FORMAT_S16_LE:
-               bf5xx_i2s.tcr2 |= 15;
-               bf5xx_i2s.rcr2 |= 15;
+               bf5xx_i2s->tcr2 |= 15;
+               bf5xx_i2s->rcr2 |= 15;
                sport_handle->wdsize = 2;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               bf5xx_i2s.tcr2 |= 23;
-               bf5xx_i2s.rcr2 |= 23;
+               bf5xx_i2s->tcr2 |= 23;
+               bf5xx_i2s->rcr2 |= 23;
                sport_handle->wdsize = 3;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_i2s.tcr2 |= 31;
-               bf5xx_i2s.rcr2 |= 31;
+               bf5xx_i2s->tcr2 |= 31;
+               bf5xx_i2s->rcr2 |= 31;
                sport_handle->wdsize = 4;
                break;
        }
 
-       if (!bf5xx_i2s.configured) {
+       if (!bf5xx_i2s->configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
-               bf5xx_i2s.configured = 1;
-               ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-                                     bf5xx_i2s.rcr2, 0, 0);
+               bf5xx_i2s->configured = 1;
+               ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+                                     bf5xx_i2s->rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-                                     bf5xx_i2s.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+                                     bf5xx_i2s->tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
        pr_debug("%s enter\n", __func__);
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
-               bf5xx_i2s.configured = 0;
-}
-
-static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
-{
-       pr_debug("%s enter\n", __func__);
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
-       }
-
-       /* request DMA for SPORT */
-       sport_handle = sport_init(&sport_params[sport_num], 4, \
-                       2 * sizeof(u32), NULL);
-       if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
-{
-       pr_debug("%s enter\n", __func__);
-       peripheral_free_list(&sport_req[sport_num][0]);
-       return 0;
+               bf5xx_i2s->configured = 0;
 }
 
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret;
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
-       ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-                                     bf5xx_i2s.rcr2, 0, 0);
+       ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+                                     bf5xx_i2s->rcr2, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                return -EBUSY;
        }
 
-       ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-                                     bf5xx_i2s.tcr2, 0, 0);
+       ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+                                     bf5xx_i2s->tcr2, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                return -EBUSY;
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
                SNDRV_PCM_RATE_96000)
 
-#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
-       SNDRV_PCM_FMTBIT_S32_LE)
+#define BF5XX_I2S_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 bf5xx_i2s_dai_ops = {
        .shutdown       = bf5xx_i2s_shutdown,
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
-       .probe = bf5xx_i2s_probe,
-       .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .ops = &bf5xx_i2s_dai_ops,
 };
 
-static int bfin_i2s_drv_probe(struct platform_device *pdev)
+static int __devinit bf5xx_i2s_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       struct sport_device *sport_handle;
+       int ret;
+
+       /* configure SPORT for I2S */
+       sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+               sizeof(struct bf5xx_i2s_port));
+       if (!sport_handle)
+               return -ENODEV;
+
+       /* register with the ASoC layers */
+       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       if (ret) {
+               pr_err("Failed to register DAI: %d\n", ret);
+               sport_done(sport_handle);
+               return ret;
+       }
+
+       return 0;
 }
 
-static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+static int __devexit bf5xx_i2s_remove(struct platform_device *pdev)
 {
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+       pr_debug("%s enter\n", __func__);
+
        snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
+
        return 0;
 }
 
 static struct platform_driver bfin_i2s_driver = {
-       .probe = bfin_i2s_drv_probe,
-       .remove = __devexit_p(bfin_i2s_drv_remove),
-
+       .probe  = bf5xx_i2s_probe,
+       .remove = __devexit_p(bf5xx_i2s_remove),
        .driver = {
-               .name = "bf5xx-i2s",
+               .name = "bfin-i2s",
                .owner = THIS_MODULE,
        },
 };
index 99051ff0954e6ffe6772d0ee4957ee53e4d3ebc4..a2d40349fcc4113e7892ceb61401af2a140f9e07 100644 (file)
@@ -42,8 +42,6 @@
 /* delay between frame sync pulse and first data bit in multichannel mode */
 #define FRAME_DELAY (1<<12)
 
-struct sport_device *sport_handle;
-EXPORT_SYMBOL(sport_handle);
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
@@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport,
 }
 EXPORT_SYMBOL(sport_set_err_callback);
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-               unsigned dummy_count, void *private_data)
+static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
 {
-       int ret;
+       /* Extract settings from platform data */
+       struct device *dev = &pdev->dev;
+       struct bfin_snd_platform_data *pdata = dev->platform_data;
+       struct resource *res;
+
+       param->num = pdev->id;
+
+       if (!pdata) {
+               dev_err(dev, "no platform_data\n");
+               return -ENODEV;
+       }
+       param->pin_req = pdata->pin_req;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no MEM resource\n");
+               return -ENODEV;
+       }
+       param->regs = (struct sport_register *)res->start;
+
+       /* first RX, then TX */
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(dev, "no rx DMA resource\n");
+               return -ENODEV;
+       }
+       param->dma_rx_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(dev, "no tx DMA resource\n");
+               return -ENODEV;
+       }
+       param->dma_tx_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev, "no irq resource\n");
+               return -ENODEV;
+       }
+       param->err_irq = res->start;
+
+       return 0;
+}
+
+struct sport_device *sport_init(struct platform_device *pdev,
+       unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
+{
+       struct device *dev = &pdev->dev;
+       struct sport_param param;
        struct sport_device *sport;
-       pr_debug("%s enter\n", __func__);
-       BUG_ON(param == NULL);
-       BUG_ON(wdsize == 0 || dummy_count == 0);
-       sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
-       if (!sport) {
-               pr_err("Failed to allocate for sport device\n");
+       int ret;
+
+       dev_dbg(dev, "%s enter\n", __func__);
+
+       param.wdsize = wdsize;
+       param.dummy_count = dummy_count;
+       BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+
+       ret = sport_config_pdev(pdev, &param);
+       if (ret)
+               return NULL;
+
+       if (peripheral_request_list(param.pin_req, "soc-audio")) {
+               dev_err(dev, "requesting Peripherals failed\n");
                return NULL;
        }
 
-       memset(sport, 0, sizeof(struct sport_device));
-       sport->dma_rx_chan = param->dma_rx_chan;
-       sport->dma_tx_chan = param->dma_tx_chan;
-       sport->err_irq = param->err_irq;
-       sport->regs = param->regs;
-       sport->private_data = private_data;
+       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+       if (!sport) {
+               dev_err(dev, "failed to allocate for sport device\n");
+               goto __init_err0;
+       }
+
+       sport->num = param.num;
+       sport->dma_rx_chan = param.dma_rx_chan;
+       sport->dma_tx_chan = param.dma_tx_chan;
+       sport->err_irq = param.err_irq;
+       sport->regs = param.regs;
+       sport->pin_req = param.pin_req;
 
        if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
-               pr_err("Failed to request RX dma %d\n", \
-                               sport->dma_rx_chan);
+               dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
                goto __init_err1;
        }
        if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
-               pr_err("Failed to request RX irq %d\n", \
-                               sport->dma_rx_chan);
+               dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
                goto __init_err2;
        }
 
        if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
-               pr_err("Failed to request TX dma %d\n", \
-                               sport->dma_tx_chan);
+               dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
                goto __init_err2;
        }
 
        if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
-               pr_err("Failed to request TX irq %d\n", \
-                               sport->dma_tx_chan);
+               dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
                goto __init_err3;
        }
 
        if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
                        sport) < 0) {
-               pr_err("Failed to request err irq:%d\n", \
-                               sport->err_irq);
+               dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
                goto __init_err3;
        }
 
-       pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+       dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
                        sport->dma_rx_chan, sport->dma_tx_chan,
                        sport->err_irq, sport->regs);
 
-       sport->wdsize = wdsize;
-       sport->dummy_count = dummy_count;
+       sport->wdsize = param.wdsize;
+       sport->dummy_count = param.dummy_count;
+
+       sport->private_data = kzalloc(priv_size, GFP_KERNEL);
+       if (!sport->private_data) {
+               dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
+               goto __init_err4;
+       }
 
        if (L1_DATA_A_LENGTH)
-               sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+               sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
        else
-               sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
+               sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
        if (sport->dummy_buf == NULL) {
-               pr_err("Failed to allocate dummy buffer\n");
-               goto __error;
+               dev_err(dev, "failed to allocate dummy buffer\n");
+               goto __error1;
        }
 
        ret = sport_config_rx_dummy(sport);
        if (ret) {
-               pr_err("Failed to config rx dummy ring\n");
-               goto __error;
+               dev_err(dev, "failed to config rx dummy ring\n");
+               goto __error2;
        }
        ret = sport_config_tx_dummy(sport);
        if (ret) {
-               pr_err("Failed to config tx dummy ring\n");
-               goto __error;
+               dev_err(dev, "failed to config tx dummy ring\n");
+               goto __error3;
        }
 
+       platform_set_drvdata(pdev, sport);
+
        return sport;
-__error:
+__error3:
+       if (L1_DATA_A_LENGTH)
+               l1_data_sram_free(sport->dummy_rx_desc);
+       else
+               dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+                               sport->dummy_rx_desc, 0);
+__error2:
+       if (L1_DATA_A_LENGTH)
+               l1_data_sram_free(sport->dummy_buf);
+       else
+               kfree(sport->dummy_buf);
+__error1:
+       kfree(sport->private_data);
+__init_err4:
        free_irq(sport->err_irq, sport);
 __init_err3:
        free_dma(sport->dma_tx_chan);
@@ -885,6 +961,8 @@ __init_err2:
        free_dma(sport->dma_rx_chan);
 __init_err1:
        kfree(sport);
+__init_err0:
+       peripheral_free_list(param.pin_req);
        return NULL;
 }
 EXPORT_SYMBOL(sport_init);
@@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport)
        free_dma(sport->dma_tx_chan);
        free_irq(sport->err_irq, sport);
 
+       kfree(sport->private_data);
+       peripheral_free_list(sport->pin_req);
        kfree(sport);
-               sport = NULL;
 }
 EXPORT_SYMBOL(sport_done);
 
index a86e8cc0b2d30ab45b36e7ab489e8cbc7d7e8f2f..5ab60bd613ea314cfc73b3219f07282b8945f8f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * File:         bf5xx_ac97_sport.h
+ * File:         bf5xx_sport.h
  * Based on:
  * Author:       Roy Huang <roy.huang@analog.com>
  *
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 #include <asm/dma.h>
 #include <asm/bfin_sport.h>
 
 #define DESC_ELEMENT_COUNT 9
 
 struct sport_device {
+       int num;
        int dma_rx_chan;
        int dma_tx_chan;
        int err_irq;
+       const unsigned short *pin_req;
        struct sport_register *regs;
 
        unsigned char *rx_buf;
@@ -103,17 +106,20 @@ struct sport_device {
        void *private_data;
 };
 
-extern struct sport_device *sport_handle;
-
 struct sport_param {
+       int num;
        int dma_rx_chan;
        int dma_tx_chan;
        int err_irq;
+       const unsigned short *pin_req;
        struct sport_register *regs;
+       unsigned int wdsize;
+       unsigned int dummy_count;
+       void *private_data;
 };
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-               unsigned dummy_count, void *private_data);
+struct sport_device *sport_init(struct platform_device *pdev,
+       unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
 
 void sport_done(struct sport_device *sport);
 
index ad28663f5bbdf3fe2ee53dacc57cd5ca46cfdb7a..767e772a815de3b7b1bc2a6550df126b9525bda1 100644 (file)
 
 static struct snd_soc_card bf5xx_ssm2602;
 
-static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
-       .startup = bf5xx_ssm2602_startup,
        .hw_params = bf5xx_ssm2602_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
-       .name = "ssm2602",
-       .stream_name = "SSM2602",
-       .cpu_dai_name = "bf5xx-i2s",
-       .codec_dai_name = "ssm2602-hifi",
-       .platform_name = "bf5xx-pcm-audio",
-       .codec_name = "ssm2602-codec.0-001b",
-       .ops = &bf5xx_ssm2602_ops,
+static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
+       {
+               .name = "ssm2602",
+               .stream_name = "SSM2602",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "ssm2602-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ssm2602.0-001b",
+               .ops = &bf5xx_ssm2602_ops,
+       },
+       {
+               .name = "ssm2602",
+               .stream_name = "SSM2602",
+               .cpu_dai_name = "bfin-i2s.1",
+               .codec_dai_name = "ssm2602-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ssm2602.0-001b",
+               .ops = &bf5xx_ssm2602_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ssm2602 = {
-       .name = "bf5xx_ssm2602",
-       .dai_link = &bf5xx_ssm2602_dai,
+       .name = "bfin-ssm2602",
+       .dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 74cf759b78a6ceac0fa2210e25f540e191ed1e08..07cfc7a9e49acc1d44f63876b17f102230ab4703 100644 (file)
@@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+
        int ret = 0;
 
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
@@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        if (ret < 0)
                goto out;
 
-       if (sport_handle != NULL)
+       if (sport_handle != NULL) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_handle->tx_buf = buf->area;
+               else
+                       sport_handle->rx_buf = buf->area;
+
                runtime->private_data = sport_handle;
-       else {
+       else {
                pr_err("sport_handle is NULL\n");
                ret = -ENODEV;
        }
@@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        }
        buf->bytes = size;
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               sport_handle->tx_buf = buf->area;
-       else
-               sport_handle->rx_buf = buf->area;
-
        return 0;
 }
 
@@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
                dma_free_coherent(NULL, buf->bytes, buf->area, 0);
                buf->area = NULL;
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_tdm_driver = {
        .driver = {
-                       .name = "bf5xx-tdm-pcm-audio",
+                       .name = "bfin-tdm-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index 5515ac9e05c70bca470a3f2fe913747cb95fe16f..a822d1ee1380057db79148c265785e933616d1b2 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       }
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-       P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-          {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-                  P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        unsigned int fmt)
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int ret = 0;
 
-       bf5xx_tdm.tcr2 &= ~0x1f;
-       bf5xx_tdm.rcr2 &= ~0x1f;
+       bf5xx_tdm->tcr2 &= ~0x1f;
+       bf5xx_tdm->rcr2 &= ~0x1f;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_tdm.tcr2 |= 31;
-               bf5xx_tdm.rcr2 |= 31;
+               bf5xx_tdm->tcr2 |= 31;
+               bf5xx_tdm->rcr2 |= 31;
                sport_handle->wdsize = 4;
                break;
                /* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       if (!bf5xx_tdm.configured) {
+       if (!bf5xx_tdm->configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
-               ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-                       bf5xx_tdm.rcr2, 0, 0);
+               ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+                       bf5xx_tdm->rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-                       bf5xx_tdm.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+                       bf5xx_tdm->tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               bf5xx_tdm.configured = 1;
+               bf5xx_tdm->configured = 1;
        }
 
        return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
-               bf5xx_tdm.configured = 0;
+               bf5xx_tdm->configured = 0;
 }
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                unsigned int tx_num, unsigned int *tx_slot,
                unsigned int rx_num, unsigned int *rx_slot)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int i;
        unsigned int slot;
        unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = tx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(tx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.tx_map[i] = slot;
+                       bf5xx_tdm->tx_map[i] = slot;
                        tx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = rx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(rx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.rx_map[i] = slot;
+                       bf5xx_tdm->rx_map[i] = slot;
                        rx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-       if (dai->capture_active)
-               sport_rx_stop(sport);
        if (dai->playback_active)
                sport_tx_stop(sport);
+       if (dai->capture_active)
+               sport_rx_stop(sport);
+
+       /* isolate sync/clock pins from codec while sports resume */
+       peripheral_free_list(sport->pin_req);
+
        return 0;
 }
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
        int ret;
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-
        ret = sport_set_multichannel(sport, 8, 0xFF, 1);
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
                ret = -EBUSY;
        }
 
+       peripheral_request_list(sport->pin_req, "soc-audio");
+
        return 0;
 }
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
-       }
+       struct sport_device *sport_handle;
+       int ret;
 
-       /* request DMA for SPORT */
-       sport_handle = sport_init(&sport_params[sport_num], 4, \
-               8 * sizeof(u32), NULL);
-       if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
+       /* configure SPORT for TDM */
+       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+               sizeof(struct bf5xx_tdm_port));
+       if (!sport_handle)
                return -ENODEV;
-       }
 
        /* SPORT works in TDM mode */
        ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       sport_handle->private_data = &bf5xx_tdm;
        return 0;
 
 sport_config_err:
-       peripheral_free_list(&sport_req[sport_num][0]);
+       sport_done(sport_handle);
        return ret;
 }
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
-       peripheral_free_list(&sport_req[sport_num][0]);
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
        snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
 
        return 0;
 }
index 06b6981b8d6d6e87aa8519113d936946412246e4..19241576b6b590a9982b457fe405d0e245c7aca7 100644 (file)
  */
 #define PM860X_DAPM_OUTPUT(wname, wevent)      \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-       .shift = 0, .invert = 0, .kcontrols = NULL, \
+       .shift = 0, .invert = 0, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 
index 6943e24a74a16b0adb4dd6f2ef7c0ef3a23293ee..98175a096df2496da11822e6772d4f92420ca3bb 100644 (file)
@@ -16,10 +16,11 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD1836 if SPI_MASTER
        select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+       select SND_SOC_AD73311
        select SND_SOC_ADS117X
-       select SND_SOC_AD73311 if I2C
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
+       select SND_SOC_AK4641 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
        select SND_SOC_ALC5623 if I2C
@@ -33,13 +34,14 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_JZ4740_CODEC if SOC_JZ4740
        select SND_SOC_LM4857 if I2C
        select SND_SOC_MAX98088 if I2C
+       select SND_SOC_MAX98095 if I2C
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
        select SND_SOC_SGTL5000 if I2C
        select SND_SOC_SN95031 if INTEL_SCU_IPC
        select SND_SOC_SPDIF
-       select SND_SOC_SSM2602 if I2C
+       select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -52,6 +54,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
        select SND_SOC_WL1273 if MFD_WL1273_CORE
+       select SND_SOC_WM1250_EV1 if I2C
        select SND_SOC_WM2000 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
        select SND_SOC_WM8400 if MFD_WM8400
@@ -72,6 +75,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
+       select SND_SOC_WM8915 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
@@ -136,6 +140,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
        tristate
 
+config SND_SOC_AK4641
+       tristate
+
 config SND_SOC_AK4642
        tristate
 
@@ -187,6 +194,9 @@ config SND_SOC_DMIC
 config SND_SOC_MAX98088
        tristate
 
+config SND_SOC_MAX98095
+       tristate
+
 config SND_SOC_MAX9850
        tristate
 
@@ -241,6 +251,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WL1273
        tristate
 
+config SND_SOC_WM1250_EV1
+       tristate
+
 config SND_SOC_WM8350
        tristate
 
@@ -298,6 +311,9 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
        tristate
 
+config SND_SOC_WM8915
+       tristate
+
 config SND_SOC_WM8940
         tristate
 
index 379bc55f072385150fb7abb5808920f47842de2f..fd8558406ef002a71aea9a2521d60f6fdcd3c730 100644 (file)
@@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
@@ -19,6 +20,7 @@ snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-l3-objs := l3.o
 snd-soc-max98088-objs := max98088.o
+snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -37,6 +39,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -56,6 +59,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
+snd-soc-wm8915-objs := wm8915.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
@@ -69,7 +73,7 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
@@ -94,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4641)   += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
@@ -108,6 +113,7 @@ obj-$(CONFIG_SND_SOC_DMIC)  += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
@@ -125,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)       += snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.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
@@ -144,6 +151,7 @@ obj-$(CONFIG_SND_SOC_WM8804)        += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
+obj-$(CONFIG_SND_SOC_WM8915)   += snd-soc-wm8915.o
 obj-$(CONFIG_SND_SOC_WM8940)   += snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)   += snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
index da46479bfcfaf00f36b77bab83ab13ebe230139b..2374ca5ffe68bacc6c37db16be249858fb17fad2 100644 (file)
@@ -23,8 +23,7 @@
 
 /* codec private data */
 struct ad193x_priv {
-       enum snd_soc_control_type bus_type;
-       void *control_data;
+       enum snd_soc_control_type control_type;
        int sysclk;
 };
 
@@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       codec->control_data = ad193x->control_data;
-       if (ad193x->bus_type == SND_SOC_I2C)
-               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+       if (ad193x->control_type == SND_SOC_I2C)
+               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
        else
-               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
+               dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
@@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        spi_set_drvdata(spi, ad193x);
-       ad193x->control_data = spi;
-       ad193x->bus_type = SND_SOC_SPI;
+       ad193x->control_type = SND_SOC_SPI;
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
 static struct spi_driver ad193x_spi_driver = {
        .driver = {
-               .name   = "ad193x-codec",
+               .name   = "ad193x",
                .owner  = THIS_MODULE,
        },
        .probe          = ad193x_spi_probe,
@@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        i2c_set_clientdata(client, ad193x);
-       ad193x->control_data = client;
-       ad193x->bus_type = SND_SOC_I2C;
+       ad193x->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
 static struct i2c_driver ad193x_i2c_driver = {
        .driver = {
-               .name = "ad193x-codec",
+               .name = "ad193x",
        },
        .probe    = ad193x_i2c_probe,
        .remove   = __devexit_p(ad193x_i2c_remove),
index 34cb51ef2156645dc7e1ae46d877b26f3f32f8e0..923b364a3e41926e88c99025c11326ab49236773 100644 (file)
@@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev)
 
 static struct platform_driver ad1980_codec_driver = {
        .driver = {
-                       .name = "ad1980-codec",
+                       .name = "ad1980",
                        .owner = THIS_MODULE,
        },
 
index de799cd1ba727e7b1fa45cad05f5e7aa9d0d80d3..8d793e993e9a8a7110d2601141649a72072baee6 100644 (file)
@@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev)
 
 static struct platform_driver ad73311_codec_driver = {
        .driver = {
-                       .name = "ad73311-codec",
+                       .name = "ad73311",
                        .owner = THIS_MODULE,
        },
 
index 8b38739c88f8901b00b2aa3484523744d89918bb..e1a214ee757ffaa2621572ebb084fb0033bd621c 100644 (file)
@@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("AIN"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
        /*stereo mixer */
        {"Stereo Mixer", "Playback Switch", "DAC"},
        {"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
@@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Input Mixer", "Aux Capture Switch", "Aux In"},
 };
 
-static int ak4535_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
-                                 ARRAY_SIZE(ak4535_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        int clk_id, unsigned int freq, int dir)
 {
@@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ak4535_snd_controls,
                                ARRAY_SIZE(ak4535_snd_controls));
-       ak4535_add_widgets(codec);
-
        return 0;
 }
 
@@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
        .reg_cache_size = ARRAY_SIZE(ak4535_reg),
        .reg_word_size = sizeof(u8),
        .reg_cache_default = ak4535_reg,
+       .dapm_widgets = ak4535_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
+       .dapm_routes = ak4535_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
new file mode 100644 (file)
index 0000000..ed96f24
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ * ak4641.c  --  AK4641 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org>
+ * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * Based on ak4535.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/ak4641.h>
+
+#include "ak4641.h"
+
+/* codec private data */
+struct ak4641_priv {
+       struct snd_soc_codec *codec;
+       unsigned int sysclk;
+       int deemph;
+       int playback_fs;
+};
+
+/*
+ * ak4641 register cache
+ */
+static const u8 ak4641_reg[AK4641_CACHEREGNUM] = {
+       0x00, 0x80, 0x00, 0x80,
+       0x02, 0x00, 0x11, 0x05,
+       0x00, 0x00, 0x36, 0x10,
+       0x00, 0x00, 0x57, 0x00,
+       0x88, 0x88, 0x08, 0x08
+};
+
+static const int deemph_settings[] = {44100, 0, 48000, 32000};
+
+static int ak4641_set_deemph(struct snd_soc_codec *codec)
+{
+       struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+       int i, best = 0;
+
+       for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
+               /* if deemphasis is on, select the nearest available rate */
+               if (ak4641->deemph && deemph_settings[i] != 0 &&
+                   abs(deemph_settings[i] - ak4641->playback_fs) <
+                   abs(deemph_settings[best] - ak4641->playback_fs))
+                       best = i;
+
+               if (!ak4641->deemph && deemph_settings[i] == 0)
+                       best = i;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d\n", best);
+
+       return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best);
+}
+
+static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+       int deemph = ucontrol->value.enumerated.item[0];
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       ak4641->deemph = deemph;
+
+       return ak4641_set_deemph(codec);
+}
+
+static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = ak4641->deemph;
+       return 0;
+};
+
+static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4641_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4641_mic_select[] = {"Internal", "External"};
+static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"};
+
+
+static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
+
+
+static const struct soc_enum ak4641_mono_out_enum =
+       SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out);
+static const struct soc_enum ak4641_hp_out_enum =
+       SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out);
+static const struct soc_enum ak4641_mic_select_enum =
+       SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select);
+static const struct soc_enum ak4641_mic_or_dac_enum =
+       SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac);
+
+static const struct snd_kcontrol_new ak4641_snd_controls[] = {
+       SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
+       SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1,
+                                                       mono_gain_tlv),
+       SOC_ENUM("Headphone Output", ak4641_hp_out_enum),
+       SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+                                       ak4641_get_deemph, ak4641_put_deemph),
+
+       SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv),
+
+       SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0),
+       SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0),
+       SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0),
+
+       SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0),
+
+       SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv),
+       SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0),
+       SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0),
+
+       SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv),
+
+       SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT,
+                               AK4641_RATT, 0, 255, 1, master_tlv),
+
+       SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv),
+
+       SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0),
+       SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv),
+       SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv),
+       SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv),
+       SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv),
+       SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv),
+};
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = {
+       SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0,
+                                               mic_mono_sidetone_tlv),
+       SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0),
+       SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = {
+       SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0,
+                                               mic_stereo_sidetone_tlv),
+       SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0),
+       SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0),
+       SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0),
+};
+
+/* Mic mux */
+static const struct snd_kcontrol_new ak4641_mic_mux_control =
+       SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum);
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4641_input_mux_control =
+       SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4641_mono2_control =
+       SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0);
+
+/* ak4641 dapm widgets */
+static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4641_stereo_mixer_controls[0],
+               ARRAY_SIZE(ak4641_stereo_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4641_mono1_mixer_controls[0],
+               ARRAY_SIZE(ak4641_mono1_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4641_input_mixer_controls[0],
+               ARRAY_SIZE(ak4641_input_mixer_controls)),
+       SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
+               &ak4641_mic_mux_control),
+       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+               &ak4641_input_mux_control),
+       SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+               &ak4641_mono2_control),
+
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+       SND_SOC_DAPM_OUTPUT("MOUT1"),
+       SND_SOC_DAPM_OUTPUT("MOUT2"),
+       SND_SOC_DAPM_OUTPUT("MICOUT"),
+
+       SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0),
+       SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0),
+
+       SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0),
+       SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
+
+       SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
+       SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
+
+       SND_SOC_DAPM_INPUT("MICIN"),
+       SND_SOC_DAPM_INPUT("MICEXT"),
+       SND_SOC_DAPM_INPUT("AUX"),
+       SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route ak4641_audio_map[] = {
+       /* Stereo Mixer */
+       {"Stereo Mixer", "Playback Switch", "DAC"},
+       {"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"},
+       {"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+       /* Mono 1 Mixer */
+       {"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"},
+       {"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+       /* Mic */
+       {"Mic", NULL, "AIN"},
+       {"Mic Mux", "Internal", "Mic Int Bias"},
+       {"Mic Mux", "External", "Mic Ext Bias"},
+       {"Mic Int Bias", NULL, "MICIN"},
+       {"Mic Ext Bias", NULL, "MICEXT"},
+       {"MICOUT", NULL, "Mic Mux"},
+
+       /* Input Mux */
+       {"Input Mux", "Microphone", "Mic"},
+       {"Input Mux", "Voice DAC", "Voice DAC"},
+
+       /* Line Out */
+       {"LOUT", NULL, "Line Out"},
+       {"ROUT", NULL, "Line Out"},
+       {"Line Out", NULL, "Stereo Mixer"},
+
+       /* Mono 1 Out */
+       {"MOUT1", NULL, "Mono Out"},
+       {"Mono Out", NULL, "Mono1 Mixer"},
+
+       /* Mono 2 Out */
+       {"MOUT2", NULL, "Mono 2 Enable"},
+       {"Mono 2 Enable", "Switch", "Mono Out 2"},
+       {"Mono Out 2", NULL, "Stereo Mixer"},
+
+       {"Voice ADC", NULL, "Mono 2 Enable"},
+
+       /* Aux In */
+       {"AUX In", NULL, "AUX"},
+
+       /* ADC */
+       {"ADC", NULL, "Input Mixer"},
+       {"Input Mixer", "Mic Capture Switch", "Mic"},
+       {"Input Mixer", "Aux Capture Switch", "AUX In"},
+};
+
+static int ak4641_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 ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+       ak4641->sysclk = freq;
+       return 0;
+}
+
+static int ak4641_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;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+       int rate = params_rate(params), fs = 256;
+       u8 mode2;
+
+       if (rate)
+               fs = ak4641->sysclk / rate;
+       else
+               return -EINVAL;
+
+       /* set fs */
+       switch (fs) {
+       case 1024:
+               mode2 = (0x2 << 5);
+               break;
+       case 512:
+               mode2 = (0x1 << 5);
+               break;
+       case 256:
+               mode2 = (0x0 << 5);
+               break;
+       default:
+               dev_err(codec->dev, "Error: unsupported fs=%d\n", fs);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2);
+
+       /* Update de-emphasis filter for the new rate */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ak4641->playback_fs = rate;
+               ak4641_set_deemph(codec);
+       };
+
+       return 0;
+}
+
+static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                 unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 btif;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               btif = (0x3 << 5);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               btif = (0x2 << 5);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:      /* MSB after FRM */
+               btif = (0x0 << 5);
+               break;
+       case SND_SOC_DAIFMT_DSP_B:      /* MSB during FRM */
+               btif = (0x1 << 5);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+}
+
+static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 mode1 = 0;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               mode1 = 0x02;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               mode1 = 0x01;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_write(codec, AK4641_MODE1, mode1);
+}
+
+static int ak4641_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
+}
+
+static int ak4641_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       struct ak4641_platform_data *pdata = codec->dev->platform_data;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* unmute */
+               snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               /* mute */
+               snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       if (pdata && gpio_is_valid(pdata->gpio_power))
+                               gpio_set_value(pdata->gpio_power, 1);
+                       mdelay(1);
+                       if (pdata && gpio_is_valid(pdata->gpio_npdn))
+                               gpio_set_value(pdata->gpio_npdn, 1);
+                       mdelay(1);
+
+                       ret = snd_soc_cache_sync(codec);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+               }
+               snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80);
+               snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0);
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0);
+               if (pdata && gpio_is_valid(pdata->gpio_npdn))
+                       gpio_set_value(pdata->gpio_npdn, 0);
+               if (pdata && gpio_is_valid(pdata->gpio_power))
+                       gpio_set_value(pdata->gpio_power, 0);
+               codec->cache_sync = 1;
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define AK4641_RATES   (SNDRV_PCM_RATE_8000_48000)
+#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+                        SNDRV_PCM_RATE_16000)
+#define AK4641_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
+       .hw_params    = ak4641_i2s_hw_params,
+       .set_fmt      = ak4641_i2s_set_dai_fmt,
+       .digital_mute = ak4641_mute,
+       .set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
+       .hw_params    = NULL, /* rates are controlled by BT chip */
+       .set_fmt      = ak4641_pcm_set_dai_fmt,
+       .digital_mute = ak4641_mute,
+       .set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+struct snd_soc_dai_driver ak4641_dai[] = {
+{
+       .name = "ak4641-hifi",
+       .id = 1,
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4641_RATES,
+               .formats = AK4641_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4641_RATES,
+               .formats = AK4641_FORMATS,
+       },
+       .ops = &ak4641_i2s_dai_ops,
+       .symmetric_rates = 1,
+},
+{
+       .name = "ak4641-voice",
+       .id = 1,
+       .playback = {
+               .stream_name = "Voice Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = AK4641_RATES_BT,
+               .formats = AK4641_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Voice Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = AK4641_RATES_BT,
+               .formats = AK4641_FORMATS,
+       },
+       .ops = &ak4641_pcm_dai_ops,
+       .symmetric_rates = 1,
+},
+};
+
+static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int ak4641_resume(struct snd_soc_codec *codec)
+{
+       ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+
+static int ak4641_probe(struct snd_soc_codec *codec)
+{
+       struct ak4641_platform_data *pdata = codec->dev->platform_data;
+       int ret;
+
+
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power)) {
+                       ret = gpio_request_one(pdata->gpio_power,
+                                       GPIOF_OUT_INIT_LOW, "ak4641 power");
+                       if (ret)
+                               goto err_out;
+               }
+               if (gpio_is_valid(pdata->gpio_npdn)) {
+                       ret = gpio_request_one(pdata->gpio_npdn,
+                                       GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+                       if (ret)
+                               goto err_gpio;
+
+                       udelay(1); /* > 150 ns */
+                       gpio_set_value(pdata->gpio_npdn, 1);
+               }
+       }
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err_register;
+       }
+
+       /* power on device */
+       ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+
+err_register:
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power))
+                       gpio_set_value(pdata->gpio_power, 0);
+               if (gpio_is_valid(pdata->gpio_npdn))
+                       gpio_free(pdata->gpio_npdn);
+       }
+err_gpio:
+       if (pdata && gpio_is_valid(pdata->gpio_power))
+               gpio_free(pdata->gpio_power);
+err_out:
+       return ret;
+}
+
+static int ak4641_remove(struct snd_soc_codec *codec)
+{
+       struct ak4641_platform_data *pdata = codec->dev->platform_data;
+
+       ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power)) {
+                       gpio_set_value(pdata->gpio_power, 0);
+                       gpio_free(pdata->gpio_power);
+               }
+               if (gpio_is_valid(pdata->gpio_npdn))
+                       gpio_free(pdata->gpio_npdn);
+       }
+       return 0;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
+       .probe                  = ak4641_probe,
+       .remove                 = ak4641_remove,
+       .suspend                = ak4641_suspend,
+       .resume                 = ak4641_resume,
+       .controls               = ak4641_snd_controls,
+       .num_controls           = ARRAY_SIZE(ak4641_snd_controls),
+       .dapm_widgets           = ak4641_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(ak4641_dapm_widgets),
+       .dapm_routes            = ak4641_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(ak4641_audio_map),
+       .set_bias_level         = ak4641_set_bias_level,
+       .reg_cache_size         = ARRAY_SIZE(ak4641_reg),
+       .reg_word_size          = sizeof(u8),
+       .reg_cache_default      = ak4641_reg,
+       .reg_cache_step         = 1,
+};
+
+
+static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct ak4641_priv *ak4641;
+       int ret;
+
+       ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL);
+       if (!ak4641)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, ak4641);
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
+                               ak4641_dai, ARRAY_SIZE(ak4641_dai));
+       if (ret < 0)
+               kfree(ak4641);
+
+       return ret;
+}
+
+static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
+       return 0;
+}
+
+static const struct i2c_device_id ak4641_i2c_id[] = {
+       { "ak4641", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
+
+static struct i2c_driver ak4641_i2c_driver = {
+       .driver = {
+               .name = "ak4641",
+               .owner = THIS_MODULE,
+       },
+       .probe =    ak4641_i2c_probe,
+       .remove =   __devexit_p(ak4641_i2c_remove),
+       .id_table = ak4641_i2c_id,
+};
+
+static int __init ak4641_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&ak4641_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(ak4641_modinit);
+
+static void __exit ak4641_exit(void)
+{
+       i2c_del_driver(&ak4641_i2c_driver);
+}
+module_exit(ak4641_exit);
+
+MODULE_DESCRIPTION("SoC AK4641 driver");
+MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h
new file mode 100644 (file)
index 0000000..4a26324
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * ak4641.h  --  AK4641 SoC Audio driver
+ *
+ * Copyright 2008 Harald Welte <laforge@gnufiish.org>
+ *
+ * Based on ak4535.h
+ *
+ * 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 _AK4641_H
+#define _AK4641_H
+
+/* AK4641 register space */
+
+#define AK4641_PM1             0x00
+#define AK4641_PM2             0x01
+#define AK4641_SIG1            0x02
+#define AK4641_SIG2            0x03
+#define AK4641_MODE1           0x04
+#define AK4641_MODE2           0x05
+#define AK4641_DAC             0x06
+#define AK4641_MIC             0x07
+#define AK4641_TIMER           0x08
+#define AK4641_ALC1            0x09
+#define AK4641_ALC2            0x0a
+#define AK4641_PGA             0x0b
+#define AK4641_LATT            0x0c
+#define AK4641_RATT            0x0d
+#define AK4641_VOL             0x0e
+#define AK4641_STATUS          0x0f
+#define AK4641_EQLO            0x10
+#define AK4641_EQMID           0x11
+#define AK4641_EQHI            0x12
+#define AK4641_BTIF            0x13
+
+#define AK4641_CACHEREGNUM     0x14
+
+
+
+#define AK4641_DAI_HIFI                0
+#define AK4641_DAI_VOICE       1
+
+
+#endif
index 2ec75abfa3e9759036da009301d933a3c1ae7797..88b29f8c748bf09a1908ecad84b088a6dd6c270f 100644 (file)
@@ -352,7 +352,7 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"DAC Left", "NULL", "PMPLL"},
        {"DAC Right", "NULL", "PMPLL"},
        {"ADC Left", "NULL", "PMPLL"},
@@ -433,17 +433,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
 };
 
-static int ak4671_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
-                                 ARRAY_SIZE(ak4671_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int ak4671_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *dai)
@@ -650,7 +639,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ak4671_snd_controls,
                             ARRAY_SIZE(ak4671_snd_controls));
-       ak4671_add_widgets(codec);
 
        ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -670,6 +658,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
        .reg_cache_size = AK4671_CACHEREGNUM,
        .reg_word_size = sizeof(u8),
        .reg_cache_default = ak4671_reg,
+       .dapm_widgets = ak4671_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
+       .dapm_routes = ak4671_intercon,
+       .num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
 };
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
index 0bb424af956fb0377632d53a9bd6e2bcaadcccd9..d68ea532cc7f59a52e46be1a89ccf4d0c35ad518 100644 (file)
@@ -86,18 +86,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
        {"ADC", NULL, "Input Mixer"},
 };
 
-static int cx20442_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
-                                 ARRAY_SIZE(cx20442_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
-                               ARRAY_SIZE(cx20442_audio_map));
-
-       return 0;
-}
-
 static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
                                                        unsigned int reg)
 {
@@ -344,8 +332,6 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, cx20442);
 
-       cx20442_add_widgets(codec);
-
        cx20442->control_data = NULL;
        codec->hw_write = NULL;
        codec->card->pop_time = 0;
@@ -377,6 +363,10 @@ static struct snd_soc_codec_driver cx20442_codec_dev = {
        .reg_word_size = sizeof(u8),
        .read = cx20442_read_reg_cache,
        .write = cx20442_write,
+       .dapm_widgets = cx20442_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
+       .dapm_routes = cx20442_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
index 57e9dac88d388f85e02b962e9d42ebe81a4bfe50..f9a87737ec16876c14b3602408c149ea26fa913f 100644 (file)
@@ -39,7 +39,31 @@ static struct snd_soc_dai_driver dmic_dai = {
        },
 };
 
-static struct snd_soc_codec_driver soc_dmic = {};
+static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
+                            SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_INPUT("DMic"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       {"DMIC AIF", NULL, "DMic"},
+};
+
+static int dmic_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
+                                 ARRAY_SIZE(dmic_dapm_widgets));
+        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_widgets(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_dmic = {
+       .probe  = dmic_probe,
+};
 
 static int __devinit dmic_dev_probe(struct platform_device *pdev)
 {
index f5ccdbf7ebc6e1fb0630b5ef6db426db5c2ba3e8..e373f8f0690731874d0a153190951ddc564500fe 100644 (file)
@@ -294,20 +294,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
        snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
                        JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
-       snd_soc_add_controls(codec, jz4740_codec_controls,
-               ARRAY_SIZE(jz4740_codec_controls));
-
-       snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets,
-               ARRAY_SIZE(jz4740_codec_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
-               ARRAY_SIZE(jz4740_codec_dapm_routes));
-
        jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -348,6 +337,13 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .reg_cache_default      = jz4740_codec_regs,
        .reg_word_size = sizeof(u32),
        .reg_cache_size = 2,
+
+       .controls = jz4740_codec_controls,
+       .num_controls = ARRAY_SIZE(jz4740_codec_controls),
+       .dapm_widgets = jz4740_codec_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets),
+       .dapm_routes = jz4740_codec_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
 };
 
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
index bd0517cb7980b3a309cd7e8e10a7e2e3ba432bfb..4173b67c94d18c213f48e24c48519a5e5e2910ea 100644 (file)
@@ -656,8 +656,6 @@ static const struct soc_enum max98088_exmode_enum =
                              ARRAY_SIZE(max98088_exmode_texts),
                              max98088_exmode_texts,
                              max98088_exmode_values);
-static const struct snd_kcontrol_new max98088_exmode_controls =
-       SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
 
 static const char *max98088_ex_thresh[] = { /* volts PP */
        "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
@@ -783,6 +781,7 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
        SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
        SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
 
+       SOC_ENUM("EX Limiter Mode", max98088_exmode_enum),
        SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
 
        SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
@@ -808,10 +807,10 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
 
 /* Left speaker mixer switch */
 static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
@@ -836,10 +835,10 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
 
 /* Left headphone mixer switch */
 static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
@@ -864,10 +863,10 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
 
 /* Left earpiece/receiver mixer switch */
 static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
@@ -1094,9 +1093,6 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
 
        SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
 
-       SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
-               &max98088_exmode_controls),
-
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
        SND_SOC_DAPM_OUTPUT("SPKL"),
@@ -1112,7 +1108,7 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("INB2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route max98088_audio_map[] = {
        /* Left headphone output mixer */
        {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
        {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
@@ -1226,22 +1222,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2 Input", NULL, "MIC2"},
 };
 
-static int max98088_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
-                                 ARRAY_SIZE(max98088_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       snd_soc_add_controls(codec, max98088_snd_controls,
-                            ARRAY_SIZE(max98088_snd_controls));
-
-       snd_soc_dapm_new_widgets(dapm);
-       return 0;
-}
-
 /* codec mclk clock divider coefficients */
 static const struct {
        u32 rate;
@@ -1586,6 +1566,36 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_2F_LVL_DAI1_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
+static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_31_LVL_DAI2_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
 static void max98088_sync_cache(struct snd_soc_codec *codec)
 {
        u16 *reg_cache = codec->reg_cache;
@@ -1647,12 +1657,14 @@ static struct snd_soc_dai_ops max98088_dai1_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai1_set_fmt,
        .hw_params = max98088_dai1_hw_params,
+       .digital_mute = max98088_dai1_digital_mute,
 };
 
 static struct snd_soc_dai_ops max98088_dai2_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai2_set_fmt,
        .hw_params = max98088_dai2_hw_params,
+       .digital_mute = max98088_dai2_digital_mute,
 };
 
 static struct snd_soc_dai_driver max98088_dai[] = {
@@ -2010,7 +2022,8 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
        max98088_handle_pdata(codec);
 
-       max98088_add_widgets(codec);
+       snd_soc_add_controls(codec, max98088_snd_controls,
+                            ARRAY_SIZE(max98088_snd_controls));
 
 err_access:
        return ret;
@@ -2036,6 +2049,10 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
        .reg_word_size = sizeof(u8),
        .reg_cache_default = max98088_reg,
        .volatile_register = max98088_volatile_register,
+       .dapm_widgets = max98088_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
+       .dapm_routes = max98088_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
index 56554c797fef9c74e1a78897035d472ad779b03d..be89a4f4aab828ad4efe941c6ce7b6a93c25b510 100644 (file)
        #define M98088_REC_LINEMODE             (1<<7)
        #define M98088_REC_LINEMODE_MASK        (1<<7)
 
+/* M98088_REG_2D_MIX_SPK_CNTL */
+       #define M98088_MIX_SPKR_GAIN_MASK       (3<<2)
+       #define M98088_MIX_SPKR_GAIN_SHIFT      2
+       #define M98088_MIX_SPKL_GAIN_MASK       (3<<0)
+       #define M98088_MIX_SPKL_GAIN_SHIFT      0
+
+/* M98088_REG_2F_LVL_DAI1_PLAY, M98088_REG_31_LVL_DAI2_PLAY */
+       #define M98088_DAI_MUTE                 (1<<7)
+       #define M98088_DAI_MUTE_MASK            (1<<7)
+       #define M98088_DAI_VOICE_GAIN_MASK      (3<<4)
+       #define M98088_DAI_ATTENUATION_MASK     (0xF<<0)
+       #define M98088_DAI_ATTENUATION_SHIFT    0
+
 /* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
        #define M98088_MICPRE_MASK              (3<<5)
        #define M98088_MICPRE_SHIFT             5
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
new file mode 100644 (file)
index 0000000..e1d282d
--- /dev/null
@@ -0,0 +1,2396 @@
+/*
+ * max98095.c -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98095.h>
+#include "max98095.h"
+
+enum max98095_type {
+       MAX98095,
+};
+
+struct max98095_cdata {
+       unsigned int rate;
+       unsigned int fmt;
+       int eq_sel;
+       int bq_sel;
+};
+
+struct max98095_priv {
+       enum max98095_type devtype;
+       void *control_data;
+       struct max98095_pdata *pdata;
+       unsigned int sysclk;
+       struct max98095_cdata dai[3];
+       const char **eq_texts;
+       const char **bq_texts;
+       struct soc_enum eq_enum;
+       struct soc_enum bq_enum;
+       int eq_textcnt;
+       int bq_textcnt;
+       u8 lin_state;
+       unsigned int mic1pre;
+       unsigned int mic2pre;
+};
+
+static const u8 max98095_reg_def[M98095_REG_CNT] = {
+       0x00, /* 00 */
+       0x00, /* 01 */
+       0x00, /* 02 */
+       0x00, /* 03 */
+       0x00, /* 04 */
+       0x00, /* 05 */
+       0x00, /* 06 */
+       0x00, /* 07 */
+       0x00, /* 08 */
+       0x00, /* 09 */
+       0x00, /* 0A */
+       0x00, /* 0B */
+       0x00, /* 0C */
+       0x00, /* 0D */
+       0x00, /* 0E */
+       0x00, /* 0F */
+       0x00, /* 10 */
+       0x00, /* 11 */
+       0x00, /* 12 */
+       0x00, /* 13 */
+       0x00, /* 14 */
+       0x00, /* 15 */
+       0x00, /* 16 */
+       0x00, /* 17 */
+       0x00, /* 18 */
+       0x00, /* 19 */
+       0x00, /* 1A */
+       0x00, /* 1B */
+       0x00, /* 1C */
+       0x00, /* 1D */
+       0x00, /* 1E */
+       0x00, /* 1F */
+       0x00, /* 20 */
+       0x00, /* 21 */
+       0x00, /* 22 */
+       0x00, /* 23 */
+       0x00, /* 24 */
+       0x00, /* 25 */
+       0x00, /* 26 */
+       0x00, /* 27 */
+       0x00, /* 28 */
+       0x00, /* 29 */
+       0x00, /* 2A */
+       0x00, /* 2B */
+       0x00, /* 2C */
+       0x00, /* 2D */
+       0x00, /* 2E */
+       0x00, /* 2F */
+       0x00, /* 30 */
+       0x00, /* 31 */
+       0x00, /* 32 */
+       0x00, /* 33 */
+       0x00, /* 34 */
+       0x00, /* 35 */
+       0x00, /* 36 */
+       0x00, /* 37 */
+       0x00, /* 38 */
+       0x00, /* 39 */
+       0x00, /* 3A */
+       0x00, /* 3B */
+       0x00, /* 3C */
+       0x00, /* 3D */
+       0x00, /* 3E */
+       0x00, /* 3F */
+       0x00, /* 40 */
+       0x00, /* 41 */
+       0x00, /* 42 */
+       0x00, /* 43 */
+       0x00, /* 44 */
+       0x00, /* 45 */
+       0x00, /* 46 */
+       0x00, /* 47 */
+       0x00, /* 48 */
+       0x00, /* 49 */
+       0x00, /* 4A */
+       0x00, /* 4B */
+       0x00, /* 4C */
+       0x00, /* 4D */
+       0x00, /* 4E */
+       0x00, /* 4F */
+       0x00, /* 50 */
+       0x00, /* 51 */
+       0x00, /* 52 */
+       0x00, /* 53 */
+       0x00, /* 54 */
+       0x00, /* 55 */
+       0x00, /* 56 */
+       0x00, /* 57 */
+       0x00, /* 58 */
+       0x00, /* 59 */
+       0x00, /* 5A */
+       0x00, /* 5B */
+       0x00, /* 5C */
+       0x00, /* 5D */
+       0x00, /* 5E */
+       0x00, /* 5F */
+       0x00, /* 60 */
+       0x00, /* 61 */
+       0x00, /* 62 */
+       0x00, /* 63 */
+       0x00, /* 64 */
+       0x00, /* 65 */
+       0x00, /* 66 */
+       0x00, /* 67 */
+       0x00, /* 68 */
+       0x00, /* 69 */
+       0x00, /* 6A */
+       0x00, /* 6B */
+       0x00, /* 6C */
+       0x00, /* 6D */
+       0x00, /* 6E */
+       0x00, /* 6F */
+       0x00, /* 70 */
+       0x00, /* 71 */
+       0x00, /* 72 */
+       0x00, /* 73 */
+       0x00, /* 74 */
+       0x00, /* 75 */
+       0x00, /* 76 */
+       0x00, /* 77 */
+       0x00, /* 78 */
+       0x00, /* 79 */
+       0x00, /* 7A */
+       0x00, /* 7B */
+       0x00, /* 7C */
+       0x00, /* 7D */
+       0x00, /* 7E */
+       0x00, /* 7F */
+       0x00, /* 80 */
+       0x00, /* 81 */
+       0x00, /* 82 */
+       0x00, /* 83 */
+       0x00, /* 84 */
+       0x00, /* 85 */
+       0x00, /* 86 */
+       0x00, /* 87 */
+       0x00, /* 88 */
+       0x00, /* 89 */
+       0x00, /* 8A */
+       0x00, /* 8B */
+       0x00, /* 8C */
+       0x00, /* 8D */
+       0x00, /* 8E */
+       0x00, /* 8F */
+       0x00, /* 90 */
+       0x00, /* 91 */
+       0x30, /* 92 */
+       0xF0, /* 93 */
+       0x00, /* 94 */
+       0x00, /* 95 */
+       0x3F, /* 96 */
+       0x00, /* 97 */
+       0x00, /* 98 */
+       0x00, /* 99 */
+       0x00, /* 9A */
+       0x00, /* 9B */
+       0x00, /* 9C */
+       0x00, /* 9D */
+       0x00, /* 9E */
+       0x00, /* 9F */
+       0x00, /* A0 */
+       0x00, /* A1 */
+       0x00, /* A2 */
+       0x00, /* A3 */
+       0x00, /* A4 */
+       0x00, /* A5 */
+       0x00, /* A6 */
+       0x00, /* A7 */
+       0x00, /* A8 */
+       0x00, /* A9 */
+       0x00, /* AA */
+       0x00, /* AB */
+       0x00, /* AC */
+       0x00, /* AD */
+       0x00, /* AE */
+       0x00, /* AF */
+       0x00, /* B0 */
+       0x00, /* B1 */
+       0x00, /* B2 */
+       0x00, /* B3 */
+       0x00, /* B4 */
+       0x00, /* B5 */
+       0x00, /* B6 */
+       0x00, /* B7 */
+       0x00, /* B8 */
+       0x00, /* B9 */
+       0x00, /* BA */
+       0x00, /* BB */
+       0x00, /* BC */
+       0x00, /* BD */
+       0x00, /* BE */
+       0x00, /* BF */
+       0x00, /* C0 */
+       0x00, /* C1 */
+       0x00, /* C2 */
+       0x00, /* C3 */
+       0x00, /* C4 */
+       0x00, /* C5 */
+       0x00, /* C6 */
+       0x00, /* C7 */
+       0x00, /* C8 */
+       0x00, /* C9 */
+       0x00, /* CA */
+       0x00, /* CB */
+       0x00, /* CC */
+       0x00, /* CD */
+       0x00, /* CE */
+       0x00, /* CF */
+       0x00, /* D0 */
+       0x00, /* D1 */
+       0x00, /* D2 */
+       0x00, /* D3 */
+       0x00, /* D4 */
+       0x00, /* D5 */
+       0x00, /* D6 */
+       0x00, /* D7 */
+       0x00, /* D8 */
+       0x00, /* D9 */
+       0x00, /* DA */
+       0x00, /* DB */
+       0x00, /* DC */
+       0x00, /* DD */
+       0x00, /* DE */
+       0x00, /* DF */
+       0x00, /* E0 */
+       0x00, /* E1 */
+       0x00, /* E2 */
+       0x00, /* E3 */
+       0x00, /* E4 */
+       0x00, /* E5 */
+       0x00, /* E6 */
+       0x00, /* E7 */
+       0x00, /* E8 */
+       0x00, /* E9 */
+       0x00, /* EA */
+       0x00, /* EB */
+       0x00, /* EC */
+       0x00, /* ED */
+       0x00, /* EE */
+       0x00, /* EF */
+       0x00, /* F0 */
+       0x00, /* F1 */
+       0x00, /* F2 */
+       0x00, /* F3 */
+       0x00, /* F4 */
+       0x00, /* F5 */
+       0x00, /* F6 */
+       0x00, /* F7 */
+       0x00, /* F8 */
+       0x00, /* F9 */
+       0x00, /* FA */
+       0x00, /* FB */
+       0x00, /* FC */
+       0x00, /* FD */
+       0x00, /* FE */
+       0x00, /* FF */
+};
+
+static struct {
+       int readable;
+       int writable;
+} max98095_access[M98095_REG_CNT] = {
+       { 0x00, 0x00 }, /* 00 */
+       { 0xFF, 0x00 }, /* 01 */
+       { 0xFF, 0x00 }, /* 02 */
+       { 0xFF, 0x00 }, /* 03 */
+       { 0xFF, 0x00 }, /* 04 */
+       { 0xFF, 0x00 }, /* 05 */
+       { 0xFF, 0x00 }, /* 06 */
+       { 0xFF, 0x00 }, /* 07 */
+       { 0xFF, 0x00 }, /* 08 */
+       { 0xFF, 0x00 }, /* 09 */
+       { 0xFF, 0x00 }, /* 0A */
+       { 0xFF, 0x00 }, /* 0B */
+       { 0xFF, 0x00 }, /* 0C */
+       { 0xFF, 0x00 }, /* 0D */
+       { 0xFF, 0x00 }, /* 0E */
+       { 0xFF, 0x9F }, /* 0F */
+       { 0xFF, 0xFF }, /* 10 */
+       { 0xFF, 0xFF }, /* 11 */
+       { 0xFF, 0xFF }, /* 12 */
+       { 0xFF, 0xFF }, /* 13 */
+       { 0xFF, 0xFF }, /* 14 */
+       { 0xFF, 0xFF }, /* 15 */
+       { 0xFF, 0xFF }, /* 16 */
+       { 0xFF, 0xFF }, /* 17 */
+       { 0xFF, 0xFF }, /* 18 */
+       { 0xFF, 0xFF }, /* 19 */
+       { 0xFF, 0xFF }, /* 1A */
+       { 0xFF, 0xFF }, /* 1B */
+       { 0xFF, 0xFF }, /* 1C */
+       { 0xFF, 0xFF }, /* 1D */
+       { 0xFF, 0x77 }, /* 1E */
+       { 0xFF, 0x77 }, /* 1F */
+       { 0xFF, 0x77 }, /* 20 */
+       { 0xFF, 0x77 }, /* 21 */
+       { 0xFF, 0x77 }, /* 22 */
+       { 0xFF, 0x77 }, /* 23 */
+       { 0xFF, 0xFF }, /* 24 */
+       { 0xFF, 0x7F }, /* 25 */
+       { 0xFF, 0x31 }, /* 26 */
+       { 0xFF, 0xFF }, /* 27 */
+       { 0xFF, 0xFF }, /* 28 */
+       { 0xFF, 0xFF }, /* 29 */
+       { 0xFF, 0xF7 }, /* 2A */
+       { 0xFF, 0x2F }, /* 2B */
+       { 0xFF, 0xEF }, /* 2C */
+       { 0xFF, 0xFF }, /* 2D */
+       { 0xFF, 0xFF }, /* 2E */
+       { 0xFF, 0xFF }, /* 2F */
+       { 0xFF, 0xFF }, /* 30 */
+       { 0xFF, 0xFF }, /* 31 */
+       { 0xFF, 0xFF }, /* 32 */
+       { 0xFF, 0xFF }, /* 33 */
+       { 0xFF, 0xF7 }, /* 34 */
+       { 0xFF, 0x2F }, /* 35 */
+       { 0xFF, 0xCF }, /* 36 */
+       { 0xFF, 0xFF }, /* 37 */
+       { 0xFF, 0xFF }, /* 38 */
+       { 0xFF, 0xFF }, /* 39 */
+       { 0xFF, 0xFF }, /* 3A */
+       { 0xFF, 0xFF }, /* 3B */
+       { 0xFF, 0xFF }, /* 3C */
+       { 0xFF, 0xFF }, /* 3D */
+       { 0xFF, 0xF7 }, /* 3E */
+       { 0xFF, 0x2F }, /* 3F */
+       { 0xFF, 0xCF }, /* 40 */
+       { 0xFF, 0xFF }, /* 41 */
+       { 0xFF, 0x77 }, /* 42 */
+       { 0xFF, 0xFF }, /* 43 */
+       { 0xFF, 0xFF }, /* 44 */
+       { 0xFF, 0xFF }, /* 45 */
+       { 0xFF, 0xFF }, /* 46 */
+       { 0xFF, 0xFF }, /* 47 */
+       { 0xFF, 0xFF }, /* 48 */
+       { 0xFF, 0x0F }, /* 49 */
+       { 0xFF, 0xFF }, /* 4A */
+       { 0xFF, 0xFF }, /* 4B */
+       { 0xFF, 0x3F }, /* 4C */
+       { 0xFF, 0x3F }, /* 4D */
+       { 0xFF, 0x3F }, /* 4E */
+       { 0xFF, 0xFF }, /* 4F */
+       { 0xFF, 0x7F }, /* 50 */
+       { 0xFF, 0x7F }, /* 51 */
+       { 0xFF, 0x0F }, /* 52 */
+       { 0xFF, 0x3F }, /* 53 */
+       { 0xFF, 0x3F }, /* 54 */
+       { 0xFF, 0x3F }, /* 55 */
+       { 0xFF, 0xFF }, /* 56 */
+       { 0xFF, 0xFF }, /* 57 */
+       { 0xFF, 0xBF }, /* 58 */
+       { 0xFF, 0x1F }, /* 59 */
+       { 0xFF, 0xBF }, /* 5A */
+       { 0xFF, 0x1F }, /* 5B */
+       { 0xFF, 0xBF }, /* 5C */
+       { 0xFF, 0x3F }, /* 5D */
+       { 0xFF, 0x3F }, /* 5E */
+       { 0xFF, 0x7F }, /* 5F */
+       { 0xFF, 0x7F }, /* 60 */
+       { 0xFF, 0x47 }, /* 61 */
+       { 0xFF, 0x9F }, /* 62 */
+       { 0xFF, 0x9F }, /* 63 */
+       { 0xFF, 0x9F }, /* 64 */
+       { 0xFF, 0x9F }, /* 65 */
+       { 0xFF, 0x9F }, /* 66 */
+       { 0xFF, 0xBF }, /* 67 */
+       { 0xFF, 0xBF }, /* 68 */
+       { 0xFF, 0xFF }, /* 69 */
+       { 0xFF, 0xFF }, /* 6A */
+       { 0xFF, 0x7F }, /* 6B */
+       { 0xFF, 0xF7 }, /* 6C */
+       { 0xFF, 0xFF }, /* 6D */
+       { 0xFF, 0xFF }, /* 6E */
+       { 0xFF, 0x1F }, /* 6F */
+       { 0xFF, 0xF7 }, /* 70 */
+       { 0xFF, 0xFF }, /* 71 */
+       { 0xFF, 0xFF }, /* 72 */
+       { 0xFF, 0x1F }, /* 73 */
+       { 0xFF, 0xF7 }, /* 74 */
+       { 0xFF, 0xFF }, /* 75 */
+       { 0xFF, 0xFF }, /* 76 */
+       { 0xFF, 0x1F }, /* 77 */
+       { 0xFF, 0xF7 }, /* 78 */
+       { 0xFF, 0xFF }, /* 79 */
+       { 0xFF, 0xFF }, /* 7A */
+       { 0xFF, 0x1F }, /* 7B */
+       { 0xFF, 0xF7 }, /* 7C */
+       { 0xFF, 0xFF }, /* 7D */
+       { 0xFF, 0xFF }, /* 7E */
+       { 0xFF, 0x1F }, /* 7F */
+       { 0xFF, 0xF7 }, /* 80 */
+       { 0xFF, 0xFF }, /* 81 */
+       { 0xFF, 0xFF }, /* 82 */
+       { 0xFF, 0x1F }, /* 83 */
+       { 0xFF, 0x7F }, /* 84 */
+       { 0xFF, 0x0F }, /* 85 */
+       { 0xFF, 0xD8 }, /* 86 */
+       { 0xFF, 0xFF }, /* 87 */
+       { 0xFF, 0xEF }, /* 88 */
+       { 0xFF, 0xFE }, /* 89 */
+       { 0xFF, 0xFE }, /* 8A */
+       { 0xFF, 0xFF }, /* 8B */
+       { 0xFF, 0xFF }, /* 8C */
+       { 0xFF, 0x3F }, /* 8D */
+       { 0xFF, 0xFF }, /* 8E */
+       { 0xFF, 0x3F }, /* 8F */
+       { 0xFF, 0x8F }, /* 90 */
+       { 0xFF, 0xFF }, /* 91 */
+       { 0xFF, 0x3F }, /* 92 */
+       { 0xFF, 0xFF }, /* 93 */
+       { 0xFF, 0xFF }, /* 94 */
+       { 0xFF, 0x0F }, /* 95 */
+       { 0xFF, 0x3F }, /* 96 */
+       { 0xFF, 0x8C }, /* 97 */
+       { 0x00, 0x00 }, /* 98 */
+       { 0x00, 0x00 }, /* 99 */
+       { 0x00, 0x00 }, /* 9A */
+       { 0x00, 0x00 }, /* 9B */
+       { 0x00, 0x00 }, /* 9C */
+       { 0x00, 0x00 }, /* 9D */
+       { 0x00, 0x00 }, /* 9E */
+       { 0x00, 0x00 }, /* 9F */
+       { 0x00, 0x00 }, /* A0 */
+       { 0x00, 0x00 }, /* A1 */
+       { 0x00, 0x00 }, /* A2 */
+       { 0x00, 0x00 }, /* A3 */
+       { 0x00, 0x00 }, /* A4 */
+       { 0x00, 0x00 }, /* A5 */
+       { 0x00, 0x00 }, /* A6 */
+       { 0x00, 0x00 }, /* A7 */
+       { 0x00, 0x00 }, /* A8 */
+       { 0x00, 0x00 }, /* A9 */
+       { 0x00, 0x00 }, /* AA */
+       { 0x00, 0x00 }, /* AB */
+       { 0x00, 0x00 }, /* AC */
+       { 0x00, 0x00 }, /* AD */
+       { 0x00, 0x00 }, /* AE */
+       { 0x00, 0x00 }, /* AF */
+       { 0x00, 0x00 }, /* B0 */
+       { 0x00, 0x00 }, /* B1 */
+       { 0x00, 0x00 }, /* B2 */
+       { 0x00, 0x00 }, /* B3 */
+       { 0x00, 0x00 }, /* B4 */
+       { 0x00, 0x00 }, /* B5 */
+       { 0x00, 0x00 }, /* B6 */
+       { 0x00, 0x00 }, /* B7 */
+       { 0x00, 0x00 }, /* B8 */
+       { 0x00, 0x00 }, /* B9 */
+       { 0x00, 0x00 }, /* BA */
+       { 0x00, 0x00 }, /* BB */
+       { 0x00, 0x00 }, /* BC */
+       { 0x00, 0x00 }, /* BD */
+       { 0x00, 0x00 }, /* BE */
+       { 0x00, 0x00 }, /* BF */
+       { 0x00, 0x00 }, /* C0 */
+       { 0x00, 0x00 }, /* C1 */
+       { 0x00, 0x00 }, /* C2 */
+       { 0x00, 0x00 }, /* C3 */
+       { 0x00, 0x00 }, /* C4 */
+       { 0x00, 0x00 }, /* C5 */
+       { 0x00, 0x00 }, /* C6 */
+       { 0x00, 0x00 }, /* C7 */
+       { 0x00, 0x00 }, /* C8 */
+       { 0x00, 0x00 }, /* C9 */
+       { 0x00, 0x00 }, /* CA */
+       { 0x00, 0x00 }, /* CB */
+       { 0x00, 0x00 }, /* CC */
+       { 0x00, 0x00 }, /* CD */
+       { 0x00, 0x00 }, /* CE */
+       { 0x00, 0x00 }, /* CF */
+       { 0x00, 0x00 }, /* D0 */
+       { 0x00, 0x00 }, /* D1 */
+       { 0x00, 0x00 }, /* D2 */
+       { 0x00, 0x00 }, /* D3 */
+       { 0x00, 0x00 }, /* D4 */
+       { 0x00, 0x00 }, /* D5 */
+       { 0x00, 0x00 }, /* D6 */
+       { 0x00, 0x00 }, /* D7 */
+       { 0x00, 0x00 }, /* D8 */
+       { 0x00, 0x00 }, /* D9 */
+       { 0x00, 0x00 }, /* DA */
+       { 0x00, 0x00 }, /* DB */
+       { 0x00, 0x00 }, /* DC */
+       { 0x00, 0x00 }, /* DD */
+       { 0x00, 0x00 }, /* DE */
+       { 0x00, 0x00 }, /* DF */
+       { 0x00, 0x00 }, /* E0 */
+       { 0x00, 0x00 }, /* E1 */
+       { 0x00, 0x00 }, /* E2 */
+       { 0x00, 0x00 }, /* E3 */
+       { 0x00, 0x00 }, /* E4 */
+       { 0x00, 0x00 }, /* E5 */
+       { 0x00, 0x00 }, /* E6 */
+       { 0x00, 0x00 }, /* E7 */
+       { 0x00, 0x00 }, /* E8 */
+       { 0x00, 0x00 }, /* E9 */
+       { 0x00, 0x00 }, /* EA */
+       { 0x00, 0x00 }, /* EB */
+       { 0x00, 0x00 }, /* EC */
+       { 0x00, 0x00 }, /* ED */
+       { 0x00, 0x00 }, /* EE */
+       { 0x00, 0x00 }, /* EF */
+       { 0x00, 0x00 }, /* F0 */
+       { 0x00, 0x00 }, /* F1 */
+       { 0x00, 0x00 }, /* F2 */
+       { 0x00, 0x00 }, /* F3 */
+       { 0x00, 0x00 }, /* F4 */
+       { 0x00, 0x00 }, /* F5 */
+       { 0x00, 0x00 }, /* F6 */
+       { 0x00, 0x00 }, /* F7 */
+       { 0x00, 0x00 }, /* F8 */
+       { 0x00, 0x00 }, /* F9 */
+       { 0x00, 0x00 }, /* FA */
+       { 0x00, 0x00 }, /* FB */
+       { 0x00, 0x00 }, /* FC */
+       { 0x00, 0x00 }, /* FD */
+       { 0x00, 0x00 }, /* FE */
+       { 0xFF, 0x00 }, /* FF */
+};
+
+static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg)
+{
+       if (reg >= M98095_REG_CNT)
+               return 0;
+       return max98095_access[reg].readable != 0;
+}
+
+static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
+{
+       if (reg > M98095_REG_MAX_CACHED)
+               return 1;
+
+       switch (reg) {
+       case M98095_000_HOST_DATA:
+       case M98095_001_HOST_INT_STS:
+       case M98095_002_HOST_RSP_STS:
+       case M98095_003_HOST_CMD_STS:
+       case M98095_004_CODEC_STS:
+       case M98095_005_DAI1_ALC_STS:
+       case M98095_006_DAI2_ALC_STS:
+       case M98095_007_JACK_AUTO_STS:
+       case M98095_008_JACK_MANUAL_STS:
+       case M98095_009_JACK_VBAT_STS:
+       case M98095_00A_ACC_ADC_STS:
+       case M98095_00B_MIC_NG_AGC_STS:
+       case M98095_00C_SPK_L_VOLT_STS:
+       case M98095_00D_SPK_R_VOLT_STS:
+       case M98095_00E_TEMP_SENSOR_STS:
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Filter coefficients are in a separate register segment
+ * and they share the address space of the normal registers.
+ * The coefficient registers do not need or share the cache.
+ */
+static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u8 data[2];
+
+       data[0] = reg;
+       data[1] = value;
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+                   unsigned int band, u16 *coefs)
+{
+       unsigned int eq_reg;
+       unsigned int i;
+
+       BUG_ON(band > 4);
+       BUG_ON(dai > 1);
+
+       /* Load the base register address */
+       eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE;
+
+       /* Add the band address offset, note adjustment for word address */
+       eq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+       /* Step through the registers and coefs */
+       for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+               max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
+               max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
+       }
+}
+
+/*
+ * Load biquad filter coefficient configurations registers
+ */
+static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
+                   unsigned int band, u16 *coefs)
+{
+       unsigned int bq_reg;
+       unsigned int i;
+
+       BUG_ON(band > 1);
+       BUG_ON(dai > 1);
+
+       /* Load the base register address */
+       bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE;
+
+       /* Add the band address offset, note adjustment for word address */
+       bq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+       /* Step through the registers and coefs */
+       for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+               max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
+               max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
+       }
+}
+
+static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
+static const struct soc_enum max98095_dai1_filter_mode_enum[] = {
+       SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode),
+};
+static const struct soc_enum max98095_dai2_filter_mode_enum[] = {
+       SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode),
+};
+
+static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98095_extmic_enum =
+       SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text);
+
+static const struct snd_kcontrol_new max98095_extmic_mux =
+       SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
+
+static const char * const max98095_linein_text[] = { "INA", "INB" };
+
+static const struct soc_enum max98095_linein_enum =
+       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text);
+
+static const struct snd_kcontrol_new max98095_linein_mux =
+       SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
+
+static const char * const max98095_line_mode_text[] = {
+       "Stereo", "Differential"};
+
+static const struct soc_enum max98095_linein_mode_enum =
+       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text);
+
+static const struct soc_enum max98095_lineout_mode_enum =
+       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text);
+
+static const char * const max98095_dai_fltr[] = {
+       "Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
+       "Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
+static const struct soc_enum max98095_dai1_dac_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai2_dac_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai3_dac_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr),
+};
+
+static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98095->mic1pre = sel;
+       snd_soc_update_bits(codec, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
+               (1+sel)<<M98095_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98095->mic1pre;
+       return 0;
+}
+
+static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98095->mic2pre = sel;
+       snd_soc_update_bits(codec, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
+               (1+sel)<<M98095_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98095->mic2pre;
+       return 0;
+}
+
+static const unsigned int max98095_micboost_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0);
+
+static const unsigned int max98095_hp_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+       7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+       15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+       22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+       28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static const unsigned int max98095_spk_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0),
+       11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+       19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0),
+       28, 39, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_rcv_lout_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+       7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+       15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+       22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+       28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_lin_tlv[] = {
+       TLV_DB_RANGE_HEAD(3),
+       0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0),
+       3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0),
+       4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
+};
+
+static const struct snd_kcontrol_new max98095_snd_controls[] = {
+
+       SOC_DOUBLE_R_TLV("Headphone Volume", M98095_064_LVL_HP_L,
+               M98095_065_LVL_HP_R, 0, 31, 0, max98095_hp_tlv),
+
+       SOC_DOUBLE_R_TLV("Speaker Volume", M98095_067_LVL_SPK_L,
+               M98095_068_LVL_SPK_R, 0, 39, 0, max98095_spk_tlv),
+
+       SOC_SINGLE_TLV("Receiver Volume", M98095_066_LVL_RCV,
+               0, 31, 0, max98095_rcv_lout_tlv),
+
+       SOC_DOUBLE_R_TLV("Lineout Volume", M98095_062_LVL_LINEOUT1,
+               M98095_063_LVL_LINEOUT2, 0, 31, 0, max98095_rcv_lout_tlv),
+
+       SOC_DOUBLE_R("Headphone Switch", M98095_064_LVL_HP_L,
+               M98095_065_LVL_HP_R, 7, 1, 1),
+
+       SOC_DOUBLE_R("Speaker Switch", M98095_067_LVL_SPK_L,
+               M98095_068_LVL_SPK_R, 7, 1, 1),
+
+       SOC_SINGLE("Receiver Switch", M98095_066_LVL_RCV, 7, 1, 1),
+
+       SOC_DOUBLE_R("Lineout Switch", M98095_062_LVL_LINEOUT1,
+               M98095_063_LVL_LINEOUT2, 7, 1, 1),
+
+       SOC_SINGLE_TLV("MIC1 Volume", M98095_05F_LVL_MIC1, 0, 20, 1,
+               max98095_mic_tlv),
+
+       SOC_SINGLE_TLV("MIC2 Volume", M98095_060_LVL_MIC2, 0, 20, 1,
+               max98095_mic_tlv),
+
+       SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+                       M98095_05F_LVL_MIC1, 5, 2, 0,
+                       max98095_mic1pre_get, max98095_mic1pre_set,
+                       max98095_micboost_tlv),
+       SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+                       M98095_060_LVL_MIC2, 5, 2, 0,
+                       max98095_mic2pre_get, max98095_mic2pre_set,
+                       max98095_micboost_tlv),
+
+       SOC_SINGLE_TLV("Linein Volume", M98095_061_LVL_LINEIN, 0, 5, 1,
+               max98095_lin_tlv),
+
+       SOC_SINGLE_TLV("ADCL Volume", M98095_05D_LVL_ADC_L, 0, 15, 1,
+               max98095_adc_tlv),
+       SOC_SINGLE_TLV("ADCR Volume", M98095_05E_LVL_ADC_R, 0, 15, 1,
+               max98095_adc_tlv),
+
+       SOC_SINGLE_TLV("ADCL Boost Volume", M98095_05D_LVL_ADC_L, 4, 3, 0,
+               max98095_adcboost_tlv),
+       SOC_SINGLE_TLV("ADCR Boost Volume", M98095_05E_LVL_ADC_R, 4, 3, 0,
+               max98095_adcboost_tlv),
+
+       SOC_SINGLE("EQ1 Switch", M98095_088_CFG_LEVEL, 0, 1, 0),
+       SOC_SINGLE("EQ2 Switch", M98095_088_CFG_LEVEL, 1, 1, 0),
+
+       SOC_SINGLE("Biquad1 Switch", M98095_088_CFG_LEVEL, 2, 1, 0),
+       SOC_SINGLE("Biquad2 Switch", M98095_088_CFG_LEVEL, 3, 1, 0),
+
+       SOC_ENUM("DAI1 Filter Mode", max98095_dai1_filter_mode_enum),
+       SOC_ENUM("DAI2 Filter Mode", max98095_dai2_filter_mode_enum),
+       SOC_ENUM("DAI1 DAC Filter", max98095_dai1_dac_filter_enum),
+       SOC_ENUM("DAI2 DAC Filter", max98095_dai2_dac_filter_enum),
+       SOC_ENUM("DAI3 DAC Filter", max98095_dai3_dac_filter_enum),
+
+       SOC_ENUM("Linein Mode", max98095_linein_mode_enum),
+       SOC_ENUM("Lineout Mode", max98095_lineout_mode_enum),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98095_left_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_050_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_050_MIX_SPK_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_050_MIX_SPK_LEFT, 4, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_050_MIX_SPK_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_050_MIX_SPK_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_050_MIX_SPK_LEFT, 2, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98095_right_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_051_MIX_SPK_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_051_MIX_SPK_RIGHT, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_051_MIX_SPK_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_051_MIX_SPK_RIGHT, 2, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98095_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04C_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04C_MIX_HP_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_04C_MIX_HP_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_04C_MIX_HP_LEFT, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_04C_MIX_HP_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_04C_MIX_HP_LEFT, 2, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98095_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_04D_MIX_HP_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_04D_MIX_HP_RIGHT, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_04D_MIX_HP_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_04D_MIX_HP_RIGHT, 2, 1, 0),
+};
+
+/* Receiver earpiece mixer switch */
+static const struct snd_kcontrol_new max98095_mono_rcv_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04F_MIX_RCV, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04F_MIX_RCV, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_04F_MIX_RCV, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_04F_MIX_RCV, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_04F_MIX_RCV, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_04F_MIX_RCV, 2, 1, 0),
+};
+
+/* Left lineout mixer switch */
+static const struct snd_kcontrol_new max98095_left_lineout_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_053_MIX_LINEOUT1, 5, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_053_MIX_LINEOUT1, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_053_MIX_LINEOUT1, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_053_MIX_LINEOUT1, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_053_MIX_LINEOUT1, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_053_MIX_LINEOUT1, 2, 1, 0),
+};
+
+/* Right lineout mixer switch */
+static const struct snd_kcontrol_new max98095_right_lineout_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_054_MIX_LINEOUT2, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_054_MIX_LINEOUT2, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_054_MIX_LINEOUT2, 3, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_054_MIX_LINEOUT2, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_054_MIX_LINEOUT2, 1, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_054_MIX_LINEOUT2, 2, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98095_left_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_04A_MIX_ADC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_04A_MIX_ADC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_04A_MIX_ADC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_04A_MIX_ADC_LEFT, 2, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98095_04B_MIX_ADC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98095_04B_MIX_ADC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("IN1 Switch", M98095_04B_MIX_ADC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("IN2 Switch", M98095_04B_MIX_ADC_RIGHT, 2, 1, 0),
+};
+
+static int max98095_mic_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (w->reg == M98095_05F_LVL_MIC1) {
+                       snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+                               (1+max98095->mic1pre)<<M98095_MICPRE_SHIFT);
+               } else {
+                       snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+                               (1+max98095->mic2pre)<<M98095_MICPRE_SHIFT);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * The line inputs are stereo inputs with the left and right
+ * channels sharing a common PGA power control signal.
+ */
+static int max98095_line_pga(struct snd_soc_dapm_widget *w,
+                            int event, u8 channel)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       u8 *state;
+
+       BUG_ON(!((channel == 1) || (channel == 2)));
+
+       state = &max98095->lin_state;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               *state |= channel;
+               snd_soc_update_bits(codec, w->reg,
+                       (1 << w->shift), (1 << w->shift));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               *state &= ~channel;
+               if (*state == 0) {
+                       snd_soc_update_bits(codec, w->reg,
+                               (1 << w->shift), 0);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int max98095_pga_in1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98095_line_pga(w, event, 1);
+}
+
+static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98095_line_pga(w, event, 2);
+}
+
+/*
+ * The stereo line out mixer outputs to two stereo line outs.
+ * The 2nd pair has a separate set of enables.
+ */
+static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, w->reg,
+                       (1 << (w->shift+2)), (1 << (w->shift+2)));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg,
+                       (1 << (w->shift+2)), 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget max98095_dapm_widgets[] = {
+
+       SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98095_090_PWR_EN_IN, 0, 0),
+       SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98095_090_PWR_EN_IN, 1, 0),
+
+       SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+               M98095_091_PWR_EN_OUT, 0, 0),
+       SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+               M98095_091_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACM2", "Aux Playback",
+               M98095_091_PWR_EN_OUT, 2, 0),
+       SND_SOC_DAPM_DAC("DACM3", "Voice Playback",
+               M98095_091_PWR_EN_OUT, 2, 0),
+
+       SND_SOC_DAPM_PGA("HP Left Out", M98095_091_PWR_EN_OUT,
+               6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Right Out", M98095_091_PWR_EN_OUT,
+               7, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("SPK Left Out", M98095_091_PWR_EN_OUT,
+               4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Right Out", M98095_091_PWR_EN_OUT,
+               5, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("RCV Mono Out", M98095_091_PWR_EN_OUT,
+               3, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA_E("LINE Left Out", M98095_092_PWR_EN_OUT,
+               0, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_PGA_E("LINE Right Out", M98095_092_PWR_EN_OUT,
+               1, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+               &max98095_extmic_mux),
+
+       SND_SOC_DAPM_MUX("Linein Mux", SND_SOC_NOPM, 0, 0,
+               &max98095_linein_mux),
+
+       SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_left_hp_mixer_controls[0],
+               ARRAY_SIZE(max98095_left_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_right_hp_mixer_controls[0],
+               ARRAY_SIZE(max98095_right_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_left_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98095_left_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_right_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98095_right_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Receiver Mixer", SND_SOC_NOPM, 0, 0,
+         &max98095_mono_rcv_mixer_controls[0],
+               ARRAY_SIZE(max98095_mono_rcv_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_left_lineout_mixer_controls[0],
+               ARRAY_SIZE(max98095_left_lineout_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_right_lineout_mixer_controls[0],
+               ARRAY_SIZE(max98095_right_lineout_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_left_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98095_left_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98095_right_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98095_right_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_PGA_E("MIC1 Input", M98095_05F_LVL_MIC1,
+               5, 0, NULL, 0, max98095_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("MIC2 Input", M98095_060_LVL_MIC2,
+               5, 0, NULL, 0, max98095_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("IN1 Input", M98095_090_PWR_EN_IN,
+               7, 0, NULL, 0, max98095_pga_in1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("IN2 Input", M98095_090_PWR_EN_IN,
+               7, 0, NULL, 0, max98095_pga_in2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MICBIAS("MICBIAS1", M98095_090_PWR_EN_IN, 2, 0),
+       SND_SOC_DAPM_MICBIAS("MICBIAS2", M98095_090_PWR_EN_IN, 3, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("RCV"),
+       SND_SOC_DAPM_OUTPUT("OUT1"),
+       SND_SOC_DAPM_OUTPUT("OUT2"),
+       SND_SOC_DAPM_OUTPUT("OUT3"),
+       SND_SOC_DAPM_OUTPUT("OUT4"),
+
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("INA1"),
+       SND_SOC_DAPM_INPUT("INA2"),
+       SND_SOC_DAPM_INPUT("INB1"),
+       SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route max98095_audio_map[] = {
+       /* Left headphone output mixer */
+       {"Left Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left Headphone Mixer", "IN1 Switch", "IN1 Input"},
+       {"Left Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Right headphone output mixer */
+       {"Right Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right Headphone Mixer", "IN1 Switch", "IN1 Input"},
+       {"Right Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Left speaker output mixer */
+       {"Left Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+       {"Left Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+       {"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left Speaker Mixer", "IN1 Switch", "IN1 Input"},
+       {"Left Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Right speaker output mixer */
+       {"Right Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+       {"Right Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+       {"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right Speaker Mixer", "IN1 Switch", "IN1 Input"},
+       {"Right Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Receiver Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Receiver Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Receiver Mixer", "IN1 Switch", "IN1 Input"},
+       {"Receiver Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Left Lineout output mixer */
+       {"Left Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left Lineout Mixer", "IN1 Switch", "IN1 Input"},
+       {"Left Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Right lineout output mixer */
+       {"Right Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right Lineout Mixer", "IN1 Switch", "IN1 Input"},
+       {"Right Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+       {"HP Left Out", NULL, "Left Headphone Mixer"},
+       {"HP Right Out", NULL, "Right Headphone Mixer"},
+       {"SPK Left Out", NULL, "Left Speaker Mixer"},
+       {"SPK Right Out", NULL, "Right Speaker Mixer"},
+       {"RCV Mono Out", NULL, "Receiver Mixer"},
+       {"LINE Left Out", NULL, "Left Lineout Mixer"},
+       {"LINE Right Out", NULL, "Right Lineout Mixer"},
+
+       {"HPL", NULL, "HP Left Out"},
+       {"HPR", NULL, "HP Right Out"},
+       {"SPKL", NULL, "SPK Left Out"},
+       {"SPKR", NULL, "SPK Right Out"},
+       {"RCV", NULL, "RCV Mono Out"},
+       {"OUT1", NULL, "LINE Left Out"},
+       {"OUT2", NULL, "LINE Right Out"},
+       {"OUT3", NULL, "LINE Left Out"},
+       {"OUT4", NULL, "LINE Right Out"},
+
+       /* Left ADC input mixer */
+       {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left ADC Mixer", "IN1 Switch", "IN1 Input"},
+       {"Left ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Right ADC input mixer */
+       {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right ADC Mixer", "IN1 Switch", "IN1 Input"},
+       {"Right ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+       /* Inputs */
+       {"ADCL", NULL, "Left ADC Mixer"},
+       {"ADCR", NULL, "Right ADC Mixer"},
+
+       {"IN1 Input", NULL, "INA1"},
+       {"IN2 Input", NULL, "INA2"},
+
+       {"MIC1 Input", NULL, "MIC1"},
+       {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98095_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_add_controls(codec, max98095_snd_controls,
+                            ARRAY_SIZE(max98095_snd_controls));
+
+       return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+       u32 rate;
+       u8  sr;
+} rate_table[] = {
+       {8000,  0x01},
+       {11025, 0x02},
+       {16000, 0x03},
+       {22050, 0x04},
+       {24000, 0x05},
+       {32000, 0x06},
+       {44100, 0x07},
+       {48000, 0x08},
+       {88200, 0x09},
+       {96000, 0x0A},
+};
+
+static int rate_value(int rate, u8 *value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+               if (rate_table[i].rate >= rate) {
+                       *value = rate_table[i].sr;
+                       return 0;
+               }
+       }
+       *value = rate_table[0].sr;
+       return -EINVAL;
+}
+
+static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98095->dai[0];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+                       M98095_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+                       M98095_DAI_WS, M98095_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98095_027_DAI1_CLKMODE,
+               M98095_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
+               if (max98095->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98095->sysclk);
+               snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+                       M98095_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+                       M98095_DAI_DHF, M98095_DAI_DHF);
+
+       return 0;
+}
+
+static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98095->dai[1];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+                       M98095_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+                       M98095_DAI_WS, M98095_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98095_031_DAI2_CLKMODE,
+               M98095_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
+               if (max98095->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98095->sysclk);
+               snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+                       M98095_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+                       M98095_DAI_DHF, M98095_DAI_DHF);
+
+       return 0;
+}
+
+static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98095->dai[2];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+                       M98095_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+                       M98095_DAI_WS, M98095_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98095_03B_DAI3_CLKMODE,
+               M98095_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
+               if (max98095->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98095->sysclk);
+               snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+                       M98095_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+                       M98095_DAI_DHF, M98095_DAI_DHF);
+
+       return 0;
+}
+
+static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+       /* Requested clock frequency is already setup */
+       if (freq == max98095->sysclk)
+               return 0;
+
+       max98095->sysclk = freq; /* remember current sysclk */
+
+       /* Setup clocks for slave mode, and using the PLL
+        * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+        *         0x02 (when master clk is 20MHz to 40MHz)..
+        *         0x03 (when master clk is 40MHz to 60MHz)..
+        */
+       if ((freq >= 10000000) && (freq < 20000000)) {
+               snd_soc_write(codec, M98095_026_SYS_CLK, 0x10);
+       } else if ((freq >= 20000000) && (freq < 40000000)) {
+               snd_soc_write(codec, M98095_026_SYS_CLK, 0x20);
+       } else if ((freq >= 40000000) && (freq < 60000000)) {
+               snd_soc_write(codec, M98095_026_SYS_CLK, 0x30);
+       } else {
+               dev_err(codec->dev, "Invalid master clock frequency\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       max98095->sysclk = freq;
+       return 0;
+}
+
+static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       u8 regval = 0;
+
+       cdata = &max98095->dai[0];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       regval |= M98095_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       regval |= M98095_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       regval |= M98095_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       regval |= M98095_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+                       M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+                       M98095_DAI_WCI, regval);
+
+               snd_soc_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       u8 regval = 0;
+
+       cdata = &max98095->dai[1];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       regval |= M98095_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       regval |= M98095_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       regval |= M98095_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       regval |= M98095_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+                       M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+                       M98095_DAI_WCI, regval);
+
+               snd_soc_write(codec, M98095_035_DAI2_CLOCK,
+                       M98095_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       u8 regval = 0;
+
+       cdata = &max98095->dai[2];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       regval |= M98095_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       regval |= M98095_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       regval |= M98095_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       regval |= M98095_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+                       M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+                       M98095_DAI_WCI, regval);
+
+               snd_soc_write(codec, M98095_03F_DAI3_CLOCK,
+                       M98095_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static int max98095_set_bias_level(struct snd_soc_codec *codec,
+                                  enum snd_soc_bias_level level)
+{
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = snd_soc_cache_sync(codec);
+
+                       if (ret != 0) {
+                               dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+               }
+
+               snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+                               M98095_MBEN, M98095_MBEN);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+                               M98095_MBEN, 0);
+               codec->cache_sync = 1;
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98095_dai1_ops = {
+       .set_sysclk = max98095_dai_set_sysclk,
+       .set_fmt = max98095_dai1_set_fmt,
+       .hw_params = max98095_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai2_ops = {
+       .set_sysclk = max98095_dai_set_sysclk,
+       .set_fmt = max98095_dai2_set_fmt,
+       .hw_params = max98095_dai2_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai3_ops = {
+       .set_sysclk = max98095_dai_set_sysclk,
+       .set_fmt = max98095_dai3_set_fmt,
+       .hw_params = max98095_dai3_hw_params,
+};
+
+static struct snd_soc_dai_driver max98095_dai[] = {
+{
+       .name = "HiFi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98095_RATES,
+               .formats = MAX98095_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98095_RATES,
+               .formats = MAX98095_FORMATS,
+       },
+        .ops = &max98095_dai1_ops,
+},
+{
+       .name = "Aux",
+       .playback = {
+               .stream_name = "Aux Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = MAX98095_RATES,
+               .formats = MAX98095_FORMATS,
+       },
+       .ops = &max98095_dai2_ops,
+},
+{
+       .name = "Voice",
+       .playback = {
+               .stream_name = "Voice Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = MAX98095_RATES,
+               .formats = MAX98095_FORMATS,
+       },
+       .ops = &max98095_dai3_ops,
+}
+
+};
+
+static int max98095_get_eq_channel(const char *name)
+{
+       if (strcmp(name, "EQ1 Mode") == 0)
+               return 0;
+       if (strcmp(name, "EQ2 Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_pdata *pdata = max98095->pdata;
+       int channel = max98095_get_eq_channel(kcontrol->id.name);
+       struct max98095_cdata *cdata;
+       int sel = ucontrol->value.integer.value[0];
+       struct max98095_eq_cfg *coef_set;
+       int fs, best, best_val, i;
+       int regmask, regsave;
+
+       BUG_ON(channel > 1);
+
+       if (!pdata || !max98095->eq_textcnt)
+               return 0;
+
+       if (sel >= pdata->eq_cfgcnt)
+               return -EINVAL;
+
+       cdata = &max98095->dai[channel];
+       cdata->eq_sel = sel;
+       fs = cdata->rate;
+
+       /* Find the selected configuration with nearest sample rate */
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98095->eq_texts[sel]) == 0 &&
+                       abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       coef_set = &pdata->eq_cfg[best];
+
+       regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN;
+
+       /* Disable filter while configuring, and save current on/off state */
+       regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+       mutex_lock(&codec->mutex);
+       snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+       m98095_eq_band(codec, channel, 0, coef_set->band1);
+       m98095_eq_band(codec, channel, 1, coef_set->band2);
+       m98095_eq_band(codec, channel, 2, coef_set->band3);
+       m98095_eq_band(codec, channel, 3, coef_set->band4);
+       m98095_eq_band(codec, channel, 4, coef_set->band5);
+       snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+       mutex_unlock(&codec->mutex);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+       return 0;
+}
+
+static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       int channel = max98095_get_eq_channel(kcontrol->id.name);
+       struct max98095_cdata *cdata;
+
+       cdata = &max98095->dai[channel];
+       ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+
+       return 0;
+}
+
+static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_pdata *pdata = max98095->pdata;
+       struct max98095_eq_cfg *cfg;
+       unsigned int cfgcnt;
+       int i, j;
+       const char **t;
+       int ret;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("EQ1 Mode",
+                       max98095->eq_enum,
+                       max98095_get_eq_enum,
+                       max98095_put_eq_enum),
+               SOC_ENUM_EXT("EQ2 Mode",
+                       max98095->eq_enum,
+                       max98095_get_eq_enum,
+                       max98095_put_eq_enum),
+       };
+
+       cfg = pdata->eq_cfg;
+       cfgcnt = pdata->eq_cfgcnt;
+
+       /* Setup an array of texts for the equalizer enum.
+        * This is based on Mark Brown's equalizer driver code.
+        */
+       max98095->eq_textcnt = 0;
+       max98095->eq_texts = NULL;
+       for (i = 0; i < cfgcnt; i++) {
+               for (j = 0; j < max98095->eq_textcnt; j++) {
+                       if (strcmp(cfg[i].name, max98095->eq_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != max98095->eq_textcnt)
+                       continue;
+
+               /* Expand the array */
+               t = krealloc(max98095->eq_texts,
+                            sizeof(char *) * (max98095->eq_textcnt + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* Store the new entry */
+               t[max98095->eq_textcnt] = cfg[i].name;
+               max98095->eq_textcnt++;
+               max98095->eq_texts = t;
+       }
+
+       /* Now point the soc_enum to .texts array items */
+       max98095->eq_enum.texts = max98095->eq_texts;
+       max98095->eq_enum.max = max98095->eq_textcnt;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static int max98095_get_bq_channel(const char *name)
+{
+       if (strcmp(name, "Biquad1 Mode") == 0)
+               return 0;
+       if (strcmp(name, "Biquad2 Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_pdata *pdata = max98095->pdata;
+       int channel = max98095_get_bq_channel(kcontrol->id.name);
+       struct max98095_cdata *cdata;
+       int sel = ucontrol->value.integer.value[0];
+       struct max98095_biquad_cfg *coef_set;
+       int fs, best, best_val, i;
+       int regmask, regsave;
+
+       BUG_ON(channel > 1);
+
+       if (!pdata || !max98095->bq_textcnt)
+               return 0;
+
+       if (sel >= pdata->bq_cfgcnt)
+               return -EINVAL;
+
+       cdata = &max98095->dai[channel];
+       cdata->bq_sel = sel;
+       fs = cdata->rate;
+
+       /* Find the selected configuration with nearest sample rate */
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->bq_cfgcnt; i++) {
+               if (strcmp(pdata->bq_cfg[i].name, max98095->bq_texts[sel]) == 0 &&
+                       abs(pdata->bq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->bq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->bq_cfg[best].name,
+               pdata->bq_cfg[best].rate, fs);
+
+       coef_set = &pdata->bq_cfg[best];
+
+       regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN;
+
+       /* Disable filter while configuring, and save current on/off state */
+       regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+       mutex_lock(&codec->mutex);
+       snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+       m98095_biquad_band(codec, channel, 0, coef_set->band1);
+       m98095_biquad_band(codec, channel, 1, coef_set->band2);
+       snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+       mutex_unlock(&codec->mutex);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+       return 0;
+}
+
+static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       int channel = max98095_get_bq_channel(kcontrol->id.name);
+       struct max98095_cdata *cdata;
+
+       cdata = &max98095->dai[channel];
+       ucontrol->value.enumerated.item[0] = cdata->bq_sel;
+
+       return 0;
+}
+
+static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_pdata *pdata = max98095->pdata;
+       struct max98095_biquad_cfg *cfg;
+       unsigned int cfgcnt;
+       int i, j;
+       const char **t;
+       int ret;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("Biquad1 Mode",
+                       max98095->bq_enum,
+                       max98095_get_bq_enum,
+                       max98095_put_bq_enum),
+               SOC_ENUM_EXT("Biquad2 Mode",
+                       max98095->bq_enum,
+                       max98095_get_bq_enum,
+                       max98095_put_bq_enum),
+       };
+
+       cfg = pdata->bq_cfg;
+       cfgcnt = pdata->bq_cfgcnt;
+
+       /* Setup an array of texts for the biquad enum.
+        * This is based on Mark Brown's equalizer driver code.
+        */
+       max98095->bq_textcnt = 0;
+       max98095->bq_texts = NULL;
+       for (i = 0; i < cfgcnt; i++) {
+               for (j = 0; j < max98095->bq_textcnt; j++) {
+                       if (strcmp(cfg[i].name, max98095->bq_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != max98095->bq_textcnt)
+                       continue;
+
+               /* Expand the array */
+               t = krealloc(max98095->bq_texts,
+                            sizeof(char *) * (max98095->bq_textcnt + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* Store the new entry */
+               t[max98095->bq_textcnt] = cfg[i].name;
+               max98095->bq_textcnt++;
+               max98095->bq_texts = t;
+       }
+
+       /* Now point the soc_enum to .texts array items */
+       max98095->bq_enum.texts = max98095->bq_texts;
+       max98095->bq_enum.max = max98095->bq_textcnt;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret);
+}
+
+static void max98095_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_pdata *pdata = max98095->pdata;
+       u8 regval = 0;
+
+       if (!pdata) {
+               dev_dbg(codec->dev, "No platform data\n");
+               return;
+       }
+
+       /* Configure mic for analog/digital mic mode */
+       if (pdata->digmic_left_mode)
+               regval |= M98095_DIGMIC_L;
+
+       if (pdata->digmic_right_mode)
+               regval |= M98095_DIGMIC_R;
+
+       snd_soc_write(codec, M98095_087_CFG_MIC, regval);
+
+       /* Configure equalizers */
+       if (pdata->eq_cfgcnt)
+               max98095_handle_eq_pdata(codec);
+
+       /* Configure bi-quad filters */
+       if (pdata->bq_cfgcnt)
+               max98095_handle_bq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98095_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int max98095_resume(struct snd_soc_codec *codec)
+{
+       max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define max98095_suspend NULL
+#define max98095_resume NULL
+#endif
+
+static int max98095_reset(struct snd_soc_codec *codec)
+{
+       int i, ret;
+
+       /* Gracefully reset the DSP core and the codec hardware
+        * in a proper sequence */
+       ret = snd_soc_write(codec, M98095_00F_HOST_CFG, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_write(codec, M98095_097_PWR_SYS, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+               return ret;
+       }
+
+       /* Reset to hardware default for registers, as there is not
+        * a soft reset hardware control register */
+       for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
+               ret = snd_soc_write(codec, i, max98095_reg_def[i]);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Failed to reset: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int max98095_probe(struct snd_soc_codec *codec)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct max98095_cdata *cdata;
+       int ret = 0;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* reset the codec, the DSP core, and disable all interrupts */
+       max98095_reset(codec);
+
+       /* initialize private data */
+
+       max98095->sysclk = (unsigned)-1;
+       max98095->eq_textcnt = 0;
+       max98095->bq_textcnt = 0;
+
+       cdata = &max98095->dai[0];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+       cdata->bq_sel = 0;
+
+       cdata = &max98095->dai[1];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+       cdata->bq_sel = 0;
+
+       cdata = &max98095->dai[2];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+       cdata->bq_sel = 0;
+
+       max98095->lin_state = 0;
+       max98095->mic1pre = 0;
+       max98095->mic2pre = 0;
+
+       ret = snd_soc_read(codec, M98095_0FF_REV_ID);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_access;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
+
+       /* initialize registers cache to hardware default */
+       max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       snd_soc_write(codec, M98095_048_MIX_DAC_LR,
+               M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
+
+       snd_soc_write(codec, M98095_049_MIX_DAC_M,
+               M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM);
+
+       snd_soc_write(codec, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
+       snd_soc_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL);
+       snd_soc_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL);
+
+       snd_soc_write(codec, M98095_02C_DAI1_IOCFG,
+               M98095_S1NORMAL|M98095_SDATA);
+
+       snd_soc_write(codec, M98095_036_DAI2_IOCFG,
+               M98095_S2NORMAL|M98095_SDATA);
+
+       snd_soc_write(codec, M98095_040_DAI3_IOCFG,
+               M98095_S3NORMAL|M98095_SDATA);
+
+       max98095_handle_pdata(codec);
+
+       /* take the codec out of the shut down */
+       snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
+               M98095_SHDNRUN);
+
+       max98095_add_widgets(codec);
+
+err_access:
+       return ret;
+}
+
+static int max98095_remove(struct snd_soc_codec *codec)
+{
+       max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
+       .probe   = max98095_probe,
+       .remove  = max98095_remove,
+       .suspend = max98095_suspend,
+       .resume  = max98095_resume,
+       .set_bias_level = max98095_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(max98095_reg_def),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = max98095_reg_def,
+       .readable_register = max98095_readable,
+       .volatile_register = max98095_volatile,
+       .dapm_widgets     = max98095_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
+       .dapm_routes     = max98095_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(max98095_audio_map),
+};
+
+static int max98095_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct max98095_priv *max98095;
+       int ret;
+
+       max98095 = kzalloc(sizeof(struct max98095_priv), GFP_KERNEL);
+       if (max98095 == NULL)
+               return -ENOMEM;
+
+       max98095->devtype = id->driver_data;
+       i2c_set_clientdata(i2c, max98095);
+       max98095->control_data = i2c;
+       max98095->pdata = i2c->dev.platform_data;
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_max98095, &max98095_dai[0], 3);
+       if (ret < 0)
+               kfree(max98095);
+       return ret;
+}
+
+static int __devexit max98095_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+
+       return 0;
+}
+
+static const struct i2c_device_id max98095_i2c_id[] = {
+       { "max98095", MAX98095 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
+
+static struct i2c_driver max98095_i2c_driver = {
+       .driver = {
+               .name = "max98095",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max98095_i2c_probe,
+       .remove = __devexit_p(max98095_i2c_remove),
+       .id_table = max98095_i2c_id,
+};
+
+static int __init max98095_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&max98095_i2c_driver);
+       if (ret)
+               pr_err("Failed to register max98095 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(max98095_init);
+
+static void __exit max98095_exit(void)
+{
+       i2c_del_driver(&max98095_i2c_driver);
+}
+module_exit(max98095_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
+MODULE_AUTHOR("Peter Hsiang");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
new file mode 100644 (file)
index 0000000..891584a
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * max98095.h -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * 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 _MAX98095_H
+#define _MAX98095_H
+
+/*
+ * MAX98095 Registers Definition
+ */
+
+#define M98095_000_HOST_DATA                0x00
+#define M98095_001_HOST_INT_STS             0x01
+#define M98095_002_HOST_RSP_STS             0x02
+#define M98095_003_HOST_CMD_STS             0x03
+#define M98095_004_CODEC_STS                0x04
+#define M98095_005_DAI1_ALC_STS             0x05
+#define M98095_006_DAI2_ALC_STS             0x06
+#define M98095_007_JACK_AUTO_STS            0x07
+#define M98095_008_JACK_MANUAL_STS          0x08
+#define M98095_009_JACK_VBAT_STS            0x09
+#define M98095_00A_ACC_ADC_STS              0x0A
+#define M98095_00B_MIC_NG_AGC_STS           0x0B
+#define M98095_00C_SPK_L_VOLT_STS           0x0C
+#define M98095_00D_SPK_R_VOLT_STS           0x0D
+#define M98095_00E_TEMP_SENSOR_STS          0x0E
+#define M98095_00F_HOST_CFG                 0x0F
+#define M98095_010_HOST_INT_CFG             0x10
+#define M98095_011_HOST_INT_EN              0x11
+#define M98095_012_CODEC_INT_EN             0x12
+#define M98095_013_JACK_INT_EN              0x13
+#define M98095_014_JACK_INT_EN              0x14
+#define M98095_015_DEC                      0x15
+#define M98095_016_RESERVED                 0x16
+#define M98095_017_RESERVED                 0x17
+#define M98095_018_KEYCODE3                 0x18
+#define M98095_019_KEYCODE2                 0x19
+#define M98095_01A_KEYCODE1                 0x1A
+#define M98095_01B_KEYCODE0                 0x1B
+#define M98095_01C_OEMCODE1                 0x1C
+#define M98095_01D_OEMCODE0                 0x1D
+#define M98095_01E_XCFG1                    0x1E
+#define M98095_01F_XCFG2                    0x1F
+#define M98095_020_XCFG3                    0x20
+#define M98095_021_XCFG4                    0x21
+#define M98095_022_XCFG5                    0x22
+#define M98095_023_XCFG6                    0x23
+#define M98095_024_XGPIO                    0x24
+#define M98095_025_XCLKCFG                  0x25
+#define M98095_026_SYS_CLK                  0x26
+#define M98095_027_DAI1_CLKMODE             0x27
+#define M98095_028_DAI1_CLKCFG_HI           0x28
+#define M98095_029_DAI1_CLKCFG_LO           0x29
+#define M98095_02A_DAI1_FORMAT              0x2A
+#define M98095_02B_DAI1_CLOCK               0x2B
+#define M98095_02C_DAI1_IOCFG               0x2C
+#define M98095_02D_DAI1_TDM                 0x2D
+#define M98095_02E_DAI1_FILTERS             0x2E
+#define M98095_02F_DAI1_LVL1                0x2F
+#define M98095_030_DAI1_LVL2                0x30
+#define M98095_031_DAI2_CLKMODE             0x31
+#define M98095_032_DAI2_CLKCFG_HI           0x32
+#define M98095_033_DAI2_CLKCFG_LO           0x33
+#define M98095_034_DAI2_FORMAT              0x34
+#define M98095_035_DAI2_CLOCK               0x35
+#define M98095_036_DAI2_IOCFG               0x36
+#define M98095_037_DAI2_TDM                 0x37
+#define M98095_038_DAI2_FILTERS             0x38
+#define M98095_039_DAI2_LVL1                0x39
+#define M98095_03A_DAI2_LVL2                0x3A
+#define M98095_03B_DAI3_CLKMODE             0x3B
+#define M98095_03C_DAI3_CLKCFG_HI           0x3C
+#define M98095_03D_DAI3_CLKCFG_LO           0x3D
+#define M98095_03E_DAI3_FORMAT              0x3E
+#define M98095_03F_DAI3_CLOCK               0x3F
+#define M98095_040_DAI3_IOCFG               0x40
+#define M98095_041_DAI3_TDM                 0x41
+#define M98095_042_DAI3_FILTERS             0x42
+#define M98095_043_DAI3_LVL1                0x43
+#define M98095_044_DAI3_LVL2                0x44
+#define M98095_045_CFG_DSP                  0x45
+#define M98095_046_DAC_CTRL1                0x46
+#define M98095_047_DAC_CTRL2                0x47
+#define M98095_048_MIX_DAC_LR               0x48
+#define M98095_049_MIX_DAC_M                0x49
+#define M98095_04A_MIX_ADC_LEFT             0x4A
+#define M98095_04B_MIX_ADC_RIGHT            0x4B
+#define M98095_04C_MIX_HP_LEFT              0x4C
+#define M98095_04D_MIX_HP_RIGHT             0x4D
+#define M98095_04E_CFG_HP                   0x4E
+#define M98095_04F_MIX_RCV                  0x4F
+#define M98095_050_MIX_SPK_LEFT             0x50
+#define M98095_051_MIX_SPK_RIGHT            0x51
+#define M98095_052_MIX_SPK_CFG              0x52
+#define M98095_053_MIX_LINEOUT1             0x53
+#define M98095_054_MIX_LINEOUT2             0x54
+#define M98095_055_MIX_LINEOUT_CFG          0x55
+#define M98095_056_LVL_SIDETONE_DAI12       0x56
+#define M98095_057_LVL_SIDETONE_DAI3        0x57
+#define M98095_058_LVL_DAI1_PLAY            0x58
+#define M98095_059_LVL_DAI1_EQ              0x59
+#define M98095_05A_LVL_DAI2_PLAY            0x5A
+#define M98095_05B_LVL_DAI2_EQ              0x5B
+#define M98095_05C_LVL_DAI3_PLAY            0x5C
+#define M98095_05D_LVL_ADC_L                0x5D
+#define M98095_05E_LVL_ADC_R                0x5E
+#define M98095_05F_LVL_MIC1                 0x5F
+#define M98095_060_LVL_MIC2                 0x60
+#define M98095_061_LVL_LINEIN               0x61
+#define M98095_062_LVL_LINEOUT1             0x62
+#define M98095_063_LVL_LINEOUT2             0x63
+#define M98095_064_LVL_HP_L                 0x64
+#define M98095_065_LVL_HP_R                 0x65
+#define M98095_066_LVL_RCV                  0x66
+#define M98095_067_LVL_SPK_L                0x67
+#define M98095_068_LVL_SPK_R                0x68
+#define M98095_069_MICAGC_CFG               0x69
+#define M98095_06A_MICAGC_THRESH            0x6A
+#define M98095_06B_SPK_NOISEGATE            0x6B
+#define M98095_06C_DAI1_ALC1_TIME           0x6C
+#define M98095_06D_DAI1_ALC1_COMP           0x6D
+#define M98095_06E_DAI1_ALC1_EXPN           0x6E
+#define M98095_06F_DAI1_ALC1_GAIN           0x6F
+#define M98095_070_DAI1_ALC2_TIME           0x70
+#define M98095_071_DAI1_ALC2_COMP           0x71
+#define M98095_072_DAI1_ALC2_EXPN           0x72
+#define M98095_073_DAI1_ALC2_GAIN           0x73
+#define M98095_074_DAI1_ALC3_TIME           0x74
+#define M98095_075_DAI1_ALC3_COMP           0x75
+#define M98095_076_DAI1_ALC3_EXPN           0x76
+#define M98095_077_DAI1_ALC3_GAIN           0x77
+#define M98095_078_DAI2_ALC1_TIME           0x78
+#define M98095_079_DAI2_ALC1_COMP           0x79
+#define M98095_07A_DAI2_ALC1_EXPN           0x7A
+#define M98095_07B_DAI2_ALC1_GAIN           0x7B
+#define M98095_07C_DAI2_ALC2_TIME           0x7C
+#define M98095_07D_DAI2_ALC2_COMP           0x7D
+#define M98095_07E_DAI2_ALC2_EXPN           0x7E
+#define M98095_07F_DAI2_ALC2_GAIN           0x7F
+#define M98095_080_DAI2_ALC3_TIME           0x80
+#define M98095_081_DAI2_ALC3_COMP           0x81
+#define M98095_082_DAI2_ALC3_EXPN           0x82
+#define M98095_083_DAI2_ALC3_GAIN           0x83
+#define M98095_084_HP_NOISE_GATE            0x84
+#define M98095_085_AUX_ADC                  0x85
+#define M98095_086_CFG_LINE                 0x86
+#define M98095_087_CFG_MIC                  0x87
+#define M98095_088_CFG_LEVEL                0x88
+#define M98095_089_JACK_DET_AUTO            0x89
+#define M98095_08A_JACK_DET_MANUAL          0x8A
+#define M98095_08B_JACK_KEYSCAN_DBC         0x8B
+#define M98095_08C_JACK_KEYSCAN_DLY         0x8C
+#define M98095_08D_JACK_KEY_THRESH          0x8D
+#define M98095_08E_JACK_DC_SLEW             0x8E
+#define M98095_08F_JACK_TEST_CFG            0x8F
+#define M98095_090_PWR_EN_IN                0x90
+#define M98095_091_PWR_EN_OUT               0x91
+#define M98095_092_PWR_EN_OUT               0x92
+#define M98095_093_BIAS_CTRL                0x93
+#define M98095_094_PWR_DAC_21               0x94
+#define M98095_095_PWR_DAC_03               0x95
+#define M98095_096_PWR_DAC_CK               0x96
+#define M98095_097_PWR_SYS                  0x97
+
+#define M98095_0FF_REV_ID                   0xFF
+
+#define M98095_REG_CNT                      (0xFF+1)
+#define M98095_REG_MAX_CACHED               0X97
+
+/* MAX98095 Registers Bit Fields */
+
+/* M98095_00F_HOST_CFG */
+       #define M98095_SEG                      (1<<0)
+       #define M98095_XTEN                     (1<<1)
+       #define M98095_MDLLEN                   (1<<2)
+
+/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
+       #define M98095_CLKMODE_MASK             0xFF
+
+/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
+       #define M98095_DAI_MAS                  (1<<7)
+       #define M98095_DAI_WCI                  (1<<6)
+       #define M98095_DAI_BCI                  (1<<5)
+       #define M98095_DAI_DLY                  (1<<4)
+       #define M98095_DAI_TDM                  (1<<2)
+       #define M98095_DAI_FSW                  (1<<1)
+       #define M98095_DAI_WS                   (1<<0)
+
+/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
+       #define M98095_DAI_BSEL64               (1<<0)
+       #define M98095_DAI_DOSR_DIV2            (0<<5)
+       #define M98095_DAI_DOSR_DIV4            (1<<5)
+
+/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
+       #define M98095_S1NORMAL                 (1<<6)
+       #define M98095_S2NORMAL                 (2<<6)
+       #define M98095_S3NORMAL                 (3<<6)
+       #define M98095_SDATA                    (3<<0)
+
+/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
+       #define M98095_DAI_DHF                  (1<<3)
+
+/* M98095_045_DSP_CFG */
+       #define M98095_DSPNORMAL                (5<<4)
+
+/* M98095_048_MIX_DAC_LR */
+       #define M98095_DAI1L_TO_DACR            (1<<7)
+       #define M98095_DAI1R_TO_DACR            (1<<6)
+       #define M98095_DAI2M_TO_DACR            (1<<5)
+       #define M98095_DAI1L_TO_DACL            (1<<3)
+       #define M98095_DAI1R_TO_DACL            (1<<2)
+       #define M98095_DAI2M_TO_DACL            (1<<1)
+       #define M98095_DAI3M_TO_DACL            (1<<0)
+
+/* M98095_049_MIX_DAC_M */
+       #define M98095_DAI1L_TO_DACM            (1<<3)
+       #define M98095_DAI1R_TO_DACM            (1<<2)
+       #define M98095_DAI2M_TO_DACM            (1<<1)
+       #define M98095_DAI3M_TO_DACM            (1<<0)
+
+/* M98095_04E_MIX_HP_CFG */
+       #define M98095_HPNORMAL                 (3<<4)
+
+/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
+       #define M98095_MICPRE_MASK              (3<<5)
+       #define M98095_MICPRE_SHIFT             5
+
+/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
+       #define M98095_HP_MUTE                  (1<<7)
+
+/* M98095_066_LVL_RCV */
+       #define M98095_REC_MUTE                 (1<<7)
+
+/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
+       #define M98095_SP_MUTE                  (1<<7)
+
+/* M98095_087_CFG_MIC */
+       #define M98095_MICSEL_MASK              (3<<0)
+       #define M98095_DIGMIC_L                 (1<<2)
+       #define M98095_DIGMIC_R                 (1<<3)
+       #define M98095_DIGMIC2L                 (1<<4)
+       #define M98095_DIGMIC2R                 (1<<5)
+
+/* M98095_088_CFG_LEVEL */
+       #define M98095_VSEN                     (1<<6)
+       #define M98095_ZDEN                     (1<<5)
+       #define M98095_BQ2EN                    (1<<3)
+       #define M98095_BQ1EN                    (1<<2)
+       #define M98095_EQ2EN                    (1<<1)
+       #define M98095_EQ1EN                    (1<<0)
+
+/* M98095_090_PWR_EN_IN */
+       #define M98095_INEN                     (1<<7)
+       #define M98095_MB2EN                    (1<<3)
+       #define M98095_MB1EN                    (1<<2)
+       #define M98095_MBEN                     (3<<2)
+       #define M98095_ADREN                    (1<<1)
+       #define M98095_ADLEN                    (1<<0)
+
+/* M98095_091_PWR_EN_OUT */
+       #define M98095_HPLEN                    (1<<7)
+       #define M98095_HPREN                    (1<<6)
+       #define M98095_SPLEN                    (1<<5)
+       #define M98095_SPREN                    (1<<4)
+       #define M98095_RECEN                    (1<<3)
+       #define M98095_DALEN                    (1<<1)
+       #define M98095_DAREN                    (1<<0)
+
+/* M98095_092_PWR_EN_OUT */
+       #define M98095_SPK_FIXEDSPECTRUM        (0<<4)
+       #define M98095_SPK_SPREADSPECTRUM       (1<<4)
+
+/* M98095_097_PWR_SYS */
+       #define M98095_SHDNRUN                  (1<<7)
+       #define M98095_PERFMODE                 (1<<3)
+       #define M98095_HPPLYBACK                (1<<2)
+       #define M98095_PWRSV8K                  (1<<1)
+       #define M98095_PWRSV                    (1<<0)
+
+#define M98095_COEFS_PER_BAND            5
+
+#define M98095_BYTE1(w) ((w >> 8) & 0xff)
+#define M98095_BYTE0(w) (w & 0xff)
+
+/* Equalizer filter coefficients */
+#define M98095_110_DAI1_EQ_BASE             0x10
+#define M98095_142_DAI2_EQ_BASE             0x42
+
+/* Biquad filter coefficients */
+#define M98095_174_DAI1_BQ_BASE             0x74
+#define M98095_17E_DAI2_BQ_BASE             0x7E
+
+#endif
index 4d9fb279e14673344c305a938959a4c6921f7d6f..84ffdebb8a8b9c937c9ffa1323f4de40f2874e81 100644 (file)
@@ -827,8 +827,6 @@ EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 /* codec registration */
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
        pr_debug("codec_probe called\n");
 
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
@@ -879,16 +877,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
        snd_soc_add_controls(codec, sn95031_snd_controls,
                             ARRAY_SIZE(sn95031_snd_controls));
 
-       ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets,
-                               ARRAY_SIZE(sn95031_dapm_widgets));
-       if (ret)
-               pr_err("soc_dapm_new_control failed %d", ret);
-       ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map,
-                               ARRAY_SIZE(sn95031_audio_map));
-       if (ret)
-               pr_err("soc_dapm_add_routes failed %d", ret);
-
-       return ret;
+       return 0;
 }
 
 static int sn95031_codec_remove(struct snd_soc_codec *codec)
@@ -905,6 +894,10 @@ struct snd_soc_codec_driver sn95031_codec = {
        .read           = sn95031_read,
        .write          = sn95031_write,
        .set_bias_level = sn95031_set_vaud_bias,
+       .dapm_widgets   = sn95031_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(sn95031_dapm_widgets),
+       .dapm_routes    = sn95031_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(sn95031_audio_map),
 };
 
 static int __devinit sn95031_device_probe(struct platform_device *pdev)
index 4c32b54913ad0f6316de3bea2f4e03a558fe8ec6..6a1a7e705cd767ffd11365252c88b70fe7c98ad1 100644 (file)
@@ -21,7 +21,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 
-MODULE_LICENSE("GPL");
+#define DRV_NAME "spdif-dit"
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
@@ -56,7 +56,7 @@ static struct platform_driver spdif_dit_driver = {
        .probe          = spdif_dit_probe,
        .remove         = spdif_dit_remove,
        .driver         = {
-               .name   = "spdif-dit",
+               .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
 };
@@ -74,3 +74,7 @@ static void __exit dit_exit(void)
 module_init(dit_modinit);
 module_exit(dit_exit);
 
+MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
+MODULE_DESCRIPTION("SPDIF dummy codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 2727befd158ecfd253ce25072439bf6d01e43ff0..84f4ad56855601f63b582d7aaa5e29b5fce438fd 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 #include "ssm2602.h"
 
 #define SSM2602_VERSION "0.1"
 
+enum ssm2602_type {
+       SSM2602,
+       SSM2604,
+};
+
 /* codec private data */
 struct ssm2602_priv {
        unsigned int sysclk;
        enum snd_soc_control_type control_type;
-       void *control_data;
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
+
+       enum ssm2602_type type;
 };
 
 /*
@@ -60,60 +68,12 @@ struct ssm2602_priv {
  * There is no point in caching the reset register
  */
 static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
-       0x0017, 0x0017, 0x0079, 0x0079,
-       0x0000, 0x0000, 0x0000, 0x000a,
+       0x0097, 0x0097, 0x0079, 0x0079,
+       0x000a, 0x0008, 0x009f, 0x000a,
        0x0000, 0x0000
 };
 
-/*
- * read ssm2602 register cache
- */
-static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       u16 *cache = codec->reg_cache;
-       if (reg == SSM2602_RESET)
-               return 0;
-       if (reg >= SSM2602_CACHEREGNUM)
-               return -1;
-       return cache[reg];
-}
-
-/*
- * write ssm2602 register cache
- */
-static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
-       u16 reg, unsigned int value)
-{
-       u16 *cache = codec->reg_cache;
-       if (reg >= SSM2602_CACHEREGNUM)
-               return;
-       cache[reg] = value;
-}
-
-/*
- * write to the ssm2602 register space
- */
-static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int value)
-{
-       u8 data[2];
-
-       /* data is
-        *   D15..D9 ssm2602 register offset
-        *   D8...D0 register data
-        */
-       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-       data[1] = value & 0x00ff;
-
-       ssm2602_write_reg_cache(codec, reg, value);
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
-}
-
-#define ssm2602_reset(c)       ssm2602_write(c, SSM2602_RESET, 0)
+#define ssm2602_reset(c)       snd_soc_write(c, SSM2602_RESET, 0)
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
@@ -128,174 +88,187 @@ static const struct soc_enum ssm2602_enum[] = {
        SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 };
 
-static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+static const unsigned int ssm260x_outmix_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+       48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
+};
 
-SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
-       0, 127, 0),
-SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
-       7, 1, 0),
+static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
 
-SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
+       ssm260x_inpga_tlv),
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
-SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
-SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
-SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
-
-SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
-
 SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 
-SOC_ENUM("Capture Source", ssm2602_enum[0]),
-
 SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 };
 
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+       0, 127, 0, ssm260x_outmix_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+       7, 1, 0),
+SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
+       ssm260x_sidetone_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+};
+
 /* Output Mixer */
-static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
-SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 };
 
 /* Input mux */
 static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 
-static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
-SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
-       &ssm2602_output_mixer_controls[0],
-       ARRAY_SIZE(ssm2602_output_mixer_controls)),
+static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
+
 SND_SOC_DAPM_OUTPUT("LOUT"),
-SND_SOC_DAPM_OUTPUT("LHPOUT"),
 SND_SOC_DAPM_OUTPUT("ROUT"),
-SND_SOC_DAPM_OUTPUT("RHPOUT"),
-SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+       ssm260x_output_mixer_controls,
+       ARRAY_SIZE(ssm260x_output_mixer_controls)),
+
 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
-SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
 SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
 SND_SOC_DAPM_INPUT("MICIN"),
-SND_SOC_DAPM_INPUT("RLINEIN"),
-SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 
-static const struct snd_soc_dapm_route audio_conn[] = {
-       /* output mixer */
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+       ssm260x_output_mixer_controls,
+       ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
+};
+
+static const struct snd_soc_dapm_route ssm260x_routes[] = {
+       {"DAC", NULL, "Digital Core Power"},
+       {"ADC", NULL, "Digital Core Power"},
+
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+       {"ROUT", NULL, "Output Mixer"},
+       {"LOUT", NULL, "Output Mixer"},
+
+       {"Line Input", NULL, "LLINEIN"},
+       {"Line Input", NULL, "RLINEIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2602_routes[] = {
        {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 
-       /* outputs */
        {"RHPOUT", NULL, "Output Mixer"},
-       {"ROUT", NULL, "Output Mixer"},
        {"LHPOUT", NULL, "Output Mixer"},
-       {"LOUT", NULL, "Output Mixer"},
 
-       /* input mux */
        {"Input Mux", "Line", "Line Input"},
        {"Input Mux", "Mic", "Mic Bias"},
        {"ADC", NULL, "Input Mux"},
 
-       /* inputs */
-       {"Line Input", NULL, "LLINEIN"},
-       {"Line Input", NULL, "RLINEIN"},
        {"Mic Bias", NULL, "MICIN"},
 };
 
-static int ssm2602_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
-                                 ARRAY_SIZE(ssm2602_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
-
-       return 0;
-}
+static const struct snd_soc_dapm_route ssm2604_routes[] = {
+       {"ADC", NULL, "Line Input"},
+};
 
-struct _coeff_div {
+struct ssm2602_coeff {
        u32 mclk;
        u32 rate;
-       u16 fs;
-       u8 sr:4;
-       u8 bosr:1;
-       u8 usb:1;
+       u8 srate;
 };
 
-/* codec mclk clock divider coefficients */
-static const struct _coeff_div coeff_div[] = {
+#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
+
+/* codec mclk clock coefficients */
+static const struct ssm2602_coeff ssm2602_coeff_table[] = {
        /* 48k */
-       {12288000, 48000, 256, 0x0, 0x0, 0x0},
-       {18432000, 48000, 384, 0x0, 0x1, 0x0},
-       {12000000, 48000, 250, 0x0, 0x0, 0x1},
+       {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
+       {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
+       {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
 
        /* 32k */
-       {12288000, 32000, 384, 0x6, 0x0, 0x0},
-       {18432000, 32000, 576, 0x6, 0x1, 0x0},
-       {12000000, 32000, 375, 0x6, 0x0, 0x1},
+       {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
+       {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
+       {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
 
        /* 8k */
-       {12288000, 8000, 1536, 0x3, 0x0, 0x0},
-       {18432000, 8000, 2304, 0x3, 0x1, 0x0},
-       {11289600, 8000, 1408, 0xb, 0x0, 0x0},
-       {16934400, 8000, 2112, 0xb, 0x1, 0x0},
-       {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+       {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
+       {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
+       {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
+       {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
+       {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
 
        /* 96k */
-       {12288000, 96000, 128, 0x7, 0x0, 0x0},
-       {18432000, 96000, 192, 0x7, 0x1, 0x0},
-       {12000000, 96000, 125, 0x7, 0x0, 0x1},
+       {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
+       {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
+       {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
        /* 44.1k */
-       {11289600, 44100, 256, 0x8, 0x0, 0x0},
-       {16934400, 44100, 384, 0x8, 0x1, 0x0},
-       {12000000, 44100, 272, 0x8, 0x1, 0x1},
+       {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
+       {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
+       {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
 
        /* 88.2k */
-       {11289600, 88200, 128, 0xf, 0x0, 0x0},
-       {16934400, 88200, 192, 0xf, 0x1, 0x0},
-       {12000000, 88200, 136, 0xf, 0x1, 0x1},
+       {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
+       {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
+       {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
 };
 
-static inline int get_coeff(int mclk, int rate)
+static inline int ssm2602_get_coeff(int mclk, int rate)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
-               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
-                       return i;
+       for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
+               if (ssm2602_coeff_table[i].rate == rate &&
+                       ssm2602_coeff_table[i].mclk == mclk)
+                       return ssm2602_coeff_table[i].srate;
        }
-       return i;
+       return -EINVAL;
 }
 
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       u16 srate;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
-       u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
-       int i = get_coeff(ssm2602->sysclk, params_rate(params));
+       u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
+       int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 
        if (substream == ssm2602->slave_substream) {
-               dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+               dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
                return 0;
        }
 
-       /*no match is found*/
-       if (i == ARRAY_SIZE(coeff_div))
-               return -EINVAL;
-
-       srate = (coeff_div[i].sr << 2) |
-               (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+       if (srate < 0)
+               return srate;
 
-       ssm2602_write(codec, SSM2602_ACTIVE, 0);
-       ssm2602_write(codec, SSM2602_SRATE, srate);
+       snd_soc_write(codec, SSM2602_SRATE, srate);
 
        /* bit size */
        switch (params_format(params)) {
@@ -311,8 +284,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
                iface |= 0x000c;
                break;
        }
-       ssm2602_write(codec, SSM2602_IFACE, iface);
-       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+       snd_soc_write(codec, SSM2602_IFACE, iface);
        return 0;
 }
 
@@ -354,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       /* set active */
-       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
-
-       return 0;
-}
-
 static void ssm2602_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
@@ -372,25 +333,22 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
-       /* deactivate */
-       if (!codec->active)
-               ssm2602_write(codec, SSM2602_ACTIVE, 0);
-
        if (ssm2602->master_substream == substream)
                ssm2602->master_substream = ssm2602->slave_substream;
 
        ssm2602->slave_substream = NULL;
 }
 
+
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+       u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
        if (mute)
-               ssm2602_write(codec, SSM2602_APDIGI,
+               snd_soc_write(codec, SSM2602_APDIGI,
                                mute_reg | APDIGI_ENABLE_DAC_MUTE);
        else
-               ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+               snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
        return 0;
 }
 
@@ -466,30 +424,29 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* set iface */
-       ssm2602_write(codec, SSM2602_IFACE, iface);
+       snd_soc_write(codec, SSM2602_IFACE, iface);
        return 0;
 }
 
 static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+       u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
                /* vref/mid, osc on, dac unmute */
-               ssm2602_write(codec, SSM2602_PWR, reg);
+               snd_soc_write(codec, SSM2602_PWR, reg);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
                /* everything off except vref/vmid, */
-               ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+               snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
                break;
        case SND_SOC_BIAS_OFF:
                /* everything off, dac mute, inactive */
-               ssm2602_write(codec, SSM2602_ACTIVE, 0);
-               ssm2602_write(codec, SSM2602_PWR, 0xffff);
+               snd_soc_write(codec, SSM2602_PWR, 0xffff);
                break;
 
        }
@@ -506,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 
 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,
@@ -539,50 +495,87 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-       int i;
-       u8 data[2];
-       u16 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
-               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-               data[1] = cache[i] & 0x00ff;
-               codec->hw_write(codec->control_data, data, 2);
-       }
+       snd_soc_cache_sync(codec);
+
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        return 0;
 }
 
 static int ssm2602_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret, reg;
+
+       reg = snd_soc_read(codec, SSM2602_LOUT1V);
+       snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+       reg = snd_soc_read(codec, SSM2602_ROUT1V);
+       snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+
+       ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
+                       ARRAY_SIZE(ssm2602_snd_controls));
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+                       ARRAY_SIZE(ssm2602_dapm_widgets));
+       if (ret)
+               return ret;
+
+       return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
+                       ARRAY_SIZE(ssm2602_routes));
+}
+
+static int ssm2604_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+                       ARRAY_SIZE(ssm2604_dapm_widgets));
+       if (ret)
+               return ret;
+
+       return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
+                       ARRAY_SIZE(ssm2604_routes));
+}
+
+static int ssm260x_probe(struct snd_soc_codec *codec)
 {
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0, reg;
+       int ret, reg;
 
        pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 
-       codec->control_data = ssm2602->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
 
-       ssm2602_reset(codec);
+       ret = ssm2602_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
+       }
 
-       /*power on device*/
-       ssm2602_write(codec, SSM2602_ACTIVE, 0);
        /* set the update bits */
-       reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
-       ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
-       ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
-       ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
-       ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+       reg = snd_soc_read(codec, SSM2602_LINVOL);
+       snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+       reg = snd_soc_read(codec, SSM2602_RINVOL);
+       snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
        /*select Line in as default input*/
-       ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+       snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
                        APANA_ENABLE_MIC_BOOST);
-       ssm2602_write(codec, SSM2602_PWR, 0);
 
-       snd_soc_add_controls(codec, ssm2602_snd_controls,
-                               ARRAY_SIZE(ssm2602_snd_controls));
-       ssm2602_add_widgets(codec);
+       switch (ssm2602->type) {
+       case SSM2602:
+               ret = ssm2602_probe(codec);
+               break;
+       case SSM2604:
+               ret = ssm2604_probe(codec);
+               break;
+       }
 
        return ret;
 }
@@ -595,18 +588,61 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
-       .probe =        ssm2602_probe,
+       .probe =        ssm260x_probe,
        .remove =       ssm2602_remove,
        .suspend =      ssm2602_suspend,
        .resume =       ssm2602_resume,
-       .read = ssm2602_read_reg_cache,
-       .write = ssm2602_write,
        .set_bias_level = ssm2602_set_bias_level,
-       .reg_cache_size = sizeof(ssm2602_reg),
+       .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = ssm2602_reg,
+
+       .controls = ssm260x_snd_controls,
+       .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
+       .dapm_widgets = ssm260x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
+       .dapm_routes = ssm260x_routes,
+       .num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 };
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit ssm2602_spi_probe(struct spi_device *spi)
+{
+       struct ssm2602_priv *ssm2602;
+       int ret;
+
+       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       if (ssm2602 == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ssm2602);
+       ssm2602->control_type = SND_SOC_SPI;
+       ssm2602->type = SSM2602;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+       if (ret < 0)
+               kfree(ssm2602);
+       return ret;
+}
+
+static int __devexit ssm2602_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver ssm2602_spi_driver = {
+       .driver = {
+               .name   = "ssm2602",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ssm2602_spi_probe,
+       .remove         = __devexit_p(ssm2602_spi_remove),
+};
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * ssm2602 2 wire address is determined by GPIO5
@@ -614,7 +650,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
  *    low  = 0x1a
  *    high = 0x1b
  */
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
+static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
        struct ssm2602_priv *ssm2602;
@@ -625,8 +661,8 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, ssm2602);
-       ssm2602->control_data = i2c;
        ssm2602->control_type = SND_SOC_I2C;
+       ssm2602->type = id->driver_data;
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
@@ -635,7 +671,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
        return ret;
 }
 
-static int ssm2602_i2c_remove(struct i2c_client *client)
+static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
        kfree(i2c_get_clientdata(client));
@@ -643,7 +679,9 @@ static int ssm2602_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ssm2602_i2c_id[] = {
-       { "ssm2602", 0 },
+       { "ssm2602", SSM2602 },
+       { "ssm2603", SSM2602 },
+       { "ssm2604", SSM2604 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
@@ -651,11 +689,11 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
        .driver = {
-               .name = "ssm2602-codec",
+               .name = "ssm2602",
                .owner = THIS_MODULE,
        },
        .probe = ssm2602_i2c_probe,
-       .remove = ssm2602_i2c_remove,
+       .remove = __devexit_p(ssm2602_i2c_remove),
        .id_table = ssm2602_i2c_id,
 };
 #endif
@@ -664,25 +702,35 @@ static struct i2c_driver ssm2602_i2c_driver = {
 static int __init ssm2602_modinit(void)
 {
        int ret = 0;
+
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&ssm2602_spi_driver);
+       if (ret)
+               return ret;
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&ssm2602_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
-                      ret);
-       }
+       if (ret)
+               return ret;
 #endif
+
        return ret;
 }
 module_init(ssm2602_modinit);
 
 static void __exit ssm2602_exit(void)
 {
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&ssm2602_spi_driver);
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&ssm2602_i2c_driver);
 #endif
 }
 module_exit(ssm2602_exit);
 
-MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
 MODULE_AUTHOR("Cliff Cai");
 MODULE_LICENSE("GPL");
index 42a47d0f8e2551879c7d9397e1d035ecfe918f46..b98c69168036d5b84744e42621e8d0732de3796d 100644 (file)
 #define SSM2602_CACHEREGNUM    10
 
 #define SSM2602_SYSCLK 0
-#define SSM2602_DAI            0
-
-struct ssm2602_setup_data {
-       int i2c_bus;
-       unsigned short i2c_address;
-};
 
 #endif
index 54a30ef0ec8b7fec66bacd637c6cd0481cead799..33bb52f3f68306686025890cd287a52292373fec 100644 (file)
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("MICIN"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
        /* Output Mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "Playback Switch", "DAC"},
@@ -388,18 +388,6 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
        return 0;
 }
 
-static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
-       /* set up audio path interconnects */
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
@@ -676,7 +664,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, tlv320aic23_snd_controls,
                                ARRAY_SIZE(tlv320aic23_snd_controls));
-       tlv320aic23_add_widgets(codec);
 
        return 0;
 }
@@ -698,6 +685,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
        .read = tlv320aic23_read_reg_cache,
        .write = tlv320aic23_write,
        .set_bias_level = tlv320aic23_set_bias_level,
+       .dapm_widgets = tlv320aic23_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+       .dapm_routes = tlv320aic23_intercon,
+       .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 6c43c13f04304543b127fb0e4f6b5eb60d6740e4..c3d96fc8c26734855de19a32bd1747531e914df6 100644 (file)
@@ -157,7 +157,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
index 082e9d51963fd457261143aa6d50d679731c22d6..faa5e9fb1471de20e93a4fb108ffb884b0eb6f38 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
- * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
@@ -587,6 +587,9 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("Right DAC Power",
                            DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
 
+       SND_SOC_DAPM_SUPPLY("Codec Power",
+                           DAC33_PWR_CTRL, 4, 0, NULL, 0),
+
        SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
        SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
 };
@@ -619,6 +622,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        /* output */
        {"LEFT_LO", NULL, "Output Left Amplifier"},
        {"RIGHT_LO", NULL, "Output Right Amplifier"},
+
+       {"LEFT_LO", NULL, "Codec Power"},
+       {"RIGHT_LO", NULL, "Codec Power"},
 };
 
 static int dac33_add_widgets(struct snd_soc_codec *codec)
@@ -636,13 +642,10 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               if (!dac33->substream)
-                       dac33_soft_power(codec, 1);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
@@ -943,8 +946,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
        /* Write registers 0x08 and 0x09 (MSB, LSB) */
        dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
 
-       /* calib time: 128 is a nice number ;) */
-       dac33_write(codec, DAC33_CALIB_TIME, 128);
+       /* OSC calibration time */
+       dac33_write(codec, DAC33_CALIB_TIME, 96);
 
        /* adjustment treshold & step */
        dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
@@ -1655,5 +1658,5 @@ module_exit(dac33_module_exit);
 
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
index 7c318b5da4370bfb1c8cee6af5e436161068203e..ed69670747bf71c7d0b6e20a9b40109b59579986 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
- * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
index 1f1ac8110bef6378fcc4802256b272d6fa0b5a7b..239e0c461068bebb2189a0d7aaff22f472fc8d78 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Nokia Corporation
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -495,7 +495,7 @@ static void __exit tpa6130a2_exit(void)
        i2c_del_driver(&tpa6130a2_i2c_driver);
 }
 
-MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
 
index 5df49c8756b2362df2927c869b068bd8a5241ac5..417444020ba6f898a29099ecbf9c787a5be1e593 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Nokia Corporation
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 255901c4460d32c2845686a916b28829402885bd..4c336636d4f5bbc55bd3b2b979fef6ad4936ac4c 100644 (file)
@@ -960,9 +960,9 @@ static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
 
 /*
  * AFMGAIN volume control:
- * from 18 to 24 dB in 6 dB steps
+ * from -18 to 24 dB in 6 dB steps
  */
-static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0);
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
 
 /*
  * HSGAIN volume control:
@@ -1049,7 +1049,7 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 
        /* AFM gains */
        SOC_DOUBLE_TLV("Aux FM Volume",
-               TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
+               TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
 
        /* Playback gains */
        SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
index 48ffd406a71d18e2170a7b8ca69214a9de4ee8a6..a7b8f301bad39b3ef7a691273d4d3ba4bf4b9097 100644 (file)
@@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .reg_cache_step = 1,
        .read = uda134x_read_reg_cache,
        .write = uda134x_write,
-#ifdef POWER_OFF_ON_STANDBY
        .set_bias_level = uda134x_set_bias_level,
-#endif
 };
 
 static int __devinit uda134x_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
new file mode 100644 (file)
index 0000000..14d0716
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Driver for the 1250-EV1 audio I/O module
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
+SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_INPUT("WM1250 Input"),
+SND_SOC_DAPM_INPUT("WM1250 Output"),
+};
+
+static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
+       { "ADC", NULL, "WM1250 Input" },
+       { "WM1250 Output", NULL, "DAC" },
+};
+
+static struct snd_soc_dai_driver wm1250_ev1_dai = {
+       .name = "wm1250-ev1",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
+       .dapm_widgets = wm1250_ev1_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+       .dapm_routes = wm1250_ev1_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
+};
+
+static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
+                                     &wm1250_ev1_dai, 1);
+}
+
+static int __devexit wm1250_ev1_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id wm1250_ev1_i2c_id[] = {
+       { "wm1250-ev1", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
+
+static struct i2c_driver wm1250_ev1_i2c_driver = {
+       .driver = {
+               .name = "wm1250-ev1",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm1250_ev1_probe,
+       .remove =   __devexit_p(wm1250_ev1_remove),
+       .id_table = wm1250_ev1_i2c_id,
+};
+
+static int __init wm1250_ev1_modinit(void)
+{
+       int ret = 0;
+
+       ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(wm1250_ev1_modinit);
+
+static void __exit wm1250_ev1_exit(void)
+{
+       i2c_del_driver(&wm1250_ev1_i2c_driver);
+}
+module_exit(wm1250_ev1_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
+MODULE_LICENSE("GPL");
index 97c30382d3ff4fa8370c7ed7a702e476ab924fd8..a537e4af6ae74efe7950d6a1806ee3942118a834 100644 (file)
@@ -77,7 +77,7 @@ SND_SOC_DAPM_OUTPUT("ROUT"),
 SND_SOC_DAPM_OUTPUT("RHPOUT"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8711_intercon[] = {
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -89,17 +89,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"LOUT", NULL, "Output Mixer"},
 };
 
-static int wm8711_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
-                                 ARRAY_SIZE(wm8711_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 struct _coeff_div {
        u32 mclk;
        u32 rate;
@@ -398,7 +387,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8711_snd_controls,
                             ARRAY_SIZE(wm8711_snd_controls));
-       wm8711_add_widgets(codec);
 
        return ret;
 
@@ -420,6 +408,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
        .reg_cache_size = ARRAY_SIZE(wm8711_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8711_reg,
+       .dapm_widgets = wm8711_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
+       .dapm_routes = wm8711_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 736b0352d0a748a93355af25cf618d9e248cb006..86d4718d3a76055e46c1982e526855905c871ac9 100644 (file)
@@ -65,22 +65,11 @@ SND_SOC_DAPM_OUTPUT("VOUTL"),
 SND_SOC_DAPM_OUTPUT("VOUTR"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8728_intercon[] = {
        {"VOUTL", NULL, "DAC"},
        {"VOUTR", NULL, "DAC"},
 };
 
-static int wm8728_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
-                                 ARRAY_SIZE(wm8728_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
@@ -255,7 +244,6 @@ static int wm8728_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8728_snd_controls,
                                ARRAY_SIZE(wm8728_snd_controls));
-       wm8728_add_widgets(codec);
 
        return ret;
 }
@@ -275,6 +263,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
        .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8728_reg_defaults,
+       .dapm_widgets = wm8728_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
+       .dapm_routes = wm8728_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 0a67c31b2663664cdf644d4ad8ab6eb650771c7b..6dec7cee2cb4bd5fcd0cda18c7b325284a2ae039 100644 (file)
@@ -201,7 +201,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
        return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
 }
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8731_intercon[] = {
        {"DAC", NULL, "OSC", wm8731_check_osc},
        {"ADC", NULL, "OSC", wm8731_check_osc},
 
@@ -227,17 +227,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Mic Bias", NULL, "MICIN"},
 };
 
-static int wm8731_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-                                 ARRAY_SIZE(wm8731_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 struct _coeff_div {
        u32 mclk;
        u32 rate;
@@ -599,7 +588,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8731_snd_controls,
                             ARRAY_SIZE(wm8731_snd_controls));
-       wm8731_add_widgets(codec);
 
        /* Regulators will have been enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
@@ -636,6 +624,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
        .reg_cache_size = ARRAY_SIZE(wm8731_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8731_reg,
+       .dapm_widgets = wm8731_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+       .dapm_routes = wm8731_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -667,7 +659,7 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
-               .name   = "wm8731-codec",
+               .name   = "wm8731",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
@@ -711,7 +703,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
-               .name = "wm8731-codec",
+               .name = "wm8731",
                .owner = THIS_MODULE,
        },
        .probe =    wm8731_i2c_probe,
index f52b623bb692c3a0b3954e12e7e5027446a6d136..43e3d760766f5bfc31f3a11ab8acf48e9328805a 100644 (file)
@@ -382,7 +382,8 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        u16 reg;
@@ -634,6 +635,13 @@ static const struct soc_enum lsidetone_enum =
 static const struct soc_enum rsidetone_enum =
        SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
 
+static const char *adcinput_text[] = {
+       "ADC", "DMIC"
+};
+
+static const struct soc_enum adcinput_enum =
+       SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text);
+
 static const char *aif_text[] = {
        "Left", "Right"
 };
@@ -692,7 +700,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
 SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
 
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
-                WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+                WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 
@@ -767,6 +775,9 @@ static const struct snd_kcontrol_new lsidetone_mux =
 static const struct snd_kcontrol_new rsidetone_mux =
        SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
 
+static const struct snd_kcontrol_new adcinput_mux =
+       SOC_DAPM_ENUM("ADC Input", adcinput_enum);
+
 static const struct snd_kcontrol_new lcapture_mux =
        SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
 
@@ -817,6 +828,7 @@ SND_SOC_DAPM_INPUT("IN2L"),
 SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 SND_SOC_DAPM_OUTPUT("HPOUTR"),
@@ -842,6 +854,9 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
 SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
 
+SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+
 SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
 
@@ -930,7 +945,7 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
 
        { "CLK_DSP", NULL, "CLK_SYS" },
        { "Mic Bias", NULL, "CLK_SYS" },
@@ -979,6 +994,11 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Left Input PGA", NULL, "Left Input Mode Mux" },
        { "Right Input PGA", NULL, "Right Input Mode Mux" },
 
+       { "Left ADC Input", "ADC", "Left Input PGA" },
+       { "Left ADC Input", "DMIC", "DMICDAT" },
+       { "Right ADC Input", "ADC", "Right Input PGA" },
+       { "Right ADC Input", "DMIC", "DMICDAT" },
+
        { "Left Capture Mux", "Left", "ADCL" },
        { "Left Capture Mux", "Right", "ADCR" },
 
@@ -988,9 +1008,9 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIFTXL", NULL, "Left Capture Mux" },
        { "AIFTXR", NULL, "Right Capture Mux" },
 
-       { "ADCL", NULL, "Left Input PGA" },
+       { "ADCL", NULL, "Left ADC Input" },
        { "ADCL", NULL, "CLK_DSP" },
-       { "ADCR", NULL, "Right Input PGA" },
+       { "ADCR", NULL, "Right ADC Input" },
        { "ADCR", NULL, "CLK_DSP" },
 
        { "Left Playback Mux", "Left", "AIFRXL" },
@@ -1087,17 +1107,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
-static int wm8903_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
-                                 ARRAY_SIZE(wm8903_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
@@ -2028,7 +2037,6 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8903_snd_controls,
                                ARRAY_SIZE(wm8903_snd_controls));
-       wm8903_add_widgets(codec);
 
        wm8903_init_gpio(codec);
 
@@ -2054,6 +2062,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
        .reg_cache_default = wm8903_reg_defaults,
        .volatile_register = wm8903_volatile_register,
        .seq_notifier = wm8903_seq_notifier,
+       .dapm_widgets = wm8903_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
+       .dapm_routes = wm8903_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
new file mode 100644 (file)
index 0000000..ccc9bd8
--- /dev/null
@@ -0,0 +1,2931 @@
+/*
+ * wm8915.c - WM8915 audio codec interface
+ *
+ * Copyright 2011 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/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8915.h>
+#include "wm8915.h"
+
+#define WM8915_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8915_NUM_SUPPLIES 6
+static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD1",
+       "AVDD2",
+       "CPVDD",
+       "MICVDD",
+};
+
+struct wm8915_priv {
+       struct snd_soc_codec *codec;
+
+       int ldo1ena;
+
+       int sysclk;
+
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       struct completion fll_lock;
+
+       u16 dcs_pending;
+       struct completion dcs_done;
+
+       u16 hpout_ena;
+       u16 hpout_pending;
+
+       struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8915_NUM_SUPPLIES];
+
+       struct wm8915_pdata pdata;
+
+       int rx_rate[WM8915_AIFS];
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[2];
+       struct soc_enum retune_mobile_enum;
+
+       struct snd_soc_jack *jack;
+       bool detecting;
+       bool jack_mic;
+       wm8915_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8915_REGULATOR_EVENT(n) \
+static int wm8915_regulator_event_##n(struct notifier_block *nb, \
+                                   unsigned long event, void *data)    \
+{ \
+       struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8915->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8915_REGULATOR_EVENT(0)
+WM8915_REGULATOR_EVENT(1)
+WM8915_REGULATOR_EVENT(2)
+WM8915_REGULATOR_EVENT(3)
+WM8915_REGULATOR_EVENT(4)
+WM8915_REGULATOR_EVENT(5)
+
+static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
+       [WM8915_SOFTWARE_RESET] = 0x8915,
+       [WM8915_POWER_MANAGEMENT_7] = 0x10,
+       [WM8915_DAC1_HPOUT1_VOLUME] = 0x88,
+       [WM8915_DAC2_HPOUT2_VOLUME] = 0x88,
+       [WM8915_DAC1_LEFT_VOLUME] = 0x2c0,
+       [WM8915_DAC1_RIGHT_VOLUME] = 0x2c0,
+       [WM8915_DAC2_LEFT_VOLUME] = 0x2c0,
+       [WM8915_DAC2_RIGHT_VOLUME] = 0x2c0,
+       [WM8915_OUTPUT1_LEFT_VOLUME] = 0x80,
+       [WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80,
+       [WM8915_OUTPUT2_LEFT_VOLUME] = 0x80,
+       [WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80,
+       [WM8915_MICBIAS_1] = 0x39,
+       [WM8915_MICBIAS_2] = 0x39,
+       [WM8915_LDO_1] = 0x3,
+       [WM8915_LDO_2] = 0x13,
+       [WM8915_ACCESSORY_DETECT_MODE_1] = 0x4,
+       [WM8915_HEADPHONE_DETECT_1] = 0x20,
+       [WM8915_MIC_DETECT_1] = 0x7600,
+       [WM8915_MIC_DETECT_2] = 0xbf,
+       [WM8915_CHARGE_PUMP_1] = 0x1f25,
+       [WM8915_CHARGE_PUMP_2] = 0xab19,
+       [WM8915_DC_SERVO_5] = 0x2a2a,
+       [WM8915_CONTROL_INTERFACE_1] = 0x8004,
+       [WM8915_CLOCKING_1] = 0x10,
+       [WM8915_AIF_RATE] = 0x83,
+       [WM8915_FLL_CONTROL_4] = 0x5dc0,
+       [WM8915_FLL_CONTROL_5] = 0xc84,
+       [WM8915_FLL_EFS_2] = 0x2,
+       [WM8915_AIF1_TX_LRCLK_1] = 0x80,
+       [WM8915_AIF1_TX_LRCLK_2] = 0x8,
+       [WM8915_AIF1_RX_LRCLK_1] = 0x80,
+       [WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
+       [WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818,
+       [WM8915_AIF1TX_TEST] = 0x7,
+       [WM8915_AIF2_TX_LRCLK_1] = 0x80,
+       [WM8915_AIF2_TX_LRCLK_2] = 0x8,
+       [WM8915_AIF2_RX_LRCLK_1] = 0x80,
+       [WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
+       [WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818,
+       [WM8915_AIF2TX_TEST] = 0x1,
+       [WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0,
+       [WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0,
+       [WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0,
+       [WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0,
+       [WM8915_DSP1_TX_FILTERS] = 0x2000,
+       [WM8915_DSP1_RX_FILTERS_1] = 0x200,
+       [WM8915_DSP1_RX_FILTERS_2] = 0x10,
+       [WM8915_DSP1_DRC_1] = 0x98,
+       [WM8915_DSP1_DRC_2] = 0x845,
+       [WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318,
+       [WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300,
+       [WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca,
+       [WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400,
+       [WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
+       [WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
+       [WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145,
+       [WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75,
+       [WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
+       [WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
+       [WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373,
+       [WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54,
+       [WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558,
+       [WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e,
+       [WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829,
+       [WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
+       [WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
+       [WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564,
+       [WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559,
+       [WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
+       [WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0,
+       [WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0,
+       [WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0,
+       [WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0,
+       [WM8915_DSP2_TX_FILTERS] = 0x2000,
+       [WM8915_DSP2_RX_FILTERS_1] = 0x200,
+       [WM8915_DSP2_RX_FILTERS_2] = 0x10,
+       [WM8915_DSP2_DRC_1] = 0x98,
+       [WM8915_DSP2_DRC_2] = 0x845,
+       [WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318,
+       [WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300,
+       [WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca,
+       [WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400,
+       [WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
+       [WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
+       [WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145,
+       [WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75,
+       [WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
+       [WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
+       [WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373,
+       [WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54,
+       [WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558,
+       [WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e,
+       [WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829,
+       [WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
+       [WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
+       [WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564,
+       [WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559,
+       [WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
+       [WM8915_OVERSAMPLING] = 0xd,
+       [WM8915_SIDETONE] = 0x1040,
+       [WM8915_GPIO_1] = 0xa101,
+       [WM8915_GPIO_2] = 0xa101,
+       [WM8915_GPIO_3] = 0xa101,
+       [WM8915_GPIO_4] = 0xa101,
+       [WM8915_GPIO_5] = 0xa101,
+       [WM8915_PULL_CONTROL_2] = 0x140,
+       [WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f,
+       [WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
+       [WM8915_RIGHT_PDM_SPEAKER] = 0x1,
+       [WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
+       [WM8915_PDM_SPEAKER_VOLUME] = 0x66,
+       [WM8915_WRITE_SEQUENCER_0] = 0x1,
+       [WM8915_WRITE_SEQUENCER_1] = 0x1,
+       [WM8915_WRITE_SEQUENCER_3] = 0x6,
+       [WM8915_WRITE_SEQUENCER_4] = 0x40,
+       [WM8915_WRITE_SEQUENCER_5] = 0x1,
+       [WM8915_WRITE_SEQUENCER_6] = 0xf,
+       [WM8915_WRITE_SEQUENCER_7] = 0x6,
+       [WM8915_WRITE_SEQUENCER_8] = 0x1,
+       [WM8915_WRITE_SEQUENCER_9] = 0x3,
+       [WM8915_WRITE_SEQUENCER_10] = 0x104,
+       [WM8915_WRITE_SEQUENCER_12] = 0x60,
+       [WM8915_WRITE_SEQUENCER_13] = 0x11,
+       [WM8915_WRITE_SEQUENCER_14] = 0x401,
+       [WM8915_WRITE_SEQUENCER_16] = 0x50,
+       [WM8915_WRITE_SEQUENCER_17] = 0x3,
+       [WM8915_WRITE_SEQUENCER_18] = 0x100,
+       [WM8915_WRITE_SEQUENCER_20] = 0x51,
+       [WM8915_WRITE_SEQUENCER_21] = 0x3,
+       [WM8915_WRITE_SEQUENCER_22] = 0x104,
+       [WM8915_WRITE_SEQUENCER_23] = 0xa,
+       [WM8915_WRITE_SEQUENCER_24] = 0x60,
+       [WM8915_WRITE_SEQUENCER_25] = 0x3b,
+       [WM8915_WRITE_SEQUENCER_26] = 0x502,
+       [WM8915_WRITE_SEQUENCER_27] = 0x100,
+       [WM8915_WRITE_SEQUENCER_28] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_32] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_36] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_40] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_44] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_48] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_52] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_56] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_60] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_64] = 0x1,
+       [WM8915_WRITE_SEQUENCER_65] = 0x1,
+       [WM8915_WRITE_SEQUENCER_67] = 0x6,
+       [WM8915_WRITE_SEQUENCER_68] = 0x40,
+       [WM8915_WRITE_SEQUENCER_69] = 0x1,
+       [WM8915_WRITE_SEQUENCER_70] = 0xf,
+       [WM8915_WRITE_SEQUENCER_71] = 0x6,
+       [WM8915_WRITE_SEQUENCER_72] = 0x1,
+       [WM8915_WRITE_SEQUENCER_73] = 0x3,
+       [WM8915_WRITE_SEQUENCER_74] = 0x104,
+       [WM8915_WRITE_SEQUENCER_76] = 0x60,
+       [WM8915_WRITE_SEQUENCER_77] = 0x11,
+       [WM8915_WRITE_SEQUENCER_78] = 0x401,
+       [WM8915_WRITE_SEQUENCER_80] = 0x50,
+       [WM8915_WRITE_SEQUENCER_81] = 0x3,
+       [WM8915_WRITE_SEQUENCER_82] = 0x100,
+       [WM8915_WRITE_SEQUENCER_84] = 0x60,
+       [WM8915_WRITE_SEQUENCER_85] = 0x3b,
+       [WM8915_WRITE_SEQUENCER_86] = 0x502,
+       [WM8915_WRITE_SEQUENCER_87] = 0x100,
+       [WM8915_WRITE_SEQUENCER_88] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_92] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_96] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_100] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_104] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_108] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_112] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_116] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_120] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_124] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_128] = 0x1,
+       [WM8915_WRITE_SEQUENCER_129] = 0x1,
+       [WM8915_WRITE_SEQUENCER_131] = 0x6,
+       [WM8915_WRITE_SEQUENCER_132] = 0x40,
+       [WM8915_WRITE_SEQUENCER_133] = 0x1,
+       [WM8915_WRITE_SEQUENCER_134] = 0xf,
+       [WM8915_WRITE_SEQUENCER_135] = 0x6,
+       [WM8915_WRITE_SEQUENCER_136] = 0x1,
+       [WM8915_WRITE_SEQUENCER_137] = 0x3,
+       [WM8915_WRITE_SEQUENCER_138] = 0x106,
+       [WM8915_WRITE_SEQUENCER_140] = 0x61,
+       [WM8915_WRITE_SEQUENCER_141] = 0x11,
+       [WM8915_WRITE_SEQUENCER_142] = 0x401,
+       [WM8915_WRITE_SEQUENCER_144] = 0x50,
+       [WM8915_WRITE_SEQUENCER_145] = 0x3,
+       [WM8915_WRITE_SEQUENCER_146] = 0x102,
+       [WM8915_WRITE_SEQUENCER_148] = 0x51,
+       [WM8915_WRITE_SEQUENCER_149] = 0x3,
+       [WM8915_WRITE_SEQUENCER_150] = 0x106,
+       [WM8915_WRITE_SEQUENCER_151] = 0xa,
+       [WM8915_WRITE_SEQUENCER_152] = 0x61,
+       [WM8915_WRITE_SEQUENCER_153] = 0x3b,
+       [WM8915_WRITE_SEQUENCER_154] = 0x502,
+       [WM8915_WRITE_SEQUENCER_155] = 0x100,
+       [WM8915_WRITE_SEQUENCER_156] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_160] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_164] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_168] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_172] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_176] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_180] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_184] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_188] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_192] = 0x1,
+       [WM8915_WRITE_SEQUENCER_193] = 0x1,
+       [WM8915_WRITE_SEQUENCER_195] = 0x6,
+       [WM8915_WRITE_SEQUENCER_196] = 0x40,
+       [WM8915_WRITE_SEQUENCER_197] = 0x1,
+       [WM8915_WRITE_SEQUENCER_198] = 0xf,
+       [WM8915_WRITE_SEQUENCER_199] = 0x6,
+       [WM8915_WRITE_SEQUENCER_200] = 0x1,
+       [WM8915_WRITE_SEQUENCER_201] = 0x3,
+       [WM8915_WRITE_SEQUENCER_202] = 0x106,
+       [WM8915_WRITE_SEQUENCER_204] = 0x61,
+       [WM8915_WRITE_SEQUENCER_205] = 0x11,
+       [WM8915_WRITE_SEQUENCER_206] = 0x401,
+       [WM8915_WRITE_SEQUENCER_208] = 0x50,
+       [WM8915_WRITE_SEQUENCER_209] = 0x3,
+       [WM8915_WRITE_SEQUENCER_210] = 0x102,
+       [WM8915_WRITE_SEQUENCER_212] = 0x61,
+       [WM8915_WRITE_SEQUENCER_213] = 0x3b,
+       [WM8915_WRITE_SEQUENCER_214] = 0x502,
+       [WM8915_WRITE_SEQUENCER_215] = 0x100,
+       [WM8915_WRITE_SEQUENCER_216] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_220] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_224] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_228] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_232] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_236] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_240] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_244] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_248] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_252] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_256] = 0x60,
+       [WM8915_WRITE_SEQUENCER_258] = 0x601,
+       [WM8915_WRITE_SEQUENCER_260] = 0x50,
+       [WM8915_WRITE_SEQUENCER_262] = 0x100,
+       [WM8915_WRITE_SEQUENCER_264] = 0x1,
+       [WM8915_WRITE_SEQUENCER_266] = 0x104,
+       [WM8915_WRITE_SEQUENCER_267] = 0x100,
+       [WM8915_WRITE_SEQUENCER_268] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_272] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_276] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_280] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_284] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_288] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_292] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_296] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_300] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_304] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_308] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_312] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_316] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_320] = 0x61,
+       [WM8915_WRITE_SEQUENCER_322] = 0x601,
+       [WM8915_WRITE_SEQUENCER_324] = 0x50,
+       [WM8915_WRITE_SEQUENCER_326] = 0x102,
+       [WM8915_WRITE_SEQUENCER_328] = 0x1,
+       [WM8915_WRITE_SEQUENCER_330] = 0x106,
+       [WM8915_WRITE_SEQUENCER_331] = 0x100,
+       [WM8915_WRITE_SEQUENCER_332] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_336] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_340] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_344] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_348] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_352] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_356] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_360] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_364] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_368] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_372] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_376] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_380] = 0x2fff,
+       [WM8915_WRITE_SEQUENCER_384] = 0x60,
+       [WM8915_WRITE_SEQUENCER_386] = 0x601,
+       [WM8915_WRITE_SEQUENCER_388] = 0x61,
+       [WM8915_WRITE_SEQUENCER_390] = 0x601,
+       [WM8915_WRITE_SEQUENCER_392] = 0x50,
+       [WM8915_WRITE_SEQUENCER_394] = 0x300,
+       [WM8915_WRITE_SEQUENCER_396] = 0x1,
+       [WM8915_WRITE_SEQUENCER_398] = 0x304,
+       [WM8915_WRITE_SEQUENCER_400] = 0x40,
+       [WM8915_WRITE_SEQUENCER_402] = 0xf,
+       [WM8915_WRITE_SEQUENCER_404] = 0x1,
+       [WM8915_WRITE_SEQUENCER_407] = 0x100,
+};
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *sidetone_hpf_text[] = {
+       "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+       SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+       "HiFi", "Custom", "Voice"
+};
+
+static const struct soc_enum dsp1tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const struct soc_enum dsp2tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+       "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum dsp1tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static const struct soc_enum dsp2tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct wm8915_pdata *pdata = &wm8915->pdata;
+       int base, best, best_val, save, i, cfg, iface;
+
+       if (!wm8915->num_retune_mobile_texts)
+               return;
+
+       switch (block) {
+       case 0:
+               base = WM8915_DSP1_RX_EQ_GAINS_1;
+               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+                   WM8915_DSP1RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       case 1:
+               base = WM8915_DSP1_RX_EQ_GAINS_2;
+               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+                   WM8915_DSP2RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       default:
+               return;
+       }
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8915->retune_mobile_cfg[block];
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8915->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8915->rx_rate[iface]) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8915->rx_rate[iface]);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+               block,
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8915->rx_rate[iface]);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, base);
+       save &= WM8915_DSP1RX_EQ_ENA;
+
+       for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+               snd_soc_update_bits(codec, base + i, 0xffff,
+                                   pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8915_get_retune_mobile_block(const char *name)
+{
+       if (strcmp(name, "DSP1 EQ Mode") == 0)
+               return 0;
+       if (strcmp(name, "DSP2 EQ Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct wm8915_pdata *pdata = &wm8915->pdata;
+       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+       int value = ucontrol->value.integer.value[0];
+
+       if (block < 0)
+               return block;
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8915->retune_mobile_cfg[block] = value;
+
+       wm8915_set_retune_mobile(codec, block);
+
+       return 0;
+}
+
+static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+
+       ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block];
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8915_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME,
+                WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME,
+            WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME,
+                WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME,
+                WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME,
+                WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME,
+                WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME,
+                WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME,
+            WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME,
+                WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME,
+            WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME,
+                WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8915_OUTPUT1_LEFT_VOLUME,
+            WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME,
+                WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8915_OUTPUT2_LEFT_VOLUME,
+            WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+              spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER,
+            WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER,
+            WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8915_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(5);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+       /* Record which outputs we enabled */
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               wm8915->hpout_pending &= ~w->shift;
+               break;
+       case SND_SOC_DAPM_PRE_PMU:
+               wm8915->hpout_pending |= w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+{
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+       unsigned long timeout = 200;
+
+       snd_soc_write(codec, WM8915_DC_SERVO_2, mask);
+
+       /* Use the interrupt if possible */
+       do {
+               if (i2c->irq) {
+                       timeout = wait_for_completion_timeout(&wm8915->dcs_done,
+                                                             msecs_to_jiffies(200));
+                       if (timeout == 0)
+                               dev_err(codec->dev, "DC servo timed out\n");
+
+               } else {
+                       msleep(1);
+                       if (--i) {
+                               timeout = 0;
+                               break;
+                       }
+               }
+
+               ret = snd_soc_read(codec, WM8915_DC_SERVO_2);
+               dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+       } while (ret & mask);
+
+       if (timeout == 0)
+               dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+       else
+               dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm,
+                               enum snd_soc_dapm_type event, int subseq)
+{
+       struct snd_soc_codec *codec = container_of(dapm,
+                                                  struct snd_soc_codec, dapm);
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       u16 val, mask;
+
+       /* Complete any pending DC servo starts */
+       if (wm8915->dcs_pending) {
+               dev_dbg(codec->dev, "Starting DC servo for %x\n",
+                       wm8915->dcs_pending);
+
+               /* Trigger a startup sequence */
+               wait_for_dc_servo(codec, wm8915->dcs_pending
+                                        << WM8915_DCS_TRIG_STARTUP_0_SHIFT);
+
+               wm8915->dcs_pending = 0;
+       }
+
+       if (wm8915->hpout_pending != wm8915->hpout_ena) {
+               dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+                       wm8915->hpout_ena, wm8915->hpout_pending);
+
+               val = 0;
+               mask = 0;
+               if (wm8915->hpout_pending & HPOUT1L) {
+                       val |= WM8915_HPOUT1L_RMV_SHORT;
+                       mask |= WM8915_HPOUT1L_RMV_SHORT;
+               } else {
+                       mask |= WM8915_HPOUT1L_RMV_SHORT |
+                               WM8915_HPOUT1L_OUTP |
+                               WM8915_HPOUT1L_DLY;
+               }
+
+               if (wm8915->hpout_pending & HPOUT1R) {
+                       val |= WM8915_HPOUT1R_RMV_SHORT;
+                       mask |= WM8915_HPOUT1R_RMV_SHORT;
+               } else {
+                       mask |= WM8915_HPOUT1R_RMV_SHORT |
+                               WM8915_HPOUT1R_OUTP |
+                               WM8915_HPOUT1R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val);
+
+               val = 0;
+               mask = 0;
+               if (wm8915->hpout_pending & HPOUT2L) {
+                       val |= WM8915_HPOUT2L_RMV_SHORT;
+                       mask |= WM8915_HPOUT2L_RMV_SHORT;
+               } else {
+                       mask |= WM8915_HPOUT2L_RMV_SHORT |
+                               WM8915_HPOUT2L_OUTP |
+                               WM8915_HPOUT2L_DLY;
+               }
+
+               if (wm8915->hpout_pending & HPOUT2R) {
+                       val |= WM8915_HPOUT2R_RMV_SHORT;
+                       mask |= WM8915_HPOUT2R_RMV_SHORT;
+               } else {
+                       mask |= WM8915_HPOUT2R_RMV_SHORT |
+                               WM8915_HPOUT2R_OUTP |
+                               WM8915_HPOUT2R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val);
+
+               wm8915->hpout_ena = wm8915->hpout_pending;
+       }
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+                    struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               wm8915->dcs_pending |= 1 << w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const char *sidetone_text[] = {
+       "IN1", "IN2",
+};
+
+static const struct soc_enum left_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+       SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static const struct soc_enum right_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+       SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const struct soc_enum spkl_enum =
+       SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+       SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static const struct soc_enum spkr_enum =
+       SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+       SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+       "AIF1", "AIF2"
+};
+
+static const struct soc_enum dsp1rx_enum =
+       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+       SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+        "AIF2", "AIF1"
+};
+
+static const struct soc_enum dsp2rx_enum =
+       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+       SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+       "DSP2", "DSP1", "AIF1"
+};
+
+static const struct soc_enum aif2tx_enum =
+       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+       SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+       "ADC", "DMIC1", "DMIC2"
+};
+
+static const struct soc_enum in1_enum =
+       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+       SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static const struct soc_enum in2_enum =
+       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+       SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event,
+                     SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+
+SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0,
+                  dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0,
+                  dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0,
+                  dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0,
+                  dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+                   WM8915_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+                   WM8915_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+                   WM8915_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+                   WM8915_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
+                   WM8915_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
+                   WM8915_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
+                   WM8915_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
+                   WM8915_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
+                   WM8915_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
+                   WM8915_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
+                    WM8915_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
+                    WM8915_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
+                    WM8915_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
+                    WM8915_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
+                    WM8915_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
+                    WM8915_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
+       { "AIFCLK", NULL, "SYSCLK" },
+       { "SYSDSPCLK", NULL, "SYSCLK" },
+       { "Charge Pump", NULL, "SYSCLK" },
+
+       { "MICB1", NULL, "LDO2" },
+       { "MICB2", NULL, "LDO2" },
+
+       { "IN1L PGA", NULL, "IN2LN" },
+       { "IN1L PGA", NULL, "IN2LP" },
+       { "IN1L PGA", NULL, "IN1LN" },
+       { "IN1L PGA", NULL, "IN1LP" },
+
+       { "IN1R PGA", NULL, "IN2RN" },
+       { "IN1R PGA", NULL, "IN2RP" },
+       { "IN1R PGA", NULL, "IN1RN" },
+       { "IN1R PGA", NULL, "IN1RP" },
+
+       { "ADCL", NULL, "IN1L PGA" },
+
+       { "ADCR", NULL, "IN1R PGA" },
+
+       { "DMIC1L", NULL, "DMIC1DAT" },
+       { "DMIC1R", NULL, "DMIC1DAT" },
+       { "DMIC2L", NULL, "DMIC2DAT" },
+       { "DMIC2R", NULL, "DMIC2DAT" },
+
+       { "DMIC2L", NULL, "DMIC2" },
+       { "DMIC2R", NULL, "DMIC2" },
+       { "DMIC1L", NULL, "DMIC1" },
+       { "DMIC1R", NULL, "DMIC1" },
+
+       { "IN1L Mux", "ADC", "ADCL" },
+       { "IN1L Mux", "DMIC1", "DMIC1L" },
+       { "IN1L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN1R Mux", "ADC", "ADCR" },
+       { "IN1R Mux", "DMIC1", "DMIC1R" },
+       { "IN1R Mux", "DMIC2", "DMIC2R" },
+
+       { "IN2L Mux", "ADC", "ADCL" },
+       { "IN2L Mux", "DMIC1", "DMIC1L" },
+       { "IN2L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN2R Mux", "ADC", "ADCR" },
+       { "IN2R Mux", "DMIC1", "DMIC1R" },
+       { "IN2R Mux", "DMIC2", "DMIC2R" },
+
+       { "Left Sidetone", "IN1", "IN1L Mux" },
+       { "Left Sidetone", "IN2", "IN2L Mux" },
+
+       { "Right Sidetone", "IN1", "IN1R Mux" },
+       { "Right Sidetone", "IN2", "IN2R Mux" },
+
+       { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+       { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+       { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+       { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+       { "AIF1TX0", NULL, "DSP1TXL" },
+       { "AIF1TX1", NULL, "DSP1TXR" },
+       { "AIF1TX2", NULL, "DSP2TXL" },
+       { "AIF1TX3", NULL, "DSP2TXR" },
+       { "AIF1TX4", NULL, "AIF2RX0" },
+       { "AIF1TX5", NULL, "AIF2RX1" },
+
+       { "AIF1RX0", NULL, "AIFCLK" },
+       { "AIF1RX1", NULL, "AIFCLK" },
+       { "AIF1RX2", NULL, "AIFCLK" },
+       { "AIF1RX3", NULL, "AIFCLK" },
+       { "AIF1RX4", NULL, "AIFCLK" },
+       { "AIF1RX5", NULL, "AIFCLK" },
+
+       { "AIF2RX0", NULL, "AIFCLK" },
+       { "AIF2RX1", NULL, "AIFCLK" },
+
+       { "DSP1RXL", NULL, "SYSDSPCLK" },
+       { "DSP1RXR", NULL, "SYSDSPCLK" },
+       { "DSP2RXL", NULL, "SYSDSPCLK" },
+       { "DSP2RXR", NULL, "SYSDSPCLK" },
+       { "DSP1TXL", NULL, "SYSDSPCLK" },
+       { "DSP1TXR", NULL, "SYSDSPCLK" },
+       { "DSP2TXL", NULL, "SYSDSPCLK" },
+       { "DSP2TXR", NULL, "SYSDSPCLK" },
+
+       { "AIF1RXA", NULL, "AIF1RX0" },
+       { "AIF1RXA", NULL, "AIF1RX1" },
+       { "AIF1RXB", NULL, "AIF1RX2" },
+       { "AIF1RXB", NULL, "AIF1RX3" },
+       { "AIF1RXC", NULL, "AIF1RX4" },
+       { "AIF1RXC", NULL, "AIF1RX5" },
+
+       { "AIF2RX", NULL, "AIF2RX0" },
+       { "AIF2RX", NULL, "AIF2RX1" },
+
+       { "AIF2TX", "DSP2", "DSP2TX" },
+       { "AIF2TX", "DSP1", "DSP1RX" },
+       { "AIF2TX", "AIF1", "AIF1RXC" },
+
+       { "DSP1RXL", NULL, "DSP1RX" },
+       { "DSP1RXR", NULL, "DSP1RX" },
+       { "DSP2RXL", NULL, "DSP2RX" },
+       { "DSP2RXR", NULL, "DSP2RX" },
+
+       { "DSP2TX", NULL, "DSP2TXL" },
+       { "DSP2TX", NULL, "DSP2TXR" },
+
+       { "DSP1RX", "AIF1", "AIF1RXA" },
+       { "DSP1RX", "AIF2", "AIF2RX" },
+
+       { "DSP2RX", "AIF1", "AIF1RXB" },
+       { "DSP2RX", "AIF2", "AIF2RX" },
+
+       { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC2L", NULL, "DAC2L Mixer" },
+       { "DAC2R", NULL, "DAC2R Mixer" },
+
+       { "HPOUT2L PGA", NULL, "Charge Pump" },
+       { "HPOUT2L PGA", NULL, "DAC2L" },
+       { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+       { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+       { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
+       { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+
+       { "HPOUT2R PGA", NULL, "Charge Pump" },
+       { "HPOUT2R PGA", NULL, "DAC2R" },
+       { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+       { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+       { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
+       { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+
+       { "HPOUT1L PGA", NULL, "Charge Pump" },
+       { "HPOUT1L PGA", NULL, "DAC1L" },
+       { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+       { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+       { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
+       { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+
+       { "HPOUT1R PGA", NULL, "Charge Pump" },
+       { "HPOUT1R PGA", NULL, "DAC1R" },
+       { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+       { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+       { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
+       { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+
+       { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+       { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+       { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+       { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+       { "SPKL", "DAC1L", "DAC1L" },
+       { "SPKL", "DAC1R", "DAC1R" },
+       { "SPKL", "DAC2L", "DAC2L" },
+       { "SPKL", "DAC2R", "DAC2R" },
+
+       { "SPKR", "DAC1L", "DAC1L" },
+       { "SPKR", "DAC1R", "DAC1R" },
+       { "SPKR", "DAC2L", "DAC2L" },
+       { "SPKR", "DAC2R", "DAC2R" },
+
+       { "SPKL PGA", NULL, "SPKL" },
+       { "SPKR PGA", NULL, "SPKR" },
+
+       { "SPKDAT", NULL, "SPKL PGA" },
+       { "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static int wm8915_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       /* Due to the sparseness of the register map the compiler
+        * output from an explicit switch statement ends up being much
+        * more efficient than a table.
+        */
+       switch (reg) {
+       case WM8915_SOFTWARE_RESET:
+       case WM8915_POWER_MANAGEMENT_1:
+       case WM8915_POWER_MANAGEMENT_2:
+       case WM8915_POWER_MANAGEMENT_3:
+       case WM8915_POWER_MANAGEMENT_4:
+       case WM8915_POWER_MANAGEMENT_5:
+       case WM8915_POWER_MANAGEMENT_6:
+       case WM8915_POWER_MANAGEMENT_7:
+       case WM8915_POWER_MANAGEMENT_8:
+       case WM8915_LEFT_LINE_INPUT_VOLUME:
+       case WM8915_RIGHT_LINE_INPUT_VOLUME:
+       case WM8915_LINE_INPUT_CONTROL:
+       case WM8915_DAC1_HPOUT1_VOLUME:
+       case WM8915_DAC2_HPOUT2_VOLUME:
+       case WM8915_DAC1_LEFT_VOLUME:
+       case WM8915_DAC1_RIGHT_VOLUME:
+       case WM8915_DAC2_LEFT_VOLUME:
+       case WM8915_DAC2_RIGHT_VOLUME:
+       case WM8915_OUTPUT1_LEFT_VOLUME:
+       case WM8915_OUTPUT1_RIGHT_VOLUME:
+       case WM8915_OUTPUT2_LEFT_VOLUME:
+       case WM8915_OUTPUT2_RIGHT_VOLUME:
+       case WM8915_MICBIAS_1:
+       case WM8915_MICBIAS_2:
+       case WM8915_LDO_1:
+       case WM8915_LDO_2:
+       case WM8915_ACCESSORY_DETECT_MODE_1:
+       case WM8915_ACCESSORY_DETECT_MODE_2:
+       case WM8915_HEADPHONE_DETECT_1:
+       case WM8915_HEADPHONE_DETECT_2:
+       case WM8915_MIC_DETECT_1:
+       case WM8915_MIC_DETECT_2:
+       case WM8915_MIC_DETECT_3:
+       case WM8915_CHARGE_PUMP_1:
+       case WM8915_CHARGE_PUMP_2:
+       case WM8915_DC_SERVO_1:
+       case WM8915_DC_SERVO_2:
+       case WM8915_DC_SERVO_3:
+       case WM8915_DC_SERVO_5:
+       case WM8915_DC_SERVO_6:
+       case WM8915_DC_SERVO_7:
+       case WM8915_DC_SERVO_READBACK_0:
+       case WM8915_ANALOGUE_HP_1:
+       case WM8915_ANALOGUE_HP_2:
+       case WM8915_CHIP_REVISION:
+       case WM8915_CONTROL_INTERFACE_1:
+       case WM8915_WRITE_SEQUENCER_CTRL_1:
+       case WM8915_WRITE_SEQUENCER_CTRL_2:
+       case WM8915_AIF_CLOCKING_1:
+       case WM8915_AIF_CLOCKING_2:
+       case WM8915_CLOCKING_1:
+       case WM8915_CLOCKING_2:
+       case WM8915_AIF_RATE:
+       case WM8915_FLL_CONTROL_1:
+       case WM8915_FLL_CONTROL_2:
+       case WM8915_FLL_CONTROL_3:
+       case WM8915_FLL_CONTROL_4:
+       case WM8915_FLL_CONTROL_5:
+       case WM8915_FLL_CONTROL_6:
+       case WM8915_FLL_EFS_1:
+       case WM8915_FLL_EFS_2:
+       case WM8915_AIF1_CONTROL:
+       case WM8915_AIF1_BCLK:
+       case WM8915_AIF1_TX_LRCLK_1:
+       case WM8915_AIF1_TX_LRCLK_2:
+       case WM8915_AIF1_RX_LRCLK_1:
+       case WM8915_AIF1_RX_LRCLK_2:
+       case WM8915_AIF1TX_DATA_CONFIGURATION_1:
+       case WM8915_AIF1TX_DATA_CONFIGURATION_2:
+       case WM8915_AIF1RX_DATA_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION:
+       case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION:
+       case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION:
+       case WM8915_AIF1RX_MONO_CONFIGURATION:
+       case WM8915_AIF1TX_TEST:
+       case WM8915_AIF2_CONTROL:
+       case WM8915_AIF2_BCLK:
+       case WM8915_AIF2_TX_LRCLK_1:
+       case WM8915_AIF2_TX_LRCLK_2:
+       case WM8915_AIF2_RX_LRCLK_1:
+       case WM8915_AIF2_RX_LRCLK_2:
+       case WM8915_AIF2TX_DATA_CONFIGURATION_1:
+       case WM8915_AIF2TX_DATA_CONFIGURATION_2:
+       case WM8915_AIF2RX_DATA_CONFIGURATION:
+       case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION:
+       case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION:
+       case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION:
+       case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION:
+       case WM8915_AIF2RX_MONO_CONFIGURATION:
+       case WM8915_AIF2TX_TEST:
+       case WM8915_DSP1_TX_LEFT_VOLUME:
+       case WM8915_DSP1_TX_RIGHT_VOLUME:
+       case WM8915_DSP1_RX_LEFT_VOLUME:
+       case WM8915_DSP1_RX_RIGHT_VOLUME:
+       case WM8915_DSP1_TX_FILTERS:
+       case WM8915_DSP1_RX_FILTERS_1:
+       case WM8915_DSP1_RX_FILTERS_2:
+       case WM8915_DSP1_DRC_1:
+       case WM8915_DSP1_DRC_2:
+       case WM8915_DSP1_DRC_3:
+       case WM8915_DSP1_DRC_4:
+       case WM8915_DSP1_DRC_5:
+       case WM8915_DSP1_RX_EQ_GAINS_1:
+       case WM8915_DSP1_RX_EQ_GAINS_2:
+       case WM8915_DSP1_RX_EQ_BAND_1_A:
+       case WM8915_DSP1_RX_EQ_BAND_1_B:
+       case WM8915_DSP1_RX_EQ_BAND_1_PG:
+       case WM8915_DSP1_RX_EQ_BAND_2_A:
+       case WM8915_DSP1_RX_EQ_BAND_2_B:
+       case WM8915_DSP1_RX_EQ_BAND_2_C:
+       case WM8915_DSP1_RX_EQ_BAND_2_PG:
+       case WM8915_DSP1_RX_EQ_BAND_3_A:
+       case WM8915_DSP1_RX_EQ_BAND_3_B:
+       case WM8915_DSP1_RX_EQ_BAND_3_C:
+       case WM8915_DSP1_RX_EQ_BAND_3_PG:
+       case WM8915_DSP1_RX_EQ_BAND_4_A:
+       case WM8915_DSP1_RX_EQ_BAND_4_B:
+       case WM8915_DSP1_RX_EQ_BAND_4_C:
+       case WM8915_DSP1_RX_EQ_BAND_4_PG:
+       case WM8915_DSP1_RX_EQ_BAND_5_A:
+       case WM8915_DSP1_RX_EQ_BAND_5_B:
+       case WM8915_DSP1_RX_EQ_BAND_5_PG:
+       case WM8915_DSP2_TX_LEFT_VOLUME:
+       case WM8915_DSP2_TX_RIGHT_VOLUME:
+       case WM8915_DSP2_RX_LEFT_VOLUME:
+       case WM8915_DSP2_RX_RIGHT_VOLUME:
+       case WM8915_DSP2_TX_FILTERS:
+       case WM8915_DSP2_RX_FILTERS_1:
+       case WM8915_DSP2_RX_FILTERS_2:
+       case WM8915_DSP2_DRC_1:
+       case WM8915_DSP2_DRC_2:
+       case WM8915_DSP2_DRC_3:
+       case WM8915_DSP2_DRC_4:
+       case WM8915_DSP2_DRC_5:
+       case WM8915_DSP2_RX_EQ_GAINS_1:
+       case WM8915_DSP2_RX_EQ_GAINS_2:
+       case WM8915_DSP2_RX_EQ_BAND_1_A:
+       case WM8915_DSP2_RX_EQ_BAND_1_B:
+       case WM8915_DSP2_RX_EQ_BAND_1_PG:
+       case WM8915_DSP2_RX_EQ_BAND_2_A:
+       case WM8915_DSP2_RX_EQ_BAND_2_B:
+       case WM8915_DSP2_RX_EQ_BAND_2_C:
+       case WM8915_DSP2_RX_EQ_BAND_2_PG:
+       case WM8915_DSP2_RX_EQ_BAND_3_A:
+       case WM8915_DSP2_RX_EQ_BAND_3_B:
+       case WM8915_DSP2_RX_EQ_BAND_3_C:
+       case WM8915_DSP2_RX_EQ_BAND_3_PG:
+       case WM8915_DSP2_RX_EQ_BAND_4_A:
+       case WM8915_DSP2_RX_EQ_BAND_4_B:
+       case WM8915_DSP2_RX_EQ_BAND_4_C:
+       case WM8915_DSP2_RX_EQ_BAND_4_PG:
+       case WM8915_DSP2_RX_EQ_BAND_5_A:
+       case WM8915_DSP2_RX_EQ_BAND_5_B:
+       case WM8915_DSP2_RX_EQ_BAND_5_PG:
+       case WM8915_DAC1_MIXER_VOLUMES:
+       case WM8915_DAC1_LEFT_MIXER_ROUTING:
+       case WM8915_DAC1_RIGHT_MIXER_ROUTING:
+       case WM8915_DAC2_MIXER_VOLUMES:
+       case WM8915_DAC2_LEFT_MIXER_ROUTING:
+       case WM8915_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8915_DSP1_TX_LEFT_MIXER_ROUTING:
+       case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING:
+       case WM8915_DSP2_TX_LEFT_MIXER_ROUTING:
+       case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING:
+       case WM8915_DSP_TX_MIXER_SELECT:
+       case WM8915_DAC_SOFTMUTE:
+       case WM8915_OVERSAMPLING:
+       case WM8915_SIDETONE:
+       case WM8915_GPIO_1:
+       case WM8915_GPIO_2:
+       case WM8915_GPIO_3:
+       case WM8915_GPIO_4:
+       case WM8915_GPIO_5:
+       case WM8915_PULL_CONTROL_1:
+       case WM8915_PULL_CONTROL_2:
+       case WM8915_INTERRUPT_STATUS_1:
+       case WM8915_INTERRUPT_STATUS_2:
+       case WM8915_INTERRUPT_RAW_STATUS_2:
+       case WM8915_INTERRUPT_STATUS_1_MASK:
+       case WM8915_INTERRUPT_STATUS_2_MASK:
+       case WM8915_INTERRUPT_CONTROL:
+       case WM8915_LEFT_PDM_SPEAKER:
+       case WM8915_RIGHT_PDM_SPEAKER:
+       case WM8915_PDM_SPEAKER_MUTE_SEQUENCE:
+       case WM8915_PDM_SPEAKER_VOLUME:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8915_volatile_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       switch (reg) {
+       case WM8915_SOFTWARE_RESET:
+       case WM8915_CHIP_REVISION:
+       case WM8915_LDO_1:
+       case WM8915_LDO_2:
+       case WM8915_INTERRUPT_STATUS_1:
+       case WM8915_INTERRUPT_STATUS_2:
+       case WM8915_INTERRUPT_RAW_STATUS_2:
+       case WM8915_DC_SERVO_READBACK_0:
+       case WM8915_DC_SERVO_2:
+       case WM8915_DC_SERVO_6:
+       case WM8915_DC_SERVO_7:
+       case WM8915_FLL_CONTROL_6:
+       case WM8915_MIC_DETECT_3:
+       case WM8915_HEADPHONE_DETECT_1:
+       case WM8915_HEADPHONE_DETECT_2:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8915_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
+}
+
+static int wm8915_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+                       snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+                                           WM8915_BG_ENA, WM8915_BG_ENA);
+                       msleep(2);
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+                                                   wm8915->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       if (wm8915->pdata.ldo_ena >= 0) {
+                               gpio_set_value_cansleep(wm8915->pdata.ldo_ena,
+                                                       1);
+                               msleep(5);
+                       }
+
+                       codec->cache_only = false;
+                       snd_soc_cache_sync(codec);
+               }
+
+               snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+                                   WM8915_BG_ENA, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               codec->cache_only = true;
+               if (wm8915->pdata.ldo_ena >= 0)
+                       gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+               regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies),
+                                      wm8915->supplies);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int aifctrl = 0;
+       int bclk = 0;
+       int lrclk_tx = 0;
+       int lrclk_rx = 0;
+       int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+       switch (dai->id) {
+       case 0:
+               aifctrl_reg = WM8915_AIF1_CONTROL;
+               bclk_reg = WM8915_AIF1_BCLK;
+               lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2;
+               lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2;
+               break;
+       case 1:
+               aifctrl_reg = WM8915_AIF2_CONTROL;
+               bclk_reg = WM8915_AIF2_BCLK;
+               lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2;
+               lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bclk |= WM8915_AIF1_BCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bclk |= WM8915_AIF1_BCLK_INV;
+               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               bclk |= WM8915_AIF1_BCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               bclk |= WM8915_AIF1_BCLK_MSTR;
+               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aifctrl |= 1;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aifctrl |= 2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aifctrl |= 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl);
+       snd_soc_update_bits(codec, bclk_reg,
+                           WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR,
+                           bclk);
+       snd_soc_update_bits(codec, lrclk_tx_reg,
+                           WM8915_AIF1TX_LRCLK_INV |
+                           WM8915_AIF1TX_LRCLK_MSTR,
+                           lrclk_tx);
+       snd_soc_update_bits(codec, lrclk_rx_reg,
+                           WM8915_AIF1RX_LRCLK_INV |
+                           WM8915_AIF1RX_LRCLK_MSTR,
+                           lrclk_rx);
+
+       return 0;
+}
+
+static const int bclk_divs[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static const int dsp_divs[] = {
+       48000, 32000, 16000, 8000
+};
+
+static int wm8915_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int bits, i, bclk_rate, best, cur_val;
+       int aifdata = 0;
+       int bclk = 0;
+       int lrclk = 0;
+       int dsp = 0;
+       int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift;
+
+       if (!wm8915->sysclk) {
+               dev_err(codec->dev, "SYSCLK not configured\n");
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case 0:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) {
+                       aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8915_AIF1_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
+               }
+               bclk_reg = WM8915_AIF1_BCLK;
+               dsp_shift = 0;
+               break;
+       case 1:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) {
+                       aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8915_AIF2_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
+               }
+               bclk_reg = WM8915_AIF2_BCLK;
+               dsp_shift = WM8915_DSP2_DIV_SHIFT;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       bclk_rate = snd_soc_params_to_bclk(params);
+       if (bclk_rate < 0) {
+               dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+               return bclk_rate;
+       }
+
+       /* Needs looking at for TDM */
+       bits = snd_pcm_format_width(params_format(params));
+       if (bits < 0)
+               return bits;
+       aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits;
+
+       for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+               if (dsp_divs[i] == params_rate(params))
+                       break;
+       }
+       if (i == ARRAY_SIZE(dsp_divs)) {
+               dev_err(codec->dev, "Unsupported sample rate %dHz\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+       dsp |= i << dsp_shift;
+
+       /* Pick a divisor for BCLK as close as we can get to ideal */
+       best = 0;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
+               if (cur_val < 0) /* BCLK table is sorted */
+                       break;
+               best = i;
+       }
+       bclk_rate = wm8915->sysclk / bclk_divs[best];
+       dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+               bclk_divs[best], bclk_rate);
+       bclk |= best;
+
+       lrclk = bclk_rate / params_rate(params);
+       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+               lrclk, bclk_rate / lrclk);
+
+       snd_soc_update_bits(codec, aifdata_reg,
+                           WM8915_AIF1TX_WL_MASK |
+                           WM8915_AIF1TX_SLOT_LEN_MASK,
+                           aifdata);
+       snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk);
+       snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
+                           lrclk);
+       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
+                           WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
+
+       wm8915->rx_rate[dai->id] = params_rate(params);
+
+       return 0;
+}
+
+static int wm8915_set_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int lfclk = 0;
+       int ratediv = 0;
+       int src;
+       int old;
+
+       /* Disable SYSCLK while we reconfigure */
+       old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1);
+       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+                           WM8915_SYSCLK_ENA, 0);
+
+       switch (clk_id) {
+       case WM8915_SYSCLK_MCLK1:
+               wm8915->sysclk = freq;
+               src = 0;
+               break;
+       case WM8915_SYSCLK_MCLK2:
+               wm8915->sysclk = freq;
+               src = 1;
+               break;
+       case WM8915_SYSCLK_FLL:
+               wm8915->sysclk = freq;
+               src = 2;
+               break;
+       default:
+               dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       switch (wm8915->sysclk) {
+       case 6144000:
+               snd_soc_update_bits(codec, WM8915_AIF_RATE,
+                                   WM8915_SYSCLK_RATE, 0);
+               break;
+       case 24576000:
+               ratediv = WM8915_SYSCLK_DIV;
+       case 12288000:
+               snd_soc_update_bits(codec, WM8915_AIF_RATE,
+                                   WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE);
+               break;
+       case 32000:
+       case 32768:
+               lfclk = WM8915_LFCLK_ENA;
+               break;
+       default:
+               dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+                        wm8915->sysclk);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+                           WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
+                           src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
+       snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk);
+       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+                           WM8915_SYSCLK_ENA, old);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_refclk_div;
+       u16 fll_loop_gain;
+       u16 fll_ref_freq;
+       u16 n;
+       u16 theta;
+       u16 lambda;
+};
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       unsigned int target;
+       unsigned int div;
+       unsigned int fratio, gcd_fll;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_refclk_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_refclk_div++;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       if (Fref >= 3000000)
+               fll_div->fll_loop_gain = 5;
+       else
+               fll_div->fll_loop_gain = 0;
+
+       if (Fref >= 48000)
+               fll_div->fll_ref_freq = 0;
+       else
+               fll_div->fll_ref_freq = 1;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 2;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("FLL Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       fratio = fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       fll_div->n = target / (fratio * Fref);
+
+       if (target % Fref == 0) {
+               fll_div->theta = 0;
+               fll_div->lambda = 0;
+       } else {
+               gcd_fll = gcd(target, fratio * Fref);
+
+               fll_div->theta = (target - (fll_div->n * fratio * Fref))
+                       / gcd_fll;
+               fll_div->lambda = (fratio * Fref) / gcd_fll;
+       }
+
+       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+                fll_div->n, fll_div->theta, fll_div->lambda);
+       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_refclk_div);
+
+       return 0;
+}
+
+static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct _fll_div fll_div;
+       unsigned long timeout;
+       int ret, reg;
+
+       /* Any change? */
+       if (source == wm8915->fll_src && Fref == wm8915->fll_fref &&
+           Fout == wm8915->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8915->fll_fref = 0;
+               wm8915->fll_fout = 0;
+
+               snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+                                   WM8915_FLL_ENA, 0);
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       switch (source) {
+       case WM8915_FLL_MCLK1:
+               reg = 0;
+               break;
+       case WM8915_FLL_MCLK2:
+               reg = 1;
+       case WM8915_FLL_DACLRCLK1:
+               reg = 2;
+               break;
+       case WM8915_FLL_BCLK1:
+               reg = 3;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+               return -EINVAL;
+       }
+
+       reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT;
+       reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT;
+
+       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5,
+                           WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ |
+                           WM8915_FLL_REFCLK_SRC_MASK, reg);
+
+       reg = 0;
+       if (fll_div.theta || fll_div.lambda)
+               reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT);
+       else
+               reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT;
+       snd_soc_write(codec, WM8915_FLL_EFS_2, reg);
+
+       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2,
+                           WM8915_FLL_OUTDIV_MASK |
+                           WM8915_FLL_FRATIO_MASK,
+                           (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_fratio));
+
+       snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta);
+
+       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4,
+                           WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK,
+                           (fll_div.n << WM8915_FLL_N_SHIFT) |
+                           fll_div.fll_loop_gain);
+
+       snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda);
+
+       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+                           WM8915_FLL_ENA, WM8915_FLL_ENA);
+
+       /* The FLL supports live reconfiguration - kick that in case we were
+        * already enabled.
+        */
+       snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK);
+
+       /* Wait for the FLL to lock, using the interrupt if possible */
+       if (Fref > 1000000)
+               timeout = usecs_to_jiffies(300);
+       else
+               timeout = msecs_to_jiffies(2);
+
+       wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8915->fll_fref = Fref;
+       wm8915->fll_fout = Fout;
+       wm8915->fll_src = source;
+
+       return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip)
+{
+       return container_of(chip, struct wm8915_priv, gpio_chip);
+}
+
+static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+       struct snd_soc_codec *codec = wm8915->codec;
+
+       snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+                           WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT);
+}
+
+static int wm8915_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+       struct snd_soc_codec *codec = wm8915->codec;
+       int val;
+
+       val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT);
+
+       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR |
+                                  WM8915_GP1_LVL, val);
+}
+
+static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+       struct snd_soc_codec *codec = wm8915->codec;
+       int ret;
+
+       ret = snd_soc_read(codec, WM8915_GPIO_1 + offset);
+       if (ret < 0)
+               return ret;
+
+       return (ret & WM8915_GP1_LVL) != 0;
+}
+
+static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+       struct snd_soc_codec *codec = wm8915->codec;
+
+       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR,
+                                  (1 << WM8915_GP1_FN_SHIFT) |
+                                  (1 << WM8915_GP1_DIR_SHIFT));
+}
+
+static struct gpio_chip wm8915_template_chip = {
+       .label                  = "wm8915",
+       .owner                  = THIS_MODULE,
+       .direction_output       = wm8915_gpio_direction_out,
+       .set                    = wm8915_gpio_set,
+       .direction_input        = wm8915_gpio_direction_in,
+       .get                    = wm8915_gpio_get,
+       .can_sleep              = 1,
+};
+
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       wm8915->gpio_chip = wm8915_template_chip;
+       wm8915->gpio_chip.ngpio = 5;
+       wm8915->gpio_chip.dev = codec->dev;
+
+       if (wm8915->pdata.gpio_base)
+               wm8915->gpio_chip.base = wm8915->pdata.gpio_base;
+       else
+               wm8915->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&wm8915->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = gpiochip_remove(&wm8915->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+/**
+ * wm8915_detect - Enable default WM8915 jack detection
+ *
+ * The WM8915 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8915_polarity_fn polarity_cb)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+
+       wm8915->jack = jack;
+       wm8915->detecting = true;
+       wm8915->polarity_cb = polarity_cb;
+
+       if (wm8915->polarity_cb)
+               wm8915->polarity_cb(codec, 0);
+
+       /* Clear discarge to avoid noise during detection */
+       snd_soc_update_bits(codec, WM8915_MICBIAS_1,
+                           WM8915_MICB1_DISCH, 0);
+       snd_soc_update_bits(codec, WM8915_MICBIAS_2,
+                           WM8915_MICB2_DISCH, 0);
+
+       /* LDO2 powers the microphones, SYSCLK clocks detection */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+
+       /* We start off just enabling microphone detection - even a
+        * plain headphone will trigger detection.
+        */
+       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                           WM8915_MICD_ENA, WM8915_MICD_ENA);
+
+       /* Slowest detection rate, gives debounce for initial detection */
+       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                           WM8915_MICD_RATE_MASK,
+                           WM8915_MICD_RATE_MASK);
+
+       /* Enable interrupts and we're off */
+       snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK,
+                           WM8915_IM_MICD_EINT, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8915_detect);
+
+static void wm8915_micd(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int val, reg;
+
+       val = snd_soc_read(codec, WM8915_MIC_DETECT_3);
+
+       dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+       if (!(val & WM8915_MICD_VALID)) {
+               dev_warn(codec->dev, "Microphone detection state invalid\n");
+               return;
+       }
+
+       /* No accessory, reset everything and report removal */
+       if (!(val & WM8915_MICD_STS)) {
+               dev_dbg(codec->dev, "Jack removal detected\n");
+               wm8915->jack_mic = false;
+               wm8915->detecting = true;
+               snd_soc_jack_report(wm8915->jack, 0,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                   WM8915_MICD_RATE_MASK,
+                                   WM8915_MICD_RATE_MASK);
+               return;
+       }
+
+       /* If the measurement is very high we've got a microphone but
+        * do a little debounce to account for mechanical issues.
+        */
+       if (val & 0x400) {
+               dev_dbg(codec->dev, "Microphone detected\n");
+               snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               wm8915->jack_mic = true;
+               wm8915->detecting = false;
+       }
+
+       /* If we detected a lower impedence during initial startup
+        * then we probably have the wrong polarity, flip it.  Don't
+        * do this for the lowest impedences to speed up detection of
+        * plain headphones.
+        */
+       if (wm8915->detecting && (val & 0x3f0)) {
+               reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2);
+               reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+                       WM8915_MICD_BIAS_SRC;
+               snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+                                   WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+                                   WM8915_MICD_BIAS_SRC, reg);
+
+               if (wm8915->polarity_cb)
+                       wm8915->polarity_cb(codec,
+                                           (reg & WM8915_MICD_SRC) != 0);
+
+               dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+                       (reg & WM8915_MICD_SRC) != 0);
+
+               return;
+       }
+
+       /* Don't distinguish between buttons, just report any low
+        * impedence as BTN_0.
+        */
+       if (val & 0x3fc) {
+               if (wm8915->jack_mic) {
+                       dev_dbg(codec->dev, "Mic button detected\n");
+                       snd_soc_jack_report(wm8915->jack,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
+               } else {
+                       dev_dbg(codec->dev, "Headphone detected\n");
+                       snd_soc_jack_report(wm8915->jack,
+                                           SND_JACK_HEADPHONE,
+                                           SND_JACK_HEADSET |
+                                           SND_JACK_BTN_0);
+                       wm8915->detecting = false;
+               }
+       }
+
+       /* Increase poll rate to give better responsiveness for buttons */
+       if (!wm8915->detecting)
+               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                   WM8915_MICD_RATE_MASK,
+                                   5 << WM8915_MICD_RATE_SHIFT);
+}
+
+static irqreturn_t wm8915_irq(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int irq_val;
+
+       irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2);
+       if (irq_val < 0) {
+               dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+                       irq_val);
+               return IRQ_NONE;
+       }
+       irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK);
+
+       if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) {
+               dev_dbg(codec->dev, "DC servo IRQ\n");
+               complete(&wm8915->dcs_done);
+       }
+
+       if (irq_val & WM8915_FIFOS_ERR_EINT)
+               dev_err(codec->dev, "Digital core FIFO error\n");
+
+       if (irq_val & WM8915_FLL_LOCK_EINT) {
+               dev_dbg(codec->dev, "FLL locked\n");
+               complete(&wm8915->fll_lock);
+       }
+
+       if (irq_val & WM8915_MICD_EINT)
+               wm8915_micd(codec);
+
+       if (irq_val) {
+               snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val);
+
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
+}
+
+static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct wm8915_pdata *pdata = &wm8915->pdata;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("DSP1 EQ Mode",
+                            wm8915->retune_mobile_enum,
+                            wm8915_get_retune_mobile_enum,
+                            wm8915_put_retune_mobile_enum),
+               SOC_ENUM_EXT("DSP2 EQ Mode",
+                            wm8915->retune_mobile_enum,
+                            wm8915_get_retune_mobile_enum,
+                            wm8915_put_retune_mobile_enum),
+       };
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8915->num_retune_mobile_texts = 0;
+       wm8915->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8915->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8915->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8915->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8915->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8915->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8915->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8915->num_retune_mobile_texts++;
+               wm8915->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8915->num_retune_mobile_texts);
+
+       wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts;
+       wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev,
+                       "Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static int wm8915_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int i, irq_flags;
+
+       wm8915->codec = codec;
+
+       init_completion(&wm8915->dcs_done);
+       init_completion(&wm8915->fll_lock);
+
+       dapm->idle_bias_off = true;
+       dapm->bias_level = SND_SOC_BIAS_OFF;
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+               wm8915->supplies[i].supply = wm8915_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies),
+                                wm8915->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0;
+       wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
+       wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
+       wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
+       wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
+       wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
+               ret = regulator_register_notifier(wm8915->supplies[i].consumer,
+                                                 &wm8915->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+                                   wm8915->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       if (wm8915->pdata.ldo_ena >= 0) {
+               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1);
+               msleep(5);
+       }
+
+       ret = snd_soc_read(codec, WM8915_SOFTWARE_RESET);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
+               goto err_enable;
+       }
+       if (ret != 0x8915) {
+               dev_err(codec->dev, "Device is not a WM8915, ID %x\n", ret);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8915_CHIP_REVISION);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       
+       dev_info(codec->dev, "revision %c\n",
+                (ret & WM8915_CHIP_REV_MASK) + 'A');
+
+       if (wm8915->pdata.ldo_ena >= 0) {
+               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+       } else {
+               ret = wm8915_reset(codec);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Failed to issue reset\n");
+                       goto err_enable;
+               }
+       }
+
+       codec->cache_only = true;
+
+       /* Apply platform data settings */
+       snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL,
+                           WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK,
+                           wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT |
+                           wm8915->pdata.inr_mode);
+
+       for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) {
+               if (!wm8915->pdata.gpio_default[i])
+                       continue;
+
+               snd_soc_write(codec, WM8915_GPIO_1 + i,
+                             wm8915->pdata.gpio_default[i] & 0xffff);
+       }
+
+       if (wm8915->pdata.spkmute_seq)
+               snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE,
+                                   WM8915_SPK_MUTE_ENDIAN |
+                                   WM8915_SPK_MUTE_SEQ1_MASK,
+                                   wm8915->pdata.spkmute_seq);
+
+       snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+                           WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC |
+                           WM8915_MICD_SRC, wm8915->pdata.micdet_def);
+
+       /* Latch volume update bits */
+       snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME,
+                           WM8915_IN1_VU, WM8915_IN1_VU);
+       snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME,
+                           WM8915_IN1_VU, WM8915_IN1_VU);
+
+       snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME,
+                           WM8915_DAC1_VU, WM8915_DAC1_VU);
+       snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME,
+                           WM8915_DAC1_VU, WM8915_DAC1_VU);
+       snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME,
+                           WM8915_DAC2_VU, WM8915_DAC2_VU);
+       snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME,
+                           WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME,
+                           WM8915_DAC1_VU, WM8915_DAC1_VU);
+       snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME,
+                           WM8915_DAC1_VU, WM8915_DAC1_VU);
+       snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME,
+                           WM8915_DAC2_VU, WM8915_DAC2_VU);
+       snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME,
+                           WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME,
+                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME,
+                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME,
+                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME,
+                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+
+       snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME,
+                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME,
+                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME,
+                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+       snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME,
+                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+
+       /* No support currently for the underclocked TDM modes and
+        * pick a default TDM layout with each channel pair working with
+        * slots 0 and 1. */
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN0_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN1_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN2_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN2_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN3_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN4_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION,
+                           WM8915_AIF1RX_CHAN5_SLOTS_MASK |
+                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION,
+                           WM8915_AIF2RX_CHAN0_SLOTS_MASK |
+                           WM8915_AIF2RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION,
+                           WM8915_AIF2RX_CHAN1_SLOTS_MASK |
+                           WM8915_AIF2RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN0_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN1_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN2_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN3_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN4_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION,
+                           WM8915_AIF1TX_CHAN5_SLOTS_MASK |
+                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION,
+                           WM8915_AIF2TX_CHAN0_SLOTS_MASK |
+                           WM8915_AIF2TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8915_AIF2TX_CHAN1_SLOTS_MASK |
+                           WM8915_AIF2TX_CHAN1_START_SLOT_MASK,
+                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+       if (wm8915->pdata.num_retune_mobile_cfgs)
+               wm8915_retune_mobile_pdata(codec);
+       else
+               snd_soc_add_controls(codec, wm8915_eq_controls,
+                                    ARRAY_SIZE(wm8915_eq_controls));
+
+       /* If the TX LRCLK pins are not in LRCLK mode configure the
+        * AIFs to source their clocks from the RX LRCLKs.
+        */
+       if ((snd_soc_read(codec, WM8915_GPIO_1)))
+               snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2,
+                                   WM8915_AIF1TX_LRCLK_MODE,
+                                   WM8915_AIF1TX_LRCLK_MODE);
+
+       if ((snd_soc_read(codec, WM8915_GPIO_2)))
+               snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2,
+                                   WM8915_AIF2TX_LRCLK_MODE,
+                                   WM8915_AIF2TX_LRCLK_MODE);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+       wm8915_init_gpio(codec);
+
+       if (i2c->irq) {
+               if (wm8915->pdata.irq_flags)
+                       irq_flags = wm8915->pdata.irq_flags;
+               else
+                       irq_flags = IRQF_TRIGGER_LOW;
+
+               irq_flags |= IRQF_ONESHOT;
+
+               ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+                                          irq_flags, "wm8915", codec);
+               if (ret == 0) {
+                       /* Unmask the interrupt */
+                       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+                                           WM8915_IM_IRQ, 0);
+
+                       /* Enable error reporting and DC servo status */
+                       snd_soc_update_bits(codec,
+                                           WM8915_INTERRUPT_STATUS_2_MASK,
+                                           WM8915_IM_DCS_DONE_23_EINT |
+                                           WM8915_IM_DCS_DONE_01_EINT |
+                                           WM8915_IM_FLL_LOCK_EINT |
+                                           WM8915_IM_FIFOS_ERR_EINT,
+                                           0);
+               } else {
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
+                               ret);
+               }
+       }
+
+       return 0;
+
+err_enable:
+       if (wm8915->pdata.ldo_ena >= 0)
+               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err:
+       return ret;
+}
+
+static int wm8915_remove(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       int i;
+
+       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+                           WM8915_IM_IRQ, WM8915_IM_IRQ);
+
+       if (i2c->irq)
+               free_irq(i2c->irq, codec);
+
+       wm8915_free_gpio(codec);
+
+       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+               regulator_unregister_notifier(wm8915->supplies[i].consumer,
+                                             &wm8915->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8915 = {
+       .probe =        wm8915_probe,
+       .remove =       wm8915_remove,
+       .set_bias_level = wm8915_set_bias_level,
+       .seq_notifier = wm8915_seq_notifier,
+       .reg_cache_size = WM8915_MAX_REGISTER + 1,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8915_reg,
+       .volatile_register = wm8915_volatile_register,
+       .readable_register = wm8915_readable_register,
+       .compress_type = SND_SOC_RBTREE_COMPRESSION,
+       .controls = wm8915_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8915_snd_controls),
+       .dapm_widgets = wm8915_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets),
+       .dapm_routes = wm8915_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes),
+       .set_pll = wm8915_set_fll,
+};
+
+#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | 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 wm8915_dai_ops = {
+       .set_fmt = wm8915_set_fmt,
+       .hw_params = wm8915_hw_params,
+       .set_sysclk = wm8915_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8915_dai[] = {
+       {
+               .name = "wm8915-aif1",
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = WM8915_RATES,
+                       .formats = WM8915_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = WM8915_RATES,
+                        .formats = WM8915_FORMATS,
+                },
+               .ops = &wm8915_dai_ops,
+       },
+       {
+               .name = "wm8915-aif2",
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8915_RATES,
+                       .formats = WM8915_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8915_RATES,
+                        .formats = WM8915_FORMATS,
+                },
+               .ops = &wm8915_dai_ops,
+       },
+};
+
+static __devinit int wm8915_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8915_priv *wm8915;
+       int ret;
+
+       wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL);
+       if (wm8915 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8915);
+
+       if (dev_get_platdata(&i2c->dev))
+               memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev),
+                      sizeof(wm8915->pdata));
+
+       if (wm8915->pdata.ldo_ena > 0) {
+               ret = gpio_request_one(wm8915->pdata.ldo_ena,
+                                      GPIOF_OUT_INIT_LOW, "WM8915 ENA");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+                               wm8915->pdata.ldo_ena, ret);
+                       goto err;
+               }
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8915, wm8915_dai,
+                                    ARRAY_SIZE(wm8915_dai));
+       if (ret < 0)
+               goto err_gpio;
+
+       return ret;
+
+err_gpio:
+       if (wm8915->pdata.ldo_ena > 0)
+               gpio_free(wm8915->pdata.ldo_ena);
+err:
+       kfree(wm8915);
+
+       return ret;
+}
+
+static __devexit int wm8915_i2c_remove(struct i2c_client *client)
+{
+       struct wm8915_priv *wm8915 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       if (wm8915->pdata.ldo_ena > 0)
+               gpio_free(wm8915->pdata.ldo_ena);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8915_i2c_id[] = {
+       { "wm8915", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id);
+
+static struct i2c_driver wm8915_i2c_driver = {
+       .driver = {
+               .name = "wm8915",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8915_i2c_probe,
+       .remove =   __devexit_p(wm8915_i2c_remove),
+       .id_table = wm8915_i2c_id,
+};
+
+static int __init wm8915_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm8915_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n",
+                      ret);
+       }
+
+       return ret;
+}
+module_init(wm8915_modinit);
+
+static void __exit wm8915_exit(void)
+{
+       i2c_del_driver(&wm8915_i2c_driver);
+}
+module_exit(wm8915_exit);
+
+MODULE_DESCRIPTION("ASoC WM8915 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8915.h b/sound/soc/codecs/wm8915.h
new file mode 100644 (file)
index 0000000..200ffd7
--- /dev/null
@@ -0,0 +1,3717 @@
+/*
+ * wm8915.h - WM8915 audio codec interface
+ *
+ * Copyright 2011 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 _WM8915_H
+#define _WM8915_H
+
+#define WM8915_SYSCLK_MCLK1 1
+#define WM8915_SYSCLK_MCLK2 2
+#define WM8915_SYSCLK_FLL   3
+
+#define WM8915_FLL_MCLK1      1
+#define WM8915_FLL_MCLK2      2
+#define WM8915_FLL_DACLRCLK1  3
+#define WM8915_FLL_BCLK1      4
+
+typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8915_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8915_SOFTWARE_RESET                   0x00
+#define WM8915_POWER_MANAGEMENT_1               0x01
+#define WM8915_POWER_MANAGEMENT_2               0x02
+#define WM8915_POWER_MANAGEMENT_3               0x03
+#define WM8915_POWER_MANAGEMENT_4               0x04
+#define WM8915_POWER_MANAGEMENT_5               0x05
+#define WM8915_POWER_MANAGEMENT_6               0x06
+#define WM8915_POWER_MANAGEMENT_7               0x07
+#define WM8915_POWER_MANAGEMENT_8               0x08
+#define WM8915_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8915_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8915_LINE_INPUT_CONTROL               0x12
+#define WM8915_DAC1_HPOUT1_VOLUME               0x15
+#define WM8915_DAC2_HPOUT2_VOLUME               0x16
+#define WM8915_DAC1_LEFT_VOLUME                 0x18
+#define WM8915_DAC1_RIGHT_VOLUME                0x19
+#define WM8915_DAC2_LEFT_VOLUME                 0x1A
+#define WM8915_DAC2_RIGHT_VOLUME                0x1B
+#define WM8915_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8915_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8915_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8915_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8915_MICBIAS_1                        0x20
+#define WM8915_MICBIAS_2                        0x21
+#define WM8915_LDO_1                            0x28
+#define WM8915_LDO_2                            0x29
+#define WM8915_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8915_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8915_HEADPHONE_DETECT_1               0x34
+#define WM8915_HEADPHONE_DETECT_2               0x35
+#define WM8915_MIC_DETECT_1                     0x38
+#define WM8915_MIC_DETECT_2                     0x39
+#define WM8915_MIC_DETECT_3                     0x3A
+#define WM8915_CHARGE_PUMP_1                    0x40
+#define WM8915_CHARGE_PUMP_2                    0x41
+#define WM8915_DC_SERVO_1                       0x50
+#define WM8915_DC_SERVO_2                       0x51
+#define WM8915_DC_SERVO_3                       0x52
+#define WM8915_DC_SERVO_5                       0x54
+#define WM8915_DC_SERVO_6                       0x55
+#define WM8915_DC_SERVO_7                       0x56
+#define WM8915_DC_SERVO_READBACK_0              0x57
+#define WM8915_ANALOGUE_HP_1                    0x60
+#define WM8915_ANALOGUE_HP_2                    0x61
+#define WM8915_CHIP_REVISION                    0x100
+#define WM8915_CONTROL_INTERFACE_1              0x101
+#define WM8915_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8915_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8915_AIF_CLOCKING_1                   0x200
+#define WM8915_AIF_CLOCKING_2                   0x201
+#define WM8915_CLOCKING_1                       0x208
+#define WM8915_CLOCKING_2                       0x209
+#define WM8915_AIF_RATE                         0x210
+#define WM8915_FLL_CONTROL_1                    0x220
+#define WM8915_FLL_CONTROL_2                    0x221
+#define WM8915_FLL_CONTROL_3                    0x222
+#define WM8915_FLL_CONTROL_4                    0x223
+#define WM8915_FLL_CONTROL_5                    0x224
+#define WM8915_FLL_CONTROL_6                    0x225
+#define WM8915_FLL_EFS_1                        0x226
+#define WM8915_FLL_EFS_2                        0x227
+#define WM8915_AIF1_CONTROL                     0x300
+#define WM8915_AIF1_BCLK                        0x301
+#define WM8915_AIF1_TX_LRCLK_1                  0x302
+#define WM8915_AIF1_TX_LRCLK_2                  0x303
+#define WM8915_AIF1_RX_LRCLK_1                  0x304
+#define WM8915_AIF1_RX_LRCLK_2                  0x305
+#define WM8915_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8915_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8915_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8915_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8915_AIF1TX_TEST                      0x31A
+#define WM8915_AIF2_CONTROL                     0x320
+#define WM8915_AIF2_BCLK                        0x321
+#define WM8915_AIF2_TX_LRCLK_1                  0x322
+#define WM8915_AIF2_TX_LRCLK_2                  0x323
+#define WM8915_AIF2_RX_LRCLK_1                  0x324
+#define WM8915_AIF2_RX_LRCLK_2                  0x325
+#define WM8915_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8915_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8915_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8915_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8915_AIF2TX_TEST                      0x32F
+#define WM8915_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8915_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8915_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8915_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8915_DSP1_TX_FILTERS                  0x410
+#define WM8915_DSP1_RX_FILTERS_1                0x420
+#define WM8915_DSP1_RX_FILTERS_2                0x421
+#define WM8915_DSP1_DRC_1                       0x440
+#define WM8915_DSP1_DRC_2                       0x441
+#define WM8915_DSP1_DRC_3                       0x442
+#define WM8915_DSP1_DRC_4                       0x443
+#define WM8915_DSP1_DRC_5                       0x444
+#define WM8915_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8915_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8915_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8915_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8915_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8915_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8915_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8915_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8915_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8915_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8915_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8915_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8915_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8915_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8915_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8915_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8915_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8915_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8915_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8915_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8915_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8915_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8915_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8915_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8915_DSP2_TX_FILTERS                  0x510
+#define WM8915_DSP2_RX_FILTERS_1                0x520
+#define WM8915_DSP2_RX_FILTERS_2                0x521
+#define WM8915_DSP2_DRC_1                       0x540
+#define WM8915_DSP2_DRC_2                       0x541
+#define WM8915_DSP2_DRC_3                       0x542
+#define WM8915_DSP2_DRC_4                       0x543
+#define WM8915_DSP2_DRC_5                       0x544
+#define WM8915_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8915_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8915_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8915_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8915_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8915_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8915_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8915_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8915_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8915_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8915_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8915_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8915_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8915_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8915_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8915_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8915_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8915_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8915_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8915_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8915_DAC1_MIXER_VOLUMES               0x600
+#define WM8915_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8915_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8915_DAC2_MIXER_VOLUMES               0x603
+#define WM8915_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8915_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8915_DSP_TX_MIXER_SELECT              0x60A
+#define WM8915_DAC_SOFTMUTE                     0x610
+#define WM8915_OVERSAMPLING                     0x620
+#define WM8915_SIDETONE                         0x621
+#define WM8915_GPIO_1                           0x700
+#define WM8915_GPIO_2                           0x701
+#define WM8915_GPIO_3                           0x702
+#define WM8915_GPIO_4                           0x703
+#define WM8915_GPIO_5                           0x704
+#define WM8915_PULL_CONTROL_1                   0x720
+#define WM8915_PULL_CONTROL_2                   0x721
+#define WM8915_INTERRUPT_STATUS_1               0x730
+#define WM8915_INTERRUPT_STATUS_2               0x731
+#define WM8915_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8915_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8915_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8915_INTERRUPT_CONTROL                0x740
+#define WM8915_LEFT_PDM_SPEAKER                 0x800
+#define WM8915_RIGHT_PDM_SPEAKER                0x801
+#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8915_PDM_SPEAKER_VOLUME               0x803
+#define WM8915_WRITE_SEQUENCER_0                0x3000
+#define WM8915_WRITE_SEQUENCER_1                0x3001
+#define WM8915_WRITE_SEQUENCER_2                0x3002
+#define WM8915_WRITE_SEQUENCER_3                0x3003
+#define WM8915_WRITE_SEQUENCER_4                0x3004
+#define WM8915_WRITE_SEQUENCER_5                0x3005
+#define WM8915_WRITE_SEQUENCER_6                0x3006
+#define WM8915_WRITE_SEQUENCER_7                0x3007
+#define WM8915_WRITE_SEQUENCER_8                0x3008
+#define WM8915_WRITE_SEQUENCER_9                0x3009
+#define WM8915_WRITE_SEQUENCER_10               0x300A
+#define WM8915_WRITE_SEQUENCER_11               0x300B
+#define WM8915_WRITE_SEQUENCER_12               0x300C
+#define WM8915_WRITE_SEQUENCER_13               0x300D
+#define WM8915_WRITE_SEQUENCER_14               0x300E
+#define WM8915_WRITE_SEQUENCER_15               0x300F
+#define WM8915_WRITE_SEQUENCER_16               0x3010
+#define WM8915_WRITE_SEQUENCER_17               0x3011
+#define WM8915_WRITE_SEQUENCER_18               0x3012
+#define WM8915_WRITE_SEQUENCER_19               0x3013
+#define WM8915_WRITE_SEQUENCER_20               0x3014
+#define WM8915_WRITE_SEQUENCER_21               0x3015
+#define WM8915_WRITE_SEQUENCER_22               0x3016
+#define WM8915_WRITE_SEQUENCER_23               0x3017
+#define WM8915_WRITE_SEQUENCER_24               0x3018
+#define WM8915_WRITE_SEQUENCER_25               0x3019
+#define WM8915_WRITE_SEQUENCER_26               0x301A
+#define WM8915_WRITE_SEQUENCER_27               0x301B
+#define WM8915_WRITE_SEQUENCER_28               0x301C
+#define WM8915_WRITE_SEQUENCER_29               0x301D
+#define WM8915_WRITE_SEQUENCER_30               0x301E
+#define WM8915_WRITE_SEQUENCER_31               0x301F
+#define WM8915_WRITE_SEQUENCER_32               0x3020
+#define WM8915_WRITE_SEQUENCER_33               0x3021
+#define WM8915_WRITE_SEQUENCER_34               0x3022
+#define WM8915_WRITE_SEQUENCER_35               0x3023
+#define WM8915_WRITE_SEQUENCER_36               0x3024
+#define WM8915_WRITE_SEQUENCER_37               0x3025
+#define WM8915_WRITE_SEQUENCER_38               0x3026
+#define WM8915_WRITE_SEQUENCER_39               0x3027
+#define WM8915_WRITE_SEQUENCER_40               0x3028
+#define WM8915_WRITE_SEQUENCER_41               0x3029
+#define WM8915_WRITE_SEQUENCER_42               0x302A
+#define WM8915_WRITE_SEQUENCER_43               0x302B
+#define WM8915_WRITE_SEQUENCER_44               0x302C
+#define WM8915_WRITE_SEQUENCER_45               0x302D
+#define WM8915_WRITE_SEQUENCER_46               0x302E
+#define WM8915_WRITE_SEQUENCER_47               0x302F
+#define WM8915_WRITE_SEQUENCER_48               0x3030
+#define WM8915_WRITE_SEQUENCER_49               0x3031
+#define WM8915_WRITE_SEQUENCER_50               0x3032
+#define WM8915_WRITE_SEQUENCER_51               0x3033
+#define WM8915_WRITE_SEQUENCER_52               0x3034
+#define WM8915_WRITE_SEQUENCER_53               0x3035
+#define WM8915_WRITE_SEQUENCER_54               0x3036
+#define WM8915_WRITE_SEQUENCER_55               0x3037
+#define WM8915_WRITE_SEQUENCER_56               0x3038
+#define WM8915_WRITE_SEQUENCER_57               0x3039
+#define WM8915_WRITE_SEQUENCER_58               0x303A
+#define WM8915_WRITE_SEQUENCER_59               0x303B
+#define WM8915_WRITE_SEQUENCER_60               0x303C
+#define WM8915_WRITE_SEQUENCER_61               0x303D
+#define WM8915_WRITE_SEQUENCER_62               0x303E
+#define WM8915_WRITE_SEQUENCER_63               0x303F
+#define WM8915_WRITE_SEQUENCER_64               0x3040
+#define WM8915_WRITE_SEQUENCER_65               0x3041
+#define WM8915_WRITE_SEQUENCER_66               0x3042
+#define WM8915_WRITE_SEQUENCER_67               0x3043
+#define WM8915_WRITE_SEQUENCER_68               0x3044
+#define WM8915_WRITE_SEQUENCER_69               0x3045
+#define WM8915_WRITE_SEQUENCER_70               0x3046
+#define WM8915_WRITE_SEQUENCER_71               0x3047
+#define WM8915_WRITE_SEQUENCER_72               0x3048
+#define WM8915_WRITE_SEQUENCER_73               0x3049
+#define WM8915_WRITE_SEQUENCER_74               0x304A
+#define WM8915_WRITE_SEQUENCER_75               0x304B
+#define WM8915_WRITE_SEQUENCER_76               0x304C
+#define WM8915_WRITE_SEQUENCER_77               0x304D
+#define WM8915_WRITE_SEQUENCER_78               0x304E
+#define WM8915_WRITE_SEQUENCER_79               0x304F
+#define WM8915_WRITE_SEQUENCER_80               0x3050
+#define WM8915_WRITE_SEQUENCER_81               0x3051
+#define WM8915_WRITE_SEQUENCER_82               0x3052
+#define WM8915_WRITE_SEQUENCER_83               0x3053
+#define WM8915_WRITE_SEQUENCER_84               0x3054
+#define WM8915_WRITE_SEQUENCER_85               0x3055
+#define WM8915_WRITE_SEQUENCER_86               0x3056
+#define WM8915_WRITE_SEQUENCER_87               0x3057
+#define WM8915_WRITE_SEQUENCER_88               0x3058
+#define WM8915_WRITE_SEQUENCER_89               0x3059
+#define WM8915_WRITE_SEQUENCER_90               0x305A
+#define WM8915_WRITE_SEQUENCER_91               0x305B
+#define WM8915_WRITE_SEQUENCER_92               0x305C
+#define WM8915_WRITE_SEQUENCER_93               0x305D
+#define WM8915_WRITE_SEQUENCER_94               0x305E
+#define WM8915_WRITE_SEQUENCER_95               0x305F
+#define WM8915_WRITE_SEQUENCER_96               0x3060
+#define WM8915_WRITE_SEQUENCER_97               0x3061
+#define WM8915_WRITE_SEQUENCER_98               0x3062
+#define WM8915_WRITE_SEQUENCER_99               0x3063
+#define WM8915_WRITE_SEQUENCER_100              0x3064
+#define WM8915_WRITE_SEQUENCER_101              0x3065
+#define WM8915_WRITE_SEQUENCER_102              0x3066
+#define WM8915_WRITE_SEQUENCER_103              0x3067
+#define WM8915_WRITE_SEQUENCER_104              0x3068
+#define WM8915_WRITE_SEQUENCER_105              0x3069
+#define WM8915_WRITE_SEQUENCER_106              0x306A
+#define WM8915_WRITE_SEQUENCER_107              0x306B
+#define WM8915_WRITE_SEQUENCER_108              0x306C
+#define WM8915_WRITE_SEQUENCER_109              0x306D
+#define WM8915_WRITE_SEQUENCER_110              0x306E
+#define WM8915_WRITE_SEQUENCER_111              0x306F
+#define WM8915_WRITE_SEQUENCER_112              0x3070
+#define WM8915_WRITE_SEQUENCER_113              0x3071
+#define WM8915_WRITE_SEQUENCER_114              0x3072
+#define WM8915_WRITE_SEQUENCER_115              0x3073
+#define WM8915_WRITE_SEQUENCER_116              0x3074
+#define WM8915_WRITE_SEQUENCER_117              0x3075
+#define WM8915_WRITE_SEQUENCER_118              0x3076
+#define WM8915_WRITE_SEQUENCER_119              0x3077
+#define WM8915_WRITE_SEQUENCER_120              0x3078
+#define WM8915_WRITE_SEQUENCER_121              0x3079
+#define WM8915_WRITE_SEQUENCER_122              0x307A
+#define WM8915_WRITE_SEQUENCER_123              0x307B
+#define WM8915_WRITE_SEQUENCER_124              0x307C
+#define WM8915_WRITE_SEQUENCER_125              0x307D
+#define WM8915_WRITE_SEQUENCER_126              0x307E
+#define WM8915_WRITE_SEQUENCER_127              0x307F
+#define WM8915_WRITE_SEQUENCER_128              0x3080
+#define WM8915_WRITE_SEQUENCER_129              0x3081
+#define WM8915_WRITE_SEQUENCER_130              0x3082
+#define WM8915_WRITE_SEQUENCER_131              0x3083
+#define WM8915_WRITE_SEQUENCER_132              0x3084
+#define WM8915_WRITE_SEQUENCER_133              0x3085
+#define WM8915_WRITE_SEQUENCER_134              0x3086
+#define WM8915_WRITE_SEQUENCER_135              0x3087
+#define WM8915_WRITE_SEQUENCER_136              0x3088
+#define WM8915_WRITE_SEQUENCER_137              0x3089
+#define WM8915_WRITE_SEQUENCER_138              0x308A
+#define WM8915_WRITE_SEQUENCER_139              0x308B
+#define WM8915_WRITE_SEQUENCER_140              0x308C
+#define WM8915_WRITE_SEQUENCER_141              0x308D
+#define WM8915_WRITE_SEQUENCER_142              0x308E
+#define WM8915_WRITE_SEQUENCER_143              0x308F
+#define WM8915_WRITE_SEQUENCER_144              0x3090
+#define WM8915_WRITE_SEQUENCER_145              0x3091
+#define WM8915_WRITE_SEQUENCER_146              0x3092
+#define WM8915_WRITE_SEQUENCER_147              0x3093
+#define WM8915_WRITE_SEQUENCER_148              0x3094
+#define WM8915_WRITE_SEQUENCER_149              0x3095
+#define WM8915_WRITE_SEQUENCER_150              0x3096
+#define WM8915_WRITE_SEQUENCER_151              0x3097
+#define WM8915_WRITE_SEQUENCER_152              0x3098
+#define WM8915_WRITE_SEQUENCER_153              0x3099
+#define WM8915_WRITE_SEQUENCER_154              0x309A
+#define WM8915_WRITE_SEQUENCER_155              0x309B
+#define WM8915_WRITE_SEQUENCER_156              0x309C
+#define WM8915_WRITE_SEQUENCER_157              0x309D
+#define WM8915_WRITE_SEQUENCER_158              0x309E
+#define WM8915_WRITE_SEQUENCER_159              0x309F
+#define WM8915_WRITE_SEQUENCER_160              0x30A0
+#define WM8915_WRITE_SEQUENCER_161              0x30A1
+#define WM8915_WRITE_SEQUENCER_162              0x30A2
+#define WM8915_WRITE_SEQUENCER_163              0x30A3
+#define WM8915_WRITE_SEQUENCER_164              0x30A4
+#define WM8915_WRITE_SEQUENCER_165              0x30A5
+#define WM8915_WRITE_SEQUENCER_166              0x30A6
+#define WM8915_WRITE_SEQUENCER_167              0x30A7
+#define WM8915_WRITE_SEQUENCER_168              0x30A8
+#define WM8915_WRITE_SEQUENCER_169              0x30A9
+#define WM8915_WRITE_SEQUENCER_170              0x30AA
+#define WM8915_WRITE_SEQUENCER_171              0x30AB
+#define WM8915_WRITE_SEQUENCER_172              0x30AC
+#define WM8915_WRITE_SEQUENCER_173              0x30AD
+#define WM8915_WRITE_SEQUENCER_174              0x30AE
+#define WM8915_WRITE_SEQUENCER_175              0x30AF
+#define WM8915_WRITE_SEQUENCER_176              0x30B0
+#define WM8915_WRITE_SEQUENCER_177              0x30B1
+#define WM8915_WRITE_SEQUENCER_178              0x30B2
+#define WM8915_WRITE_SEQUENCER_179              0x30B3
+#define WM8915_WRITE_SEQUENCER_180              0x30B4
+#define WM8915_WRITE_SEQUENCER_181              0x30B5
+#define WM8915_WRITE_SEQUENCER_182              0x30B6
+#define WM8915_WRITE_SEQUENCER_183              0x30B7
+#define WM8915_WRITE_SEQUENCER_184              0x30B8
+#define WM8915_WRITE_SEQUENCER_185              0x30B9
+#define WM8915_WRITE_SEQUENCER_186              0x30BA
+#define WM8915_WRITE_SEQUENCER_187              0x30BB
+#define WM8915_WRITE_SEQUENCER_188              0x30BC
+#define WM8915_WRITE_SEQUENCER_189              0x30BD
+#define WM8915_WRITE_SEQUENCER_190              0x30BE
+#define WM8915_WRITE_SEQUENCER_191              0x30BF
+#define WM8915_WRITE_SEQUENCER_192              0x30C0
+#define WM8915_WRITE_SEQUENCER_193              0x30C1
+#define WM8915_WRITE_SEQUENCER_194              0x30C2
+#define WM8915_WRITE_SEQUENCER_195              0x30C3
+#define WM8915_WRITE_SEQUENCER_196              0x30C4
+#define WM8915_WRITE_SEQUENCER_197              0x30C5
+#define WM8915_WRITE_SEQUENCER_198              0x30C6
+#define WM8915_WRITE_SEQUENCER_199              0x30C7
+#define WM8915_WRITE_SEQUENCER_200              0x30C8
+#define WM8915_WRITE_SEQUENCER_201              0x30C9
+#define WM8915_WRITE_SEQUENCER_202              0x30CA
+#define WM8915_WRITE_SEQUENCER_203              0x30CB
+#define WM8915_WRITE_SEQUENCER_204              0x30CC
+#define WM8915_WRITE_SEQUENCER_205              0x30CD
+#define WM8915_WRITE_SEQUENCER_206              0x30CE
+#define WM8915_WRITE_SEQUENCER_207              0x30CF
+#define WM8915_WRITE_SEQUENCER_208              0x30D0
+#define WM8915_WRITE_SEQUENCER_209              0x30D1
+#define WM8915_WRITE_SEQUENCER_210              0x30D2
+#define WM8915_WRITE_SEQUENCER_211              0x30D3
+#define WM8915_WRITE_SEQUENCER_212              0x30D4
+#define WM8915_WRITE_SEQUENCER_213              0x30D5
+#define WM8915_WRITE_SEQUENCER_214              0x30D6
+#define WM8915_WRITE_SEQUENCER_215              0x30D7
+#define WM8915_WRITE_SEQUENCER_216              0x30D8
+#define WM8915_WRITE_SEQUENCER_217              0x30D9
+#define WM8915_WRITE_SEQUENCER_218              0x30DA
+#define WM8915_WRITE_SEQUENCER_219              0x30DB
+#define WM8915_WRITE_SEQUENCER_220              0x30DC
+#define WM8915_WRITE_SEQUENCER_221              0x30DD
+#define WM8915_WRITE_SEQUENCER_222              0x30DE
+#define WM8915_WRITE_SEQUENCER_223              0x30DF
+#define WM8915_WRITE_SEQUENCER_224              0x30E0
+#define WM8915_WRITE_SEQUENCER_225              0x30E1
+#define WM8915_WRITE_SEQUENCER_226              0x30E2
+#define WM8915_WRITE_SEQUENCER_227              0x30E3
+#define WM8915_WRITE_SEQUENCER_228              0x30E4
+#define WM8915_WRITE_SEQUENCER_229              0x30E5
+#define WM8915_WRITE_SEQUENCER_230              0x30E6
+#define WM8915_WRITE_SEQUENCER_231              0x30E7
+#define WM8915_WRITE_SEQUENCER_232              0x30E8
+#define WM8915_WRITE_SEQUENCER_233              0x30E9
+#define WM8915_WRITE_SEQUENCER_234              0x30EA
+#define WM8915_WRITE_SEQUENCER_235              0x30EB
+#define WM8915_WRITE_SEQUENCER_236              0x30EC
+#define WM8915_WRITE_SEQUENCER_237              0x30ED
+#define WM8915_WRITE_SEQUENCER_238              0x30EE
+#define WM8915_WRITE_SEQUENCER_239              0x30EF
+#define WM8915_WRITE_SEQUENCER_240              0x30F0
+#define WM8915_WRITE_SEQUENCER_241              0x30F1
+#define WM8915_WRITE_SEQUENCER_242              0x30F2
+#define WM8915_WRITE_SEQUENCER_243              0x30F3
+#define WM8915_WRITE_SEQUENCER_244              0x30F4
+#define WM8915_WRITE_SEQUENCER_245              0x30F5
+#define WM8915_WRITE_SEQUENCER_246              0x30F6
+#define WM8915_WRITE_SEQUENCER_247              0x30F7
+#define WM8915_WRITE_SEQUENCER_248              0x30F8
+#define WM8915_WRITE_SEQUENCER_249              0x30F9
+#define WM8915_WRITE_SEQUENCER_250              0x30FA
+#define WM8915_WRITE_SEQUENCER_251              0x30FB
+#define WM8915_WRITE_SEQUENCER_252              0x30FC
+#define WM8915_WRITE_SEQUENCER_253              0x30FD
+#define WM8915_WRITE_SEQUENCER_254              0x30FE
+#define WM8915_WRITE_SEQUENCER_255              0x30FF
+#define WM8915_WRITE_SEQUENCER_256              0x3100
+#define WM8915_WRITE_SEQUENCER_257              0x3101
+#define WM8915_WRITE_SEQUENCER_258              0x3102
+#define WM8915_WRITE_SEQUENCER_259              0x3103
+#define WM8915_WRITE_SEQUENCER_260              0x3104
+#define WM8915_WRITE_SEQUENCER_261              0x3105
+#define WM8915_WRITE_SEQUENCER_262              0x3106
+#define WM8915_WRITE_SEQUENCER_263              0x3107
+#define WM8915_WRITE_SEQUENCER_264              0x3108
+#define WM8915_WRITE_SEQUENCER_265              0x3109
+#define WM8915_WRITE_SEQUENCER_266              0x310A
+#define WM8915_WRITE_SEQUENCER_267              0x310B
+#define WM8915_WRITE_SEQUENCER_268              0x310C
+#define WM8915_WRITE_SEQUENCER_269              0x310D
+#define WM8915_WRITE_SEQUENCER_270              0x310E
+#define WM8915_WRITE_SEQUENCER_271              0x310F
+#define WM8915_WRITE_SEQUENCER_272              0x3110
+#define WM8915_WRITE_SEQUENCER_273              0x3111
+#define WM8915_WRITE_SEQUENCER_274              0x3112
+#define WM8915_WRITE_SEQUENCER_275              0x3113
+#define WM8915_WRITE_SEQUENCER_276              0x3114
+#define WM8915_WRITE_SEQUENCER_277              0x3115
+#define WM8915_WRITE_SEQUENCER_278              0x3116
+#define WM8915_WRITE_SEQUENCER_279              0x3117
+#define WM8915_WRITE_SEQUENCER_280              0x3118
+#define WM8915_WRITE_SEQUENCER_281              0x3119
+#define WM8915_WRITE_SEQUENCER_282              0x311A
+#define WM8915_WRITE_SEQUENCER_283              0x311B
+#define WM8915_WRITE_SEQUENCER_284              0x311C
+#define WM8915_WRITE_SEQUENCER_285              0x311D
+#define WM8915_WRITE_SEQUENCER_286              0x311E
+#define WM8915_WRITE_SEQUENCER_287              0x311F
+#define WM8915_WRITE_SEQUENCER_288              0x3120
+#define WM8915_WRITE_SEQUENCER_289              0x3121
+#define WM8915_WRITE_SEQUENCER_290              0x3122
+#define WM8915_WRITE_SEQUENCER_291              0x3123
+#define WM8915_WRITE_SEQUENCER_292              0x3124
+#define WM8915_WRITE_SEQUENCER_293              0x3125
+#define WM8915_WRITE_SEQUENCER_294              0x3126
+#define WM8915_WRITE_SEQUENCER_295              0x3127
+#define WM8915_WRITE_SEQUENCER_296              0x3128
+#define WM8915_WRITE_SEQUENCER_297              0x3129
+#define WM8915_WRITE_SEQUENCER_298              0x312A
+#define WM8915_WRITE_SEQUENCER_299              0x312B
+#define WM8915_WRITE_SEQUENCER_300              0x312C
+#define WM8915_WRITE_SEQUENCER_301              0x312D
+#define WM8915_WRITE_SEQUENCER_302              0x312E
+#define WM8915_WRITE_SEQUENCER_303              0x312F
+#define WM8915_WRITE_SEQUENCER_304              0x3130
+#define WM8915_WRITE_SEQUENCER_305              0x3131
+#define WM8915_WRITE_SEQUENCER_306              0x3132
+#define WM8915_WRITE_SEQUENCER_307              0x3133
+#define WM8915_WRITE_SEQUENCER_308              0x3134
+#define WM8915_WRITE_SEQUENCER_309              0x3135
+#define WM8915_WRITE_SEQUENCER_310              0x3136
+#define WM8915_WRITE_SEQUENCER_311              0x3137
+#define WM8915_WRITE_SEQUENCER_312              0x3138
+#define WM8915_WRITE_SEQUENCER_313              0x3139
+#define WM8915_WRITE_SEQUENCER_314              0x313A
+#define WM8915_WRITE_SEQUENCER_315              0x313B
+#define WM8915_WRITE_SEQUENCER_316              0x313C
+#define WM8915_WRITE_SEQUENCER_317              0x313D
+#define WM8915_WRITE_SEQUENCER_318              0x313E
+#define WM8915_WRITE_SEQUENCER_319              0x313F
+#define WM8915_WRITE_SEQUENCER_320              0x3140
+#define WM8915_WRITE_SEQUENCER_321              0x3141
+#define WM8915_WRITE_SEQUENCER_322              0x3142
+#define WM8915_WRITE_SEQUENCER_323              0x3143
+#define WM8915_WRITE_SEQUENCER_324              0x3144
+#define WM8915_WRITE_SEQUENCER_325              0x3145
+#define WM8915_WRITE_SEQUENCER_326              0x3146
+#define WM8915_WRITE_SEQUENCER_327              0x3147
+#define WM8915_WRITE_SEQUENCER_328              0x3148
+#define WM8915_WRITE_SEQUENCER_329              0x3149
+#define WM8915_WRITE_SEQUENCER_330              0x314A
+#define WM8915_WRITE_SEQUENCER_331              0x314B
+#define WM8915_WRITE_SEQUENCER_332              0x314C
+#define WM8915_WRITE_SEQUENCER_333              0x314D
+#define WM8915_WRITE_SEQUENCER_334              0x314E
+#define WM8915_WRITE_SEQUENCER_335              0x314F
+#define WM8915_WRITE_SEQUENCER_336              0x3150
+#define WM8915_WRITE_SEQUENCER_337              0x3151
+#define WM8915_WRITE_SEQUENCER_338              0x3152
+#define WM8915_WRITE_SEQUENCER_339              0x3153
+#define WM8915_WRITE_SEQUENCER_340              0x3154
+#define WM8915_WRITE_SEQUENCER_341              0x3155
+#define WM8915_WRITE_SEQUENCER_342              0x3156
+#define WM8915_WRITE_SEQUENCER_343              0x3157
+#define WM8915_WRITE_SEQUENCER_344              0x3158
+#define WM8915_WRITE_SEQUENCER_345              0x3159
+#define WM8915_WRITE_SEQUENCER_346              0x315A
+#define WM8915_WRITE_SEQUENCER_347              0x315B
+#define WM8915_WRITE_SEQUENCER_348              0x315C
+#define WM8915_WRITE_SEQUENCER_349              0x315D
+#define WM8915_WRITE_SEQUENCER_350              0x315E
+#define WM8915_WRITE_SEQUENCER_351              0x315F
+#define WM8915_WRITE_SEQUENCER_352              0x3160
+#define WM8915_WRITE_SEQUENCER_353              0x3161
+#define WM8915_WRITE_SEQUENCER_354              0x3162
+#define WM8915_WRITE_SEQUENCER_355              0x3163
+#define WM8915_WRITE_SEQUENCER_356              0x3164
+#define WM8915_WRITE_SEQUENCER_357              0x3165
+#define WM8915_WRITE_SEQUENCER_358              0x3166
+#define WM8915_WRITE_SEQUENCER_359              0x3167
+#define WM8915_WRITE_SEQUENCER_360              0x3168
+#define WM8915_WRITE_SEQUENCER_361              0x3169
+#define WM8915_WRITE_SEQUENCER_362              0x316A
+#define WM8915_WRITE_SEQUENCER_363              0x316B
+#define WM8915_WRITE_SEQUENCER_364              0x316C
+#define WM8915_WRITE_SEQUENCER_365              0x316D
+#define WM8915_WRITE_SEQUENCER_366              0x316E
+#define WM8915_WRITE_SEQUENCER_367              0x316F
+#define WM8915_WRITE_SEQUENCER_368              0x3170
+#define WM8915_WRITE_SEQUENCER_369              0x3171
+#define WM8915_WRITE_SEQUENCER_370              0x3172
+#define WM8915_WRITE_SEQUENCER_371              0x3173
+#define WM8915_WRITE_SEQUENCER_372              0x3174
+#define WM8915_WRITE_SEQUENCER_373              0x3175
+#define WM8915_WRITE_SEQUENCER_374              0x3176
+#define WM8915_WRITE_SEQUENCER_375              0x3177
+#define WM8915_WRITE_SEQUENCER_376              0x3178
+#define WM8915_WRITE_SEQUENCER_377              0x3179
+#define WM8915_WRITE_SEQUENCER_378              0x317A
+#define WM8915_WRITE_SEQUENCER_379              0x317B
+#define WM8915_WRITE_SEQUENCER_380              0x317C
+#define WM8915_WRITE_SEQUENCER_381              0x317D
+#define WM8915_WRITE_SEQUENCER_382              0x317E
+#define WM8915_WRITE_SEQUENCER_383              0x317F
+#define WM8915_WRITE_SEQUENCER_384              0x3180
+#define WM8915_WRITE_SEQUENCER_385              0x3181
+#define WM8915_WRITE_SEQUENCER_386              0x3182
+#define WM8915_WRITE_SEQUENCER_387              0x3183
+#define WM8915_WRITE_SEQUENCER_388              0x3184
+#define WM8915_WRITE_SEQUENCER_389              0x3185
+#define WM8915_WRITE_SEQUENCER_390              0x3186
+#define WM8915_WRITE_SEQUENCER_391              0x3187
+#define WM8915_WRITE_SEQUENCER_392              0x3188
+#define WM8915_WRITE_SEQUENCER_393              0x3189
+#define WM8915_WRITE_SEQUENCER_394              0x318A
+#define WM8915_WRITE_SEQUENCER_395              0x318B
+#define WM8915_WRITE_SEQUENCER_396              0x318C
+#define WM8915_WRITE_SEQUENCER_397              0x318D
+#define WM8915_WRITE_SEQUENCER_398              0x318E
+#define WM8915_WRITE_SEQUENCER_399              0x318F
+#define WM8915_WRITE_SEQUENCER_400              0x3190
+#define WM8915_WRITE_SEQUENCER_401              0x3191
+#define WM8915_WRITE_SEQUENCER_402              0x3192
+#define WM8915_WRITE_SEQUENCER_403              0x3193
+#define WM8915_WRITE_SEQUENCER_404              0x3194
+#define WM8915_WRITE_SEQUENCER_405              0x3195
+#define WM8915_WRITE_SEQUENCER_406              0x3196
+#define WM8915_WRITE_SEQUENCER_407              0x3197
+#define WM8915_WRITE_SEQUENCER_408              0x3198
+#define WM8915_WRITE_SEQUENCER_409              0x3199
+#define WM8915_WRITE_SEQUENCER_410              0x319A
+#define WM8915_WRITE_SEQUENCER_411              0x319B
+#define WM8915_WRITE_SEQUENCER_412              0x319C
+#define WM8915_WRITE_SEQUENCER_413              0x319D
+#define WM8915_WRITE_SEQUENCER_414              0x319E
+#define WM8915_WRITE_SEQUENCER_415              0x319F
+#define WM8915_WRITE_SEQUENCER_416              0x31A0
+#define WM8915_WRITE_SEQUENCER_417              0x31A1
+#define WM8915_WRITE_SEQUENCER_418              0x31A2
+#define WM8915_WRITE_SEQUENCER_419              0x31A3
+#define WM8915_WRITE_SEQUENCER_420              0x31A4
+#define WM8915_WRITE_SEQUENCER_421              0x31A5
+#define WM8915_WRITE_SEQUENCER_422              0x31A6
+#define WM8915_WRITE_SEQUENCER_423              0x31A7
+#define WM8915_WRITE_SEQUENCER_424              0x31A8
+#define WM8915_WRITE_SEQUENCER_425              0x31A9
+#define WM8915_WRITE_SEQUENCER_426              0x31AA
+#define WM8915_WRITE_SEQUENCER_427              0x31AB
+#define WM8915_WRITE_SEQUENCER_428              0x31AC
+#define WM8915_WRITE_SEQUENCER_429              0x31AD
+#define WM8915_WRITE_SEQUENCER_430              0x31AE
+#define WM8915_WRITE_SEQUENCER_431              0x31AF
+#define WM8915_WRITE_SEQUENCER_432              0x31B0
+#define WM8915_WRITE_SEQUENCER_433              0x31B1
+#define WM8915_WRITE_SEQUENCER_434              0x31B2
+#define WM8915_WRITE_SEQUENCER_435              0x31B3
+#define WM8915_WRITE_SEQUENCER_436              0x31B4
+#define WM8915_WRITE_SEQUENCER_437              0x31B5
+#define WM8915_WRITE_SEQUENCER_438              0x31B6
+#define WM8915_WRITE_SEQUENCER_439              0x31B7
+#define WM8915_WRITE_SEQUENCER_440              0x31B8
+#define WM8915_WRITE_SEQUENCER_441              0x31B9
+#define WM8915_WRITE_SEQUENCER_442              0x31BA
+#define WM8915_WRITE_SEQUENCER_443              0x31BB
+#define WM8915_WRITE_SEQUENCER_444              0x31BC
+#define WM8915_WRITE_SEQUENCER_445              0x31BD
+#define WM8915_WRITE_SEQUENCER_446              0x31BE
+#define WM8915_WRITE_SEQUENCER_447              0x31BF
+#define WM8915_WRITE_SEQUENCER_448              0x31C0
+#define WM8915_WRITE_SEQUENCER_449              0x31C1
+#define WM8915_WRITE_SEQUENCER_450              0x31C2
+#define WM8915_WRITE_SEQUENCER_451              0x31C3
+#define WM8915_WRITE_SEQUENCER_452              0x31C4
+#define WM8915_WRITE_SEQUENCER_453              0x31C5
+#define WM8915_WRITE_SEQUENCER_454              0x31C6
+#define WM8915_WRITE_SEQUENCER_455              0x31C7
+#define WM8915_WRITE_SEQUENCER_456              0x31C8
+#define WM8915_WRITE_SEQUENCER_457              0x31C9
+#define WM8915_WRITE_SEQUENCER_458              0x31CA
+#define WM8915_WRITE_SEQUENCER_459              0x31CB
+#define WM8915_WRITE_SEQUENCER_460              0x31CC
+#define WM8915_WRITE_SEQUENCER_461              0x31CD
+#define WM8915_WRITE_SEQUENCER_462              0x31CE
+#define WM8915_WRITE_SEQUENCER_463              0x31CF
+#define WM8915_WRITE_SEQUENCER_464              0x31D0
+#define WM8915_WRITE_SEQUENCER_465              0x31D1
+#define WM8915_WRITE_SEQUENCER_466              0x31D2
+#define WM8915_WRITE_SEQUENCER_467              0x31D3
+#define WM8915_WRITE_SEQUENCER_468              0x31D4
+#define WM8915_WRITE_SEQUENCER_469              0x31D5
+#define WM8915_WRITE_SEQUENCER_470              0x31D6
+#define WM8915_WRITE_SEQUENCER_471              0x31D7
+#define WM8915_WRITE_SEQUENCER_472              0x31D8
+#define WM8915_WRITE_SEQUENCER_473              0x31D9
+#define WM8915_WRITE_SEQUENCER_474              0x31DA
+#define WM8915_WRITE_SEQUENCER_475              0x31DB
+#define WM8915_WRITE_SEQUENCER_476              0x31DC
+#define WM8915_WRITE_SEQUENCER_477              0x31DD
+#define WM8915_WRITE_SEQUENCER_478              0x31DE
+#define WM8915_WRITE_SEQUENCER_479              0x31DF
+#define WM8915_WRITE_SEQUENCER_480              0x31E0
+#define WM8915_WRITE_SEQUENCER_481              0x31E1
+#define WM8915_WRITE_SEQUENCER_482              0x31E2
+#define WM8915_WRITE_SEQUENCER_483              0x31E3
+#define WM8915_WRITE_SEQUENCER_484              0x31E4
+#define WM8915_WRITE_SEQUENCER_485              0x31E5
+#define WM8915_WRITE_SEQUENCER_486              0x31E6
+#define WM8915_WRITE_SEQUENCER_487              0x31E7
+#define WM8915_WRITE_SEQUENCER_488              0x31E8
+#define WM8915_WRITE_SEQUENCER_489              0x31E9
+#define WM8915_WRITE_SEQUENCER_490              0x31EA
+#define WM8915_WRITE_SEQUENCER_491              0x31EB
+#define WM8915_WRITE_SEQUENCER_492              0x31EC
+#define WM8915_WRITE_SEQUENCER_493              0x31ED
+#define WM8915_WRITE_SEQUENCER_494              0x31EE
+#define WM8915_WRITE_SEQUENCER_495              0x31EF
+#define WM8915_WRITE_SEQUENCER_496              0x31F0
+#define WM8915_WRITE_SEQUENCER_497              0x31F1
+#define WM8915_WRITE_SEQUENCER_498              0x31F2
+#define WM8915_WRITE_SEQUENCER_499              0x31F3
+#define WM8915_WRITE_SEQUENCER_500              0x31F4
+#define WM8915_WRITE_SEQUENCER_501              0x31F5
+#define WM8915_WRITE_SEQUENCER_502              0x31F6
+#define WM8915_WRITE_SEQUENCER_503              0x31F7
+#define WM8915_WRITE_SEQUENCER_504              0x31F8
+#define WM8915_WRITE_SEQUENCER_505              0x31F9
+#define WM8915_WRITE_SEQUENCER_506              0x31FA
+#define WM8915_WRITE_SEQUENCER_507              0x31FB
+#define WM8915_WRITE_SEQUENCER_508              0x31FC
+#define WM8915_WRITE_SEQUENCER_509              0x31FD
+#define WM8915_WRITE_SEQUENCER_510              0x31FE
+#define WM8915_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8915_REGISTER_COUNT                   706
+#define WM8915_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8915_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8915_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8915_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8915_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8915_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8915_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8915_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8915_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8915_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8915_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8915_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8915_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8915_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8915_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8915_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8915_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8915_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8915_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8915_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8915_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8915_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8915_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8915_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8915_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8915_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8915_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8915_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8915_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8915_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8915_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8915_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8915_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8915_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8915_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8915_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8915_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8915_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8915_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8915_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8915_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8915_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8915_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8915_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8915_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8915_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8915_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8915_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8915_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8915_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8915_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8915_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8915_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8915_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8915_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8915_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8915_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8915_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8915_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8915_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8915_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8915_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8915_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8915_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8915_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8915_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8915_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8915_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8915_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8915_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8915_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8915_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8915_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8915_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8915_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8915_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8915_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8915_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8915_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8915_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8915_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8915_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8915_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8915_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8915_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8915_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8915_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8915_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8915_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8915_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8915_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8915_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8915_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8915_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8915_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8915_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8915_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8915_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8915_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8915_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8915_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8915_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8915_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8915_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8915_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8915_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8915_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8915_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8915_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8915_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8915_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8915_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8915_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8915_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8915_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8915_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8915_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8915_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8915_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8915_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8915_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8915_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8915_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8915_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8915_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8915_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8915_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8915_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8915_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8915_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8915_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8915_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8915_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8915_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8915_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8915_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8915_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8915_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8915_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8915_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8915_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8915_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8915_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8915_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8915_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8915_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8915_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8915_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8915_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8915_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8915_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8915_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8915_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8915_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8915_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8915_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8915_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8915_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8915_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8915_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8915_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8915_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8915_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8915_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8915_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8915_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8915_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8915_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8915_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8915_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8915_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8915_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8915_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8915_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8915_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8915_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8915_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8915_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8915_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8915_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8915_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8915_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8915_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8915_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8915_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8915_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8915_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8915_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8915_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8915_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8915_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8915_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8915_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8915_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8915_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8915_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8915_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8915_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8915_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8915_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8915_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8915_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8915_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8915_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8915_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8915_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8915_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8915_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8915_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8915_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8915_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8915_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8915_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8915_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8915_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8915_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8915_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8915_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8915_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8915_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8915_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8915_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8915_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8915_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8915_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8915_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8915_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8915_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8915_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8915_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8915_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8915_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8915_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8915_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8915_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8915_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8915_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8915_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8915_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8915_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8915_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8915_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8915_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8915_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8915_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8915_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8915_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8915_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8915_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8915_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8915_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8915_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8915_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8915_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8915_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8915_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8915_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8915_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8915_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8915_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8915_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8915_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8915_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8915_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8915_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8915_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8915_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8915_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8915_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8915_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8915_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8915_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8915_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8915_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8915_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8915_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8915_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8915_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8915_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8915_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8915_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8915_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8915_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8915_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8915_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8915_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8915_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8915_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8915_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8915_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8915_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8915_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8915_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8915_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8915_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8915_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8915_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8915_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8915_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8915_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8915_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8915_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8915_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8915_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8915_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8915_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8915_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8915_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8915_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8915_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8915_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8915_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8915_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8915_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8915_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8915_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8915_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8915_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8915_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8915_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8915_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8915_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8915_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8915_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8915_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8915_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8915_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8915_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8915_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8915_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8915_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8915_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8915_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8915_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8915_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8915_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8915_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8915_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8915_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8915_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8915_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8915_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8915_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8915_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8915_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8915_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8915_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8915_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8915_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
new file mode 100644 (file)
index 0000000..0293763
--- /dev/null
@@ -0,0 +1,1051 @@
+/*
+ * wm8958-dsp2.c  --  WM8958 DSP2 support
+ *
+ * Copyright 2011 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+
+#define WM_FW_BLOCK_INFO 0xff
+#define WM_FW_BLOCK_PM   0x00
+#define WM_FW_BLOCK_X    0x01
+#define WM_FW_BLOCK_Y    0x02
+#define WM_FW_BLOCK_Z    0x03
+#define WM_FW_BLOCK_I    0x06
+#define WM_FW_BLOCK_A    0x08
+#define WM_FW_BLOCK_C    0x0c
+
+static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
+                         const struct firmware *fw, bool check)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       u64 data64;
+       u32 data32;
+       const u8 *data;
+       char *str;
+       size_t block_len, len;
+       int ret = 0;
+
+       /* Suppress unneeded downloads */
+       if (wm8994->cur_fw == fw)
+               return 0;
+
+       if (fw->size < 32) {
+               dev_err(codec->dev, "%s: firmware too short\n", name);
+               goto err;
+       }
+
+       if (memcmp(fw->data, "WMFW", 4) != 0) {
+               dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
+                       name, data32);
+               goto err;
+       }
+
+       memcpy(&data32, fw->data + 4, sizeof(data32));
+       len = be32_to_cpu(data32);
+
+       memcpy(&data32, fw->data + 8, sizeof(data32));
+       data32 = be32_to_cpu(data32);
+       if ((data32 >> 24) & 0xff) {
+               dev_err(codec->dev, "%s: unsupported firmware version %d\n",
+                       name, (data32 >> 24) & 0xff);
+               goto err;
+       }
+       if ((data32 & 0xffff) != 8958) {
+               dev_err(codec->dev, "%s: unsupported target device %d\n",
+                       name, data32 & 0xffff);
+               goto err;
+       }
+       if (((data32 >> 16) & 0xff) != 0xc) {
+               dev_err(codec->dev, "%s: unsupported target core %d\n",
+                       name, (data32 >> 16) & 0xff);
+               goto err;
+       }
+
+       if (check) {
+               memcpy(&data64, fw->data + 24, sizeof(u64));
+               dev_info(codec->dev, "%s timestamp %llx\n",
+                        name, be64_to_cpu(data64));
+       } else {
+               snd_soc_write(codec, 0x102, 0x2);
+               snd_soc_write(codec, 0x900, 0x2);
+       }
+
+       data = fw->data + len;
+       len = fw->size - len;
+       while (len) {
+               if (len < 12) {
+                       dev_err(codec->dev, "%s short data block of %zd\n",
+                               name, len);
+                       goto err;
+               }
+
+               memcpy(&data32, data + 4, sizeof(data32));
+               block_len = be32_to_cpu(data32);
+               if (block_len + 8 > len) {
+                       dev_err(codec->dev, "%zd byte block longer than file\n",
+                               block_len);
+                       goto err;
+               }
+               if (block_len == 0) {
+                       dev_err(codec->dev, "Zero length block\n");
+                       goto err;
+               }
+
+               memcpy(&data32, data, sizeof(data32));
+               data32 = be32_to_cpu(data32);
+
+               switch ((data32 >> 24) & 0xff) {
+               case WM_FW_BLOCK_INFO:
+                       /* Informational text */
+                       if (!check)
+                               break;
+
+                       str = kzalloc(block_len + 1, GFP_KERNEL);
+                       if (str) {
+                               memcpy(str, data + 8, block_len);
+                               dev_info(codec->dev, "%s: %s\n", name, str);
+                               kfree(str);
+                       } else {
+                               dev_err(codec->dev, "Out of memory\n");
+                       }
+                       break;
+               case WM_FW_BLOCK_PM:
+               case WM_FW_BLOCK_X:
+               case WM_FW_BLOCK_Y:
+               case WM_FW_BLOCK_Z:
+               case WM_FW_BLOCK_I:
+               case WM_FW_BLOCK_A:
+               case WM_FW_BLOCK_C:
+                       dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
+                               block_len, (data32 >> 24) & 0xff,
+                               data32 & 0xffffff);
+
+                       if (check)
+                               break;
+
+                       data32 &= 0xffffff;
+
+                       wm8994_bulk_write(codec->control_data,
+                                         data32 & 0xffffff,
+                                         block_len / 2,
+                                         (void *)(data + 8));
+
+                       break;
+               default:
+                       dev_warn(codec->dev, "%s: unknown block type %d\n",
+                                name, (data32 >> 24) & 0xff);
+                       break;
+               }
+
+               /* Round up to the next 32 bit word */
+               block_len += block_len % 4;
+
+               data += block_len + 8;
+               len -= block_len + 8;
+       }
+
+       if (!check) {
+               dev_dbg(codec->dev, "%s: download done\n", name);
+               wm8994->cur_fw = fw;
+       } else {
+               dev_info(codec->dev, "%s: got firmware\n", name);
+       }
+
+       goto ok;
+
+err:
+       ret = -EINVAL;
+ok:
+       if (!check) {
+               snd_soc_write(codec, 0x900, 0x0);
+               snd_soc_write(codec, 0x102, 0x0);
+       }
+
+       return ret;
+}
+
+static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i;
+
+       /* If the DSP is already running then noop */
+       if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+               return;
+
+       /* If we have MBC firmware download it */
+       if (wm8994->mbc)
+               wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied MBC settings use them */
+       if (pdata && pdata->num_mbc_cfgs) {
+               struct wm8958_mbc_cfg *cfg
+                       = &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+                       snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+                                     cfg->coeff_regs[i]);
+
+               for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+                       snd_soc_write(codec,
+                                     i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+                                     cfg->cutoff_regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* And we're off! */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_ENA |
+                           WM8958_MBC_SEL_MASK,
+                           path << WM8958_MBC_SEL_SHIFT |
+                           WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i, ena;
+
+       if (wm8994->mbc_vss)
+               wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied settings use them */
+       if (pdata && pdata->num_mbc_cfgs) {
+               struct wm8958_mbc_cfg *cfg
+                       = &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
+                       snd_soc_write(codec, i + 0x2800,
+                                     cfg->combined_regs[i]);
+       }
+
+       if (pdata && pdata->num_vss_cfgs) {
+               struct wm8958_vss_cfg *cfg
+                       = &pdata->vss_cfgs[wm8994->vss_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
+       }
+
+       if (pdata && pdata->num_vss_hpf_cfgs) {
+               struct wm8958_vss_hpf_cfg *cfg
+                       = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* Enable the algorithms we've selected */
+       ena = 0;
+       if (wm8994->mbc_ena[path])
+               ena |= 0x8;
+       if (wm8994->hpf2_ena[path])
+               ena |= 0x4;
+       if (wm8994->hpf1_ena[path])
+               ena |= 0x2;
+       if (wm8994->vss_ena[path])
+               ena |= 0x1;
+
+       snd_soc_write(codec, 0x2201, ena);
+
+       /* Switch the DSP into the data path */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+                           path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i;
+
+       wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied settings use them */
+       if (pdata && pdata->num_enh_eq_cfgs) {
+               struct wm8958_enh_eq_cfg *cfg
+                       = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2200,
+                                     cfg->regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* Switch the DSP into the data path */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+                           path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+       int ena, reg, aif;
+
+       switch (path) {
+       case 0:
+               pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+               aif = 0;
+               break;
+       case 1:
+               pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+               aif = 0;
+               break;
+       case 2:
+               pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+               aif = 1;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       /* Do we have both an active AIF and an active algorithm? */
+       ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
+               wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
+               wm8994->enh_eq_ena[path];
+       if (!pwr_reg)
+               ena = 0;
+
+       reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+
+       dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+               path, wm8994->dsp_active, start, pwr_reg, reg);
+
+       if (start && ena) {
+               /* If the DSP is already running then noop */
+               if (reg & WM8958_DSP2_ENA)
+                       return;
+
+               /* If either AIFnCLK is not yet enabled postpone */
+               if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+                     & WM8994_AIF1CLK_ENA_MASK) &&
+                   !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+                     & WM8994_AIF2CLK_ENA_MASK))
+                       return;
+
+               /* Switch the clock over to the appropriate AIF */
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+                                   aif << WM8958_DSP2CLK_SRC_SHIFT |
+                                   WM8958_DSP2CLK_ENA);
+
+               if (wm8994->enh_eq_ena[path])
+                       wm8958_dsp_start_enh_eq(codec, path);
+               else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
+                   wm8994->hpf2_ena[path])
+                       wm8958_dsp_start_vss(codec, path);
+               else if (wm8994->mbc_ena[path])
+                       wm8958_dsp_start_mbc(codec, path);
+
+               wm8994->dsp_active = path;
+
+               dev_dbg(codec->dev, "DSP running in path %d\n", path);
+       }
+
+       if (!start && wm8994->dsp_active == path) {
+               /* If the DSP is already stopped then noop */
+               if (!(reg & WM8958_DSP2_ENA))
+                       return;
+
+               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                                   WM8958_MBC_ENA, 0); 
+               snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                             WM8958_DSP2_STOP);
+               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                                   WM8958_DSP2_ENA, 0);
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_ENA, 0);
+
+               wm8994->dsp_active = -1;
+
+               dev_dbg(codec->dev, "DSP stopped\n");
+       }
+}
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int i;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_PRE_PMU:
+               for (i = 0; i < 3; i++)
+                       wm8958_dsp_apply(codec, i, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+       case SND_SOC_DAPM_PRE_PMD:
+               for (i = 0; i < 3; i++)
+                       wm8958_dsp_apply(codec, i, 0);
+               break;
+       }
+
+       return 0;
+}
+
+/* Check if DSP2 is in use on another AIF */
+static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+               if (i == aif)
+                       continue;
+               if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
+                   wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_mbc_cfgs)
+               return -EINVAL;
+
+       wm8994->mbc_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+       return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+       return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
+               return 0;
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (wm8958_dsp2_busy(wm8994, mbc)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[mbc])
+               return -EBUSY;
+
+       wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+
+       return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_mbc_info, \
+       .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+       .private_value = xval }
+
+static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_vss_cfgs)
+               return -EINVAL;
+
+       wm8994->vss_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
+
+       return 0;
+}
+
+static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_vss_hpf_cfgs)
+               return -EINVAL;
+
+       wm8994->vss_hpf_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
+
+       return 0;
+}
+
+static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int vss = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
+
+       return 0;
+}
+
+static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int vss = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
+               return 0;
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->mbc_vss)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, vss)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[vss])
+               return -EBUSY;
+
+       wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
+
+       return 0;
+}
+
+
+#define WM8958_VSS_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_vss_info, \
+       .get = wm8958_vss_get, .put = wm8958_vss_put, \
+       .private_value = xval }
+
+static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int hpf = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (hpf < 3)
+               ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
+       else
+               ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
+
+       return 0;
+}
+
+static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int hpf = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (hpf < 3) {
+               if (wm8994->hpf1_ena[hpf % 3] ==
+                   ucontrol->value.integer.value[0])
+                       return 0;
+       } else {
+               if (wm8994->hpf2_ena[hpf % 3] ==
+                   ucontrol->value.integer.value[0])
+                       return 0;
+       }
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->mbc_vss)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[hpf % 3])
+               return -EBUSY;
+
+       if (hpf < 3)
+               wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
+       else
+               wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
+
+       return 0;
+}
+
+#define WM8958_HPF_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_hpf_info, \
+       .get = wm8958_hpf_get, .put = wm8958_hpf_put, \
+       .private_value = xval }
+
+static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_enh_eq_cfgs)
+               return -EINVAL;
+
+       wm8994->enh_eq_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
+
+       return 0;
+}
+
+static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int eq = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
+
+       return 0;
+}
+
+static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int eq = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
+               return 0;
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->enh_eq)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, eq)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
+               return -EBUSY;
+       }
+
+       if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
+           wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
+               return -EBUSY;
+
+       wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
+
+       return 0;
+}
+
+#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_enh_eq_info, \
+       .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
+       .private_value = xval }
+
+static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
+static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
+WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
+WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
+WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
+WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
+WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
+};
+
+static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
+WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
+WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
+WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
+};
+
+static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
+               mutex_lock(&codec->mutex);
+               wm8994->enh_eq = fw;
+               mutex_unlock(&codec->mutex);
+       }
+}
+
+static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
+               mutex_lock(&codec->mutex);
+               wm8994->mbc_vss = fw;
+               mutex_unlock(&codec->mutex);
+       }
+
+       /* We can't have more than one request outstanding at once so
+        * we daisy chain.
+        */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_enh_eq_loaded);
+}
+
+static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
+               return;
+
+       mutex_lock(&codec->mutex);
+       wm8994->mbc = fw;
+       mutex_unlock(&codec->mutex);
+
+       /* We can't have more than one request outstanding at once so
+        * we daisy chain.
+        */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_mbc_vss_loaded);
+}
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int ret, i;
+
+       wm8994->dsp_active = -1;
+
+       snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
+                            ARRAY_SIZE(wm8958_mbc_snd_controls));
+       snd_soc_add_controls(codec, wm8958_vss_snd_controls,
+                            ARRAY_SIZE(wm8958_vss_snd_controls));
+       snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
+                            ARRAY_SIZE(wm8958_enh_eq_snd_controls));
+
+
+       /* We don't *require* firmware and don't want to delay boot */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_mbc_loaded);
+
+       if (!pdata)
+               return;
+
+       if (pdata->num_mbc_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+                                    wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->mbc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_mbc_cfgs, GFP_KERNEL);
+               if (!wm8994->mbc_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d MBC config texts\n",
+                               pdata->num_mbc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_mbc_cfgs; i++)
+                       wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+               wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add MBC mode controls: %d\n", ret);
+       }
+
+       if (pdata->num_vss_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
+                                    wm8958_get_vss_enum, wm8958_put_vss_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->vss_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_vss_cfgs, GFP_KERNEL);
+               if (!wm8994->vss_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d VSS config texts\n",
+                               pdata->num_vss_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_vss_cfgs; i++)
+                       wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
+
+               wm8994->vss_enum.max = pdata->num_vss_cfgs;
+               wm8994->vss_enum.texts = wm8994->vss_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add VSS mode controls: %d\n", ret);
+       }
+
+       if (pdata->num_vss_hpf_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
+                                    wm8958_get_vss_hpf_enum,
+                                    wm8958_put_vss_hpf_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
+                                               * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
+               if (!wm8994->vss_hpf_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d VSS HPF config texts\n",
+                               pdata->num_vss_hpf_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
+                       wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
+
+               wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+               wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add VSS HPFmode controls: %d\n",
+                               ret);
+       }
+
+       if (pdata->num_enh_eq_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
+                                    wm8958_get_enh_eq_enum,
+                                    wm8958_put_enh_eq_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->enh_eq_texts = kmalloc(sizeof(char *)
+                                               * pdata->num_enh_eq_cfgs, GFP_KERNEL);
+               if (!wm8994->enh_eq_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d enhanced EQ config texts\n",
+                               pdata->num_enh_eq_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
+                       wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
+
+               wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+               wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add enhanced EQ controls: %d\n",
+                               ret);
+       }
+}
index 500011eb8b2bdb31d88fa2a8df819c72626a97bc..f90ae427242b4a26c87b9aff56fe23cc09303645 100644 (file)
@@ -58,6 +58,7 @@ struct wm8962_priv {
        int bclk;  /* Desired BCLK */
        int lrclk;
 
+       struct completion fll_lock;
        int fll_src;
        int fll_fref;
        int fll_fout;
@@ -2038,6 +2039,13 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static const char *cap_hpf_mode_text[] = {
+       "Hi-fi", "Application"
+};
+
+static const struct soc_enum cap_hpf_mode =
+       SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+
 static const struct snd_kcontrol_new wm8962_snd_controls[] = {
 SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
 
@@ -2063,6 +2071,9 @@ SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
             WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
 SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
             WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
+SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
+SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
 
 SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
                 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
@@ -2467,6 +2478,7 @@ SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 SND_SOC_DAPM_INPUT("Beep"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
 
@@ -2486,6 +2498,8 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
 SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
                   mixinr, ARRAY_SIZE(mixinr)),
 
+SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+
 SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
 SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
 
@@ -2563,13 +2577,17 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
 
        { "MICBIAS", NULL, "SYSCLK" },
 
+       { "DMIC", NULL, "DMICDAT" },
+
        { "ADCL", NULL, "SYSCLK" },
        { "ADCL", NULL, "TOCLK" },
        { "ADCL", NULL, "MIXINL" },
+       { "ADCL", NULL, "DMIC" },
 
        { "ADCR", NULL, "SYSCLK" },
        { "ADCR", NULL, "TOCLK" },
        { "ADCR", NULL, "MIXINR" },
+       { "ADCR", NULL, "DMIC" },
 
        { "STL", "Left", "ADCL" },
        { "STL", "Right", "ADCR" },
@@ -2990,7 +3008,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
        case WM8962_SYSCLK_FLL:
                wm8962->sysclk = WM8962_SYSCLK_FLL;
                src = 1 << WM8962_SYSCLK_SRC_SHIFT;
-               WARN_ON(freq != wm8962->fll_fout);
                break;
        default:
                return -EINVAL;
@@ -3172,12 +3189,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
        return 0;
 }
 
-static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                          unsigned int Fref, unsigned int Fout)
 {
-       struct snd_soc_codec *codec = dai->codec;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        struct _fll_div fll_div;
+       unsigned long timeout;
        int ret;
        int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
 
@@ -3244,6 +3261,11 @@ static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
        dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
+       /* This should be a massive overestimate */
+       timeout = msecs_to_jiffies(1);
+
+       wait_for_completion_timeout(&wm8962->fll_lock, timeout);
+
        wm8962->fll_fref = Fref;
        wm8962->fll_fout = Fout;
        wm8962->fll_src = source;
@@ -3274,7 +3296,6 @@ static struct snd_soc_dai_ops wm8962_dai_ops = {
        .hw_params = wm8962_hw_params,
        .set_sysclk = wm8962_set_dai_sysclk,
        .set_fmt = wm8962_set_dai_fmt,
-       .set_pll = wm8962_set_fll,
        .digital_mute = wm8962_mute,
 };
 
@@ -3340,6 +3361,11 @@ static irqreturn_t wm8962_irq(int irq, void *data)
        active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
        active &= ~mask;
 
+       if (active & WM8962_FLL_LOCK_EINT) {
+               dev_dbg(codec->dev, "FLL locked\n");
+               complete(&wm8962->fll_lock);
+       }
+
        if (active & WM8962_FIFOS_ERR_EINT)
                dev_err(codec->dev, "FIFO error\n");
 
@@ -3709,9 +3735,11 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                                              dev);
        u16 *reg_cache = codec->reg_cache;
        int i, trigger, irq_pol;
+       bool dmicclk, dmicdat;
 
        wm8962->codec = codec;
        INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+       init_completion(&wm8962->fll_lock);
 
        codec->cache_sync = 1;
        codec->dapm.idle_bias_off = 1;
@@ -3845,6 +3873,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 
        wm8962_add_widgets(codec);
 
+       /* Save boards having to disable DMIC when not in use */
+       dmicclk = false;
+       dmicdat = false;
+       for (i = 0; i < WM8962_MAX_GPIO; i++) {
+               switch (snd_soc_read(codec, WM8962_GPIO_BASE + i)
+                       & WM8962_GP2_FN_MASK) {
+               case WM8962_GPIO_FN_DMICCLK:
+                       dmicclk = true;
+                       break;
+               case WM8962_GPIO_FN_DMICDAT:
+                       dmicdat = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (!dmicclk || !dmicdat) {
+               dev_dbg(codec->dev, "DMIC not in use, disabling\n");
+               snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT");
+       }
+       if (dmicclk != dmicdat)
+               dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
+
        wm8962_init_beep(codec);
        wm8962_init_gpio(codec);
 
@@ -3868,9 +3919,10 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                                i2c->irq, ret);
                        /* Non-fatal */
                } else {
-                       /* Enable error reporting IRQs by default */
+                       /* Enable some IRQs by default */
                        snd_soc_update_bits(codec,
                                            WM8962_INTERRUPT_STATUS_2_MASK,
+                                           WM8962_FLL_LOCK_EINT |
                                            WM8962_TEMP_SHUT_EINT |
                                            WM8962_FIFOS_ERR_EINT, 0);
                }
@@ -3918,6 +3970,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
        .reg_cache_default = wm8962_reg,
        .volatile_register = wm8962_volatile_register,
        .readable_register = wm8962_readable_register,
+       .set_pll = wm8962_set_fll,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 056aef90434774b5382758010fa2c366bb99858d..9e5ff789b805bcf932238a07ba422ab88b8a6e44 100644 (file)
@@ -718,7 +718,8 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
 static int class_w_put(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int ret;
index 84e1bd1d2822fcfe7eca4a0bfb8749eff28a7fec..970a95c5360bfc271fd9a43c0a259bedd2d0d7a9 100644 (file)
 #include "wm8994.h"
 #include "wm_hubs.h"
 
-struct fll_config {
-       int src;
-       int in;
-       int out;
-};
-
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
@@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = {
        WM8994_AIF2_EQ_GAINS_1,
 };
 
-struct wm8994_micdet {
-       struct snd_soc_jack *jack;
-       int det;
-       int shrt;
-};
-
-/* codec private data */
-struct wm8994_priv {
-       struct wm_hubs_data hubs;
-       enum snd_soc_control_type control_type;
-       void *control_data;
-       struct snd_soc_codec *codec;
-       int sysclk[2];
-       int sysclk_rate[2];
-       int mclk[2];
-       int aifclk[2];
-       struct fll_config fll[2], fll_suspend[2];
-
-       int dac_rates[2];
-       int lrclk_shared[2];
-
-       int mbc_ena[3];
-
-       /* Platform dependent DRC configuration */
-       const char **drc_texts;
-       int drc_cfg[WM8994_NUM_DRC];
-       struct soc_enum drc_enum;
-
-       /* Platform dependent ReTune mobile configuration */
-       int num_retune_mobile_texts;
-       const char **retune_mobile_texts;
-       int retune_mobile_cfg[WM8994_NUM_EQ];
-       struct soc_enum retune_mobile_enum;
-
-       /* Platform dependent MBC configuration */
-       int mbc_cfg;
-       const char **mbc_texts;
-       struct soc_enum mbc_enum;
-
-       struct wm8994_micdet micdet[2];
-
-       wm8958_micdet_cb jack_cb;
-       void *jack_cb_data;
-       int micdet_irq;
-
-       int revision;
-       struct wm8994_pdata *pdata;
-
-       unsigned int aif1clk_enable:1;
-       unsigned int aif2clk_enable:1;
-
-       unsigned int aif1clk_disable:1;
-       unsigned int aif2clk_disable:1;
-};
-
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->control_data;
+
        switch (reg) {
        case WM8994_GPIO_1:
        case WM8994_GPIO_2:
@@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
        case WM8994_INTERRUPT_STATUS_2:
        case WM8994_INTERRUPT_RAW_STATUS_2:
                return 1;
+
+       case WM8958_DSP2_PROGRAM:
+       case WM8958_DSP2_CONFIG:
+       case WM8958_DSP2_EXECCONTROL:
+               if (control->type == WM8958)
+                       return 1;
+               else
+                       return 0;
+
        default:
                break;
        }
@@ -574,215 +525,6 @@ static const struct soc_enum dac_osr =
 static const struct soc_enum adc_osr =
        SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
 
-static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
-{
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994_pdata *pdata = wm8994->pdata;
-       int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
-       int ena, reg, aif, i;
-
-       switch (mbc) {
-       case 0:
-               pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
-               aif = 0;
-               break;
-       case 1:
-               pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
-               aif = 0;
-               break;
-       case 2:
-               pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
-               aif = 1;
-               break;
-       default:
-               BUG();
-               return;
-       }
-
-       /* We can only enable the MBC if the AIF is enabled and we
-        * want it to be enabled. */
-       ena = pwr_reg && wm8994->mbc_ena[mbc];
-
-       reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
-
-       dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
-               mbc, start, pwr_reg, reg);
-
-       if (start && ena) {
-               /* If the DSP is already running then noop */
-               if (reg & WM8958_DSP2_ENA)
-                       return;
-
-               /* Switch the clock over to the appropriate AIF */
-               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-                                   WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
-                                   aif << WM8958_DSP2CLK_SRC_SHIFT |
-                                   WM8958_DSP2CLK_ENA);
-
-               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-                                   WM8958_DSP2_ENA, WM8958_DSP2_ENA);
-
-               /* If we've got user supplied MBC settings use them */
-               if (pdata && pdata->num_mbc_cfgs) {
-                       struct wm8958_mbc_cfg *cfg
-                               = &pdata->mbc_cfgs[wm8994->mbc_cfg];
-
-                       for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
-                               snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
-                                             cfg->coeff_regs[i]);
-
-                       for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
-                               snd_soc_write(codec,
-                                             i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
-                                             cfg->cutoff_regs[i]);
-               }
-
-               /* Run the DSP */
-               snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
-                             WM8958_DSP2_RUNR);
-
-               /* And we're off! */
-               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-                                   WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
-                                   mbc << WM8958_MBC_SEL_SHIFT |
-                                   WM8958_MBC_ENA);
-       } else {
-               /* If the DSP is already stopped then noop */
-               if (!(reg & WM8958_DSP2_ENA))
-                       return;
-
-               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-                                   WM8958_MBC_ENA, 0); 
-               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-                                   WM8958_DSP2_ENA, 0);
-               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-                                   WM8958_DSP2CLK_ENA, 0);
-       }
-}
-
-static int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
-                   struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       int mbc;
-
-       switch (w->shift) {
-       case 13:
-       case 12:
-               mbc = 2;
-               break;
-       case 11:
-       case 10:
-               mbc = 1;
-               break;
-       case 9:
-       case 8:
-               mbc = 0;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               wm8958_mbc_apply(codec, mbc, 1);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               wm8958_mbc_apply(codec, mbc, 0);
-               break;
-       }
-
-       return 0;
-}
-
-static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994_pdata *pdata = wm8994->pdata;
-       int value = ucontrol->value.integer.value[0];
-       int reg;
-
-       /* Don't allow on the fly reconfiguration */
-       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
-       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
-               return -EBUSY;
-
-       if (value >= pdata->num_mbc_cfgs)
-               return -EINVAL;
-
-       wm8994->mbc_cfg = value;
-
-       return 0;
-}
-
-static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
-
-       return 0;
-}
-
-static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
-
-static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       int mbc = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
-
-       return 0;
-}
-
-static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       int mbc = kcontrol->private_value;
-       int i;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       if (ucontrol->value.integer.value[0] > 1)
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
-               if (mbc != i && wm8994->mbc_ena[i]) {
-                       dev_dbg(codec->dev, "MBC %d active already\n", mbc);
-                       return -EBUSY;
-               }
-       }
-
-       wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
-
-       wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
-
-       return 0;
-}
-
-#define WM8958_MBC_SWITCH(xname, xval) {\
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .info = wm8958_mbc_info, \
-       .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
-       .private_value = xval }
-
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
                 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
-WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
-WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
-WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 };
 
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
                break;
        }
 
+       /* We may also have postponed startup of DSP, handle that. */
+       wm8958_aif_ev(w, kcontrol, event);
+
        return 0;
 }
 
@@ -1135,7 +877,8 @@ static const char *hp_mux_text[] = {
 static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *w = wlist->widgets[0];
        struct snd_soc_codec *codec = w->codec;
        int ret;
 
@@ -1262,7 +1005,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *w = wlist->widgets[0];
        struct snd_soc_codec *codec = w->codec;
        int ret;
 
@@ -2180,6 +1924,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                            WM8994_VMID_BUF_ENA |
                                            WM8994_VMID_RAMP_MASK, 0);
 
+                       wm8994->cur_fw = NULL;
+
                        pm_runtime_put(codec->dev);
                }
                break;
@@ -2672,11 +2418,22 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
 static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = codec->control_data;
        int i, ret;
 
+       switch (control->type) {
+       case WM8994:
+               snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
+               break;
+       case WM8958:
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                   WM8958_MICD_ENA, 0);
+               break;
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
-                      sizeof(struct fll_config));
+                      sizeof(struct wm8994_fll_config));
                ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
                if (ret < 0)
                        dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
@@ -2691,6 +2448,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = codec->control_data;
        int i, ret;
        unsigned int val, mask;
 
@@ -2729,6 +2487,19 @@ static int wm8994_resume(struct snd_soc_codec *codec)
                                 i + 1, ret);
        }
 
+       switch (control->type) {
+       case WM8994:
+               if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
+                       snd_soc_update_bits(codec, WM8994_MICBIAS,
+                                           WM8994_MICD_ENA, WM8994_MICD_ENA);
+               break;
+       case WM8958:
+               if (wm8994->jack_cb)
+                       snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                           WM8958_MICD_ENA, WM8958_MICD_ENA);
+               break;
+       }
+
        return 0;
 }
 #else
@@ -2862,34 +2633,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
                pdata->num_retune_mobile_cfgs);
 
-       if (pdata->num_mbc_cfgs) {
-               struct snd_kcontrol_new control[] = {
-                       SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
-                                    wm8958_get_mbc_enum, wm8958_put_mbc_enum),
-               };
-
-               /* We need an array of texts for the enum API */
-               wm8994->mbc_texts = kmalloc(sizeof(char *)
-                                           * pdata->num_mbc_cfgs, GFP_KERNEL);
-               if (!wm8994->mbc_texts) {
-                       dev_err(wm8994->codec->dev,
-                               "Failed to allocate %d MBC config texts\n",
-                               pdata->num_mbc_cfgs);
-                       return;
-               }
-
-               for (i = 0; i < pdata->num_mbc_cfgs; i++)
-                       wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
-
-               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
-               wm8994->mbc_enum.texts = wm8994->mbc_texts;
-
-               ret = snd_soc_add_controls(wm8994->codec, control, 1);
-               if (ret != 0)
-                       dev_err(wm8994->codec->dev,
-                               "Failed to add MBC mode controls: %d\n", ret);
-       }
-
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
@@ -3343,14 +3086,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8958:
                snd_soc_add_controls(codec, wm8958_snd_controls,
                                     ARRAY_SIZE(wm8958_snd_controls));
-               snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
-                                         ARRAY_SIZE(wm8994_lateclk_widgets));
-               snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
-                                         ARRAY_SIZE(wm8994_adc_widgets));
-               snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
-                                         ARRAY_SIZE(wm8994_dac_widgets));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
+               if (wm8994->revision < 1) {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_revd_widgets));
+               } else {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_widgets));
+               }
                break;
        }
                
@@ -3374,10 +3126,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
                break;
        case WM8958:
-               snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
-                                       ARRAY_SIZE(wm8994_lateclk_intercon));
-               snd_soc_dapm_add_routes(dapm, wm8958_intercon,
-                                       ARRAY_SIZE(wm8958_intercon));
+               if (wm8994->revision < 1) {
+                       snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+                                               ARRAY_SIZE(wm8994_revd_intercon));
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+               } else {
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_intercon));
+                       snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+                                               ARRAY_SIZE(wm8958_intercon));
+               }
+
+               wm8958_dsp2_init(codec);
                break;
        }
 
@@ -3420,6 +3181,12 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
                        free_irq(wm8994->micdet_irq, wm8994);
                break;
        }
+       if (wm8994->mbc)
+               release_firmware(wm8994->mbc);
+       if (wm8994->mbc_vss)
+               release_firmware(wm8994->mbc_vss);
+       if (wm8994->enh_eq)
+               release_firmware(wm8994->enh_eq);
        kfree(wm8994->retune_mobile_texts);
        kfree(wm8994->drc_texts);
        kfree(wm8994);
index 999b8851226b6840371ec041493355ffd6f3d905..0a1db04b73bd7e97e20f61349528c108fa831a3c 100644 (file)
@@ -10,6 +10,9 @@
 #define _WM8994_H
 
 #include <sound/soc.h>
+#include <linux/firmware.h>
+
+#include "wm_hubs.h"
 
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
@@ -45,4 +48,98 @@ struct wm8994_access_mask {
 extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
 extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event);
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec);
+
+struct wm8994_micdet {
+       struct snd_soc_jack *jack;
+       int det;
+       int shrt;
+};
+
+/* codec private data */
+struct wm8994_fll_config {
+       int src;
+       int in;
+       int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+struct wm8994_priv {
+       struct wm_hubs_data hubs;
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       struct snd_soc_codec *codec;
+       int sysclk[2];
+       int sysclk_rate[2];
+       int mclk[2];
+       int aifclk[2];
+       struct wm8994_fll_config fll[2], fll_suspend[2];
+
+       int dac_rates[2];
+       int lrclk_shared[2];
+
+       int mbc_ena[3];
+       int hpf1_ena[3];
+       int hpf2_ena[3];
+       int vss_ena[3];
+       int enh_eq_ena[3];
+
+       /* Platform dependant DRC configuration */
+       const char **drc_texts;
+       int drc_cfg[WM8994_NUM_DRC];
+       struct soc_enum drc_enum;
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[WM8994_NUM_EQ];
+       struct soc_enum retune_mobile_enum;
+
+       /* Platform dependant MBC configuration */
+       int mbc_cfg;
+       const char **mbc_texts;
+       struct soc_enum mbc_enum;
+
+       /* Platform dependant VSS configuration */
+       int vss_cfg;
+       const char **vss_texts;
+       struct soc_enum vss_enum;
+
+       /* Platform dependant VSS HPF configuration */
+       int vss_hpf_cfg;
+       const char **vss_hpf_texts;
+       struct soc_enum vss_hpf_enum;
+
+       /* Platform dependant enhanced EQ configuration */
+       int enh_eq_cfg;
+       const char **enh_eq_texts;
+       struct soc_enum enh_eq_enum;
+
+       struct wm8994_micdet micdet[2];
+
+       wm8958_micdet_cb jack_cb;
+       void *jack_cb_data;
+       int micdet_irq;
+
+       int revision;
+       struct wm8994_pdata *pdata;
+
+       unsigned int aif1clk_enable:1;
+       unsigned int aif2clk_enable:1;
+
+       unsigned int aif1clk_disable:1;
+       unsigned int aif2clk_disable:1;
+
+       int dsp_active;
+       const struct firmware *cur_fw;
+       const struct firmware *mbc;
+       const struct firmware *mbc_vss;
+       const struct firmware *enh_eq;
+};
+
 #endif
index 67eaaecbb42ebdf1dfeec71e8b51e90105877ee7..5ad873fda814d9e20502684c2db87ebc13407b34 100644 (file)
@@ -305,11 +305,11 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *w = wlist->widgets[0];
        struct snd_soc_codec *codec;
        int ret;
 
-       w = snd_kcontrol_chip(kcontrol);
        codec = w->codec;
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
        wm8995_update_class_w(codec);
index 47b357adabdd13ef6f4a6e16c2779c8531387449..646b58dda849192777adc69d66ab54bb14891928 100644 (file)
@@ -142,7 +142,7 @@ static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
  * constantly enabled, we use the mutes on those inputs to simulate such
  * controls.
  */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9705_audio_map[] = {
        /* HP mixer */
        {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
        {"HP Mixer", "CD Playback Switch", "CD PGA"},
@@ -200,17 +200,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Right ADC", NULL, "ADC PGA"},
 };
 
-static int wm9705_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets,
-                                       ARRAY_SIZE(wm9705_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /* We use a register cache to enhance read performance. */
 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
 {
@@ -364,7 +353,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
                                ARRAY_SIZE(wm9705_snd_ac97_controls));
-       wm9705_add_widgets(codec);
 
        return 0;
 
@@ -390,6 +378,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9705_reg,
+       .dapm_widgets = wm9705_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
+       .dapm_routes = wm9705_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map),
 };
 
 static __devinit int wm9705_probe(struct platform_device *pdev)
index bf5d4ef1a2a6e54a4723238f8984e38fb71656c4..90117f8156e83c8da98b1f53fdb23573be4f9a03 100644 (file)
@@ -332,7 +332,7 @@ SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9712_audio_map[] = {
        /* virtual mixer - mixes left & right channels for spk and mono */
        {"AC97 Mixer", NULL, "Left DAC"},
        {"AC97 Mixer", NULL, "Right DAC"},
@@ -429,17 +429,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"ROUT2", NULL, "Speaker PGA"},
 };
 
-static int wm9712_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets,
-                                 ARRAY_SIZE(wm9712_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -651,7 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
        wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
                                ARRAY_SIZE(wm9712_snd_ac97_controls));
-       wm9712_add_widgets(codec);
 
        return 0;
 
@@ -678,6 +666,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9712_reg,
+       .dapm_widgets = wm9712_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
+       .dapm_routes = wm9712_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
 };
 
 static __devinit int wm9712_probe(struct platform_device *pdev)
index 38ed985587184fe4e3f2a4b636ae8d67e35cf60e..7167cb6787dba44efdc25a4550d12d24bbb026c6 100644 (file)
@@ -487,7 +487,7 @@ SND_SOC_DAPM_INPUT("MIC2B"),
 SND_SOC_DAPM_VMID("VMID"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9713_audio_map[] = {
        /* left HP mixer */
        {"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
@@ -644,18 +644,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 
-static int wm9713_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets,
-                                 ARRAY_SIZE(wm9713_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -1231,7 +1219,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
                                ARRAY_SIZE(wm9713_snd_ac97_controls));
-       wm9713_add_widgets(codec);
 
        return 0;
 
@@ -1262,6 +1249,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9713_reg,
+       .dapm_widgets = wm9713_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
+       .dapm_routes = wm9713_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),
 };
 
 static __devinit int wm9713_probe(struct platform_device *pdev)
index 4005e9af5d61acae8ce40c05b2862fcfa20ae4c0..e55b298c14a06e249f54453829295c880c39998a 100644 (file)
@@ -787,17 +787,17 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
 static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
        { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
        { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
-       { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
+       { "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
 
        { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
        { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
 };
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
-       { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
-       { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
+       { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
+       { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
-       { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
+       { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
        { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
        { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
@@ -806,17 +806,17 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = {
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
        { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
        { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
-       { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
+       { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
 
        { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
        { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
 };
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
-       { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
-       { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
+       { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
+       { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
-       { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
+       { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
        { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
        { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
@@ -836,17 +836,21 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
                            WM8993_IN2_VU, WM8993_IN2_VU);
 
+       snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
+                           WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
        snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
                            WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 
        snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
-                           WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
+                           WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
+                           WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
        snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
                            WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
                            WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
 
        snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
-                           WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
+                           WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
+                           WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
        snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
                            WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
                            WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
index a5af834c8ef52088c9a735b85cceebe095b95300..8566238db2a5ea7a3f807f2cb341826703167bec 100644 (file)
@@ -434,17 +434,21 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
                mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26));
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               ACLKX | AHCLKX | AFSX);
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
                mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
                mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x2d << 26));
+               mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               ACLKX | ACLKR);
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               AFSX | AFSR);
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* codec is clock and frame master */
@@ -454,7 +458,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
                mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26));
+               mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
                break;
 
        default:
@@ -644,7 +649,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
                mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask);
                mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD);
 
-               if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
+               if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
                        mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
                                        FSXMOD(dev->tdm_slots), FSXMOD(0x1FF));
                else
@@ -660,7 +665,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
                                AHCLKRE);
                mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask);
 
-               if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
+               if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
                        mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG,
                                        FSRMOD(dev->tdm_slots), FSRMOD(0x1FF));
                else
@@ -904,6 +909,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
+       dma_data->sram_size = pdata->sram_size_playback;
        dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
                                                        mem->start);
 
@@ -920,6 +926,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
+       dma_data->sram_size = pdata->sram_size_capture;
        dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
                                                        mem->start);
 
index ac2ded969253895a0b5df067922e91b1678a12a7..5b13feca753732a6664969308e0794b161936aa8 100644 (file)
@@ -667,12 +667,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
        if (res)
                ssi->dma_params_rx.dma = res->start;
 
-       if ((cpu_is_mx27() || cpu_is_mx21()) &&
-                       !(ssi->flags & IMX_SSI_USE_AC97) &&
-                       (ssi->flags & IMX_SSI_DMA)) {
-               ssi->flags |= IMX_SSI_DMA;
-       }
-
        platform_set_drvdata(pdev, ssi);
 
        ret = snd_soc_register_dai(&pdev->dev, dai);
index 419bf4f5534a6c082f8e5b5aa7a1a9ce3e43bcf7..cd22a54b2f14b3cd408d64acbbc519786320f573 100644 (file)
@@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       if (!dai->active)
+       if (dai->active)
                return;
 
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
index 49723e3e7e386ace2de3d0d3427276e1d7e5e8fd..c5fc339f68f1b792bf42932c8390590d5c4a058e 100644 (file)
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
                             struct snd_kcontrol *ctrl, int event)
 {
-       int on = 0;
-       if (event & SND_SOC_DAPM_POST_PMU)
-               on = 1;
-       else if (event & SND_SOC_DAPM_PRE_PMD)
-               on = 0;
+       int on = !SND_SOC_DAPM_EVENT_OFF(event);
 
        gpio_set_value(QI_LB60_SND_GPIO, on);
        gpio_set_value(QI_LB60_AMP_GPIO, on);
@@ -70,12 +66,6 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       snd_soc_dapm_new_controls(dapm, qi_lb60_widgets,
-                                 ARRAY_SIZE(qi_lb60_widgets));
-       snd_soc_dapm_add_routes(dapm, qi_lb60_routes,
-                               ARRAY_SIZE(qi_lb60_routes));
-       snd_soc_dapm_sync(dapm);
-
        return 0;
 }
 
@@ -93,10 +83,20 @@ static struct snd_soc_card qi_lb60 = {
        .name = "QI LB60",
        .dai_link = &qi_lb60_dai,
        .num_links = 1,
+
+       .dapm_widgets = qi_lb60_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
+       .dapm_routes = qi_lb60_routes,
+       .num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
 };
 
 static struct platform_device *qi_lb60_snd_device;
 
+static const struct gpio qi_lb60_gpios[] = {
+       { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
+       { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+};
+
 static int __init qi_lb60_init(void)
 {
        int ret;
@@ -106,23 +106,12 @@ static int __init qi_lb60_init(void)
        if (!qi_lb60_snd_device)
                return -ENOMEM;
 
-       ret = gpio_request(QI_LB60_SND_GPIO, "SND");
+       ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
        if (ret) {
-               pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n",
-                               QI_LB60_SND_GPIO, ret);
+               pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret);
                goto err_device_put;
        }
 
-       ret = gpio_request(QI_LB60_AMP_GPIO, "AMP");
-       if (ret) {
-               pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n",
-                               QI_LB60_AMP_GPIO, ret);
-               goto err_gpio_free_snd;
-       }
-
-       gpio_direction_output(QI_LB60_SND_GPIO, 0);
-       gpio_direction_output(QI_LB60_AMP_GPIO, 0);
-
        platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 
        ret = platform_device_add(qi_lb60_snd_device);
@@ -135,10 +124,8 @@ static int __init qi_lb60_init(void)
 
 err_unset_pdata:
        platform_set_drvdata(qi_lb60_snd_device, NULL);
-/*err_gpio_free_amp:*/
-       gpio_free(QI_LB60_AMP_GPIO);
-err_gpio_free_snd:
-       gpio_free(QI_LB60_SND_GPIO);
+/*err_gpio_free_array:*/
+       gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 err_device_put:
        platform_device_put(qi_lb60_snd_device);
 
@@ -148,9 +135,8 @@ module_init(qi_lb60_init);
 
 static void __exit qi_lb60_exit(void)
 {
-       gpio_free(QI_LB60_AMP_GPIO);
-       gpio_free(QI_LB60_SND_GPIO);
        platform_device_unregister(qi_lb60_snd_device);
+       gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 }
 module_exit(qi_lb60_exit);
 
index d567c322a2fb471788d7b8f47345a6b9fd6d5aed..5a946b4115a2d94df27f35e81164584c2c577f50 100644 (file)
@@ -249,10 +249,13 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
                return -ENOMEM;
        }
        stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
+       stream->sstdrv_ops->module_name = SST_CARD_NAMES;
        /* registering with SST driver to get access to SST APIs to use */
        ret_val = register_sst_card(stream->sstdrv_ops);
        if (ret_val) {
                pr_err("sst: sst card registration failed\n");
+               kfree(stream->sstdrv_ops);
+               kfree(stream);
                return ret_val;
        }
        runtime->private_data = stream;
@@ -270,6 +273,7 @@ static int sst_platform_close(struct snd_pcm_substream *substream)
        str_id = stream->stream_info.str_id;
        if (str_id)
                ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
+       unregister_sst_card(stream->sstdrv_ops);
        kfree(stream->sstdrv_ops);
        kfree(stream);
        return ret_val;
@@ -376,6 +380,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
 static struct snd_pcm_ops sst_platform_ops = {
        .open = sst_platform_open,
        .close = sst_platform_close,
@@ -384,6 +393,7 @@ static struct snd_pcm_ops sst_platform_ops = {
        .trigger = sst_platform_pcm_trigger,
        .pointer = sst_platform_pcm_pointer,
        .hw_params = sst_platform_pcm_hw_params,
+       .hw_free = sst_platform_pcm_hw_free,
 };
 
 static void sst_pcm_free(struct snd_pcm *pcm)
index 2175f09e57b60dc76f3f23d0a263cdd90957551a..07b77235724473691262d59130f897f6ead979d7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -146,7 +146,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
         * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
         * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
         */
-       if (cpu_is_omap343x() || cpu_is_omap44xx()) {
+       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
                /*
                * Rule for the buffer size. We should not allow
                * smaller buffer than the FIFO size to avoid underruns
@@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        default:
                return -EINVAL;
        }
-       if (cpu_is_omap343x()) {
+       if (cpu_is_omap34xx()) {
                dma_data->set_threshold = omap_mcbsp_set_threshold;
                /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
                if (omap_mcbsp_get_dma_op_mode(bus_id) ==
index 37dc7211ed3f8e04e7ecb1257545d04b5b2dc343..9a7dedd6f5a950bda15c2a2dfdc462c0979a94aa 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 8caeb8d305c3b0308f0592c7fa8d3461d6fce87f..e6a6b991d05fc1d29749eeefca9393ad19e24420 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME,
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
                                  SNDRV_PCM_FMTBIT_S32_LE,
        .period_bytes_min       = 32,
@@ -195,7 +196,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
        if ((cpu_is_omap1510()))
                omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
                              OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-       else
+       else if (!substream->runtime->no_period_wakeup)
                omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
 
        if (!(cpu_class_is_omap1())) {
index fea0515331fb6721f1f91b95ee565f150d5f3e37..a0ed1dbb52d67b93c26a9b65b423b4ee05db513f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index d0986220eff97844e3bef90979f329e55f6fa847..0aae998b654007a77fa82f5b1429bc65674ff4c5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 - 2009 Nokia Corporation
  *
- * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
  *          Jarkko Nikula <jhnikula@gmail.com>
  *
index 580f48571303a0023e65fba304080058ce11bd8d..33ebc46b45b5bfe9030ff062c30ad77d02c4f3c4 100644 (file)
@@ -155,6 +155,15 @@ config SND_SOC_RAUMFELD
        help
          Say Y if you want to add support for SoC audio on Raumfeld devices
 
+config SND_PXA2XX_SOC_HX4700
+       tristate "SoC Audio support for HP iPAQ hx4700"
+       depends on SND_PXA2XX_SOC && MACH_H4700
+       select SND_PXA2XX_SOC_I2S
+       select SND_SOC_AK4641
+       help
+         Say Y if you want to add support for SoC audio on the
+         HP iPAQ hx4700.
+
 config SND_PXA2XX_SOC_MAGICIAN
        tristate "SoC Audio support for HTC Magician"
        depends on SND_PXA2XX_SOC && MACH_MAGICIAN
index 07660165ec8d70cff80726004f9cec56843b2e66..af357623be9dccc7478aa2df03a1f9338eef4190 100644 (file)
@@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o
 snd-soc-saarb-objs := saarb.o
 snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
+snd-soc-hx4700-objs := hx4700.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-z2-objs := z2.o
@@ -37,6 +38,7 @@ 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_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
index 9027da466caeac67a4093d6d371e263553d228ae..28757fb9df31d49ac5c37f63ae668a157338949c 100644 (file)
@@ -310,7 +310,7 @@ static struct snd_soc_dai_link corgi_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c
new file mode 100644 (file)
index 0000000..65c1248
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * SoC audio for HP iPAQ hx4700
+ *
+ * Copyright (c) 2009 Philipp Zabel
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the 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/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hx4700.h>
+#include <asm/mach-types.h>
+#include "pxa2xx-i2s.h"
+
+#include "../codecs/ak4641.h"
+
+static struct snd_soc_jack hs_jack;
+
+/* Headphones jack detection DAPM pin */
+static struct snd_soc_jack_pin hs_jack_pin[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Speaker",
+               /* disable speaker when hp jack is inserted */
+               .mask   = SND_JACK_HEADPHONE,
+               .invert = 1,
+       },
+};
+
+/* Headphones jack detection GPIO */
+static struct snd_soc_jack_gpio hs_jack_gpio = {
+       .gpio           = GPIO75_HX4700_EARPHONE_nDET,
+       .invert         = true,
+       .name           = "hp-gpio",
+       .report         = SND_JACK_HEADPHONE,
+       .debounce_time  = 200,
+};
+
+/*
+ * iPAQ hx4700 uses I2S for capture and playback.
+ */
+static int hx4700_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->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret = 0;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+                       SND_SOC_DAIFMT_MSB | 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_MSB | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the I2S system clock as output */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+                       SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       /* inform codec driver about clock freq *
+        * (PXA I2S always uses divider 256)    */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
+                       SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops hx4700_ops = {
+       .hw_params = hx4700_hw_params,
+};
+
+static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *k, int event)
+{
+       gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event));
+       return 0;
+}
+
+static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *k, int event)
+{
+       gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event));
+       return 0;
+}
+
+/* hx4700 machine dapm widgets */
+static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
+       SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
+       SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
+};
+
+/* hx4700 machine audio_map */
+static const struct snd_soc_dapm_route hx4700_audio_map[] = {
+
+       /* Headphone connected to LOUT, ROUT */
+       {"Headphone Jack", NULL, "LOUT"},
+       {"Headphone Jack", NULL, "ROUT"},
+
+       /* Speaker connected to MOUT2 */
+       {"Speaker", NULL, "MOUT2"},
+
+       /* Microphone connected to MICIN */
+       {"MICIN", NULL, "Built-in Microphone"},
+       {"AIN", NULL, "MICOUT"},
+};
+
+/*
+ * Logic for a ak4641 as connected on a HP iPAQ hx4700
+ */
+static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       /* NC codec pins */
+       /* FIXME: is anything connected here? */
+       snd_soc_dapm_nc_pin(dapm, "MOUT1");
+       snd_soc_dapm_nc_pin(dapm, "MICEXT");
+       snd_soc_dapm_nc_pin(dapm, "AUX");
+
+       /* Jack detection API stuff */
+       err = snd_soc_jack_new(codec, "Headphone Jack",
+                               SND_JACK_HEADPHONE, &hs_jack);
+       if (err)
+               return err;
+
+       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
+                                       hs_jack_pin);
+       if (err)
+               return err;
+
+       err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
+
+       return err;
+}
+
+/* hx4700 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link hx4700_dai = {
+       .name = "ak4641",
+       .stream_name = "AK4641",
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "ak4641-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "ak4641.0-0012",
+       .init = hx4700_ak4641_init,
+       .ops = &hx4700_ops,
+};
+
+/* hx4700 audio machine driver */
+static struct snd_soc_card snd_soc_card_hx4700 = {
+       .name                   = "iPAQ hx4700",
+       .dai_link               = &hx4700_dai,
+       .num_links              = 1,
+       .dapm_widgets           = hx4700_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(hx4700_dapm_widgets),
+       .dapm_routes            = hx4700_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(hx4700_audio_map),
+};
+
+static struct gpio hx4700_audio_gpios[] = {
+       { GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" },
+       { GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" },
+};
+
+static int __devinit hx4700_audio_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (!machine_is_h4700())
+               return -ENODEV;
+
+       ret = gpio_request_array(hx4700_audio_gpios,
+                               ARRAY_SIZE(hx4700_audio_gpios));
+       if (ret)
+               return ret;
+
+       snd_soc_card_hx4700.dev = &pdev->dev;
+       ret = snd_soc_register_card(&snd_soc_card_hx4700);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int __devexit hx4700_audio_remove(struct platform_device *pdev)
+{
+       snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
+       snd_soc_unregister_card(&snd_soc_card_hx4700);
+
+       gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
+       gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
+
+       gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios));
+       return 0;
+}
+
+static struct platform_driver hx4700_audio_driver = {
+       .driver = {
+               .name = "hx4700-audio",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe  = hx4700_audio_probe,
+       .remove = __devexit_p(hx4700_audio_remove),
+};
+
+static int __init hx4700_modinit(void)
+{
+       return platform_driver_register(&hx4700_audio_driver);
+}
+module_init(hx4700_modinit);
+
+static void __exit hx4700_modexit(void)
+{
+       platform_driver_unregister(&hx4700_audio_driver);
+}
+
+module_exit(hx4700_modexit);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx4700-audio");
index a7d4999f9b24f4c9d202b9d21647760be483502a..da3ae4316cf2b9930d46fd2cf47f01c357f4f376 100644 (file)
@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
index 8e1571350630ecfeacacdd93eaab5a6a76c485d8..b253d864868a558001dd9e6e90b0e33d739a254d 100644 (file)
@@ -42,6 +42,7 @@
 
 static int spitz_jack_func;
 static int spitz_spk_func;
+static int spitz_mic_gpio;
 
 static void spitz_ext_control(struct snd_soc_codec *codec)
 {
@@ -217,14 +218,7 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol,
 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *k, int event)
 {
-       if (machine_is_borzoi() || machine_is_spitz())
-               gpio_set_value(SPITZ_GPIO_MIC_BIAS,
-                               SND_SOC_DAPM_EVENT_ON(event));
-
-       if (machine_is_akita())
-               gpio_set_value(AKITA_GPIO_MIC_BIAS,
-                               SND_SOC_DAPM_EVENT_ON(event));
-
+       gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event));
        return 0;
 }
 
@@ -339,22 +333,45 @@ static int __init spitz_init(void)
        if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
                return -ENODEV;
 
+       if (machine_is_borzoi() || machine_is_spitz())
+               spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
+       else
+               spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
+
+       ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
+       if (ret)
+               goto err1;
+
+       ret = gpio_direction_output(spitz_mic_gpio, 0);
+       if (ret)
+               goto err2;
+
        spitz_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!spitz_snd_device)
-               return -ENOMEM;
+       if (!spitz_snd_device) {
+               ret = -ENOMEM;
+               goto err2;
+       }
 
        platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
-       ret = platform_device_add(spitz_snd_device);
 
+       ret = platform_device_add(spitz_snd_device);
        if (ret)
-               platform_device_put(spitz_snd_device);
+               goto err3;
+
+       return 0;
 
+err3:
+       platform_device_put(spitz_snd_device);
+err2:
+       gpio_free(spitz_mic_gpio);
+err1:
        return ret;
 }
 
 static void __exit spitz_exit(void)
 {
        platform_device_unregister(spitz_snd_device);
+       gpio_free(spitz_mic_gpio);
 }
 
 module_init(spitz_init);
index a3fdfb63146938780e5bd7dfbfb46e5e256e4a36..459566bfcd3527cd8f142001645b3f8bfff8c1c3 100644 (file)
@@ -162,3 +162,18 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
        select SND_SAMSUNG_SPDIF
        help
          Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
+
+config SND_SOC_SMDK_WM8580_PCM
+       tristate "SoC PCM Audio support for WM8580 on SMDK"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+       select SND_SOC_WM8580
+       select SND_SAMSUNG_PCM
+       help
+         Say Y if you want to add support for SoC audio on the SMDK.
+
+config SND_SOC_SPEYSIDE
+       tristate "Audio support for Wolfson Speyside"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM8915
+       select SND_SOC_WM9081
index 294dec05c26d486e357eabe4ffba7f6574e7e0b0..683843a2744fd5f4f1c56d3c3ff0560e58e9096c 100644 (file)
@@ -34,6 +34,8 @@ snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
+snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
+snd-soc-speyside-objs := speyside.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -51,3 +53,5 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
+obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
index f6b3a3ce59196078e11c670c94a417edc1517b5b..eb6d72ed55a7d53accac1809921572ba92570d87 100644 (file)
@@ -236,18 +236,17 @@ static struct snd_soc_dai_link goni_dai[] = {
        .name = "WM8994",
        .stream_name = "WM8994 HiFi",
        .cpu_dai_name = "samsung-i2s.0",
-       .codec_dai_name = "wm8994-hifi",
+       .codec_dai_name = "wm8994-aif1",
        .platform_name = "samsung-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
+       .codec_name = "wm8994-codec.0-001a",
        .init = goni_wm8994_init,
        .ops = &goni_hifi_ops,
 }, {
        .name = "WM8994 Voice",
        .stream_name = "Voice",
        .cpu_dai_name = "goni-voice-dai",
-       .codec_dai_name = "wm8994-voice",
-       .platform_name = "samsung-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
+       .codec_dai_name = "wm8994-aif2",
+       .codec_name = "wm8994-codec.0-001a",
        .ops = &goni_voice_ops,
 },
 };
index 4522309756322e1b0dd85f8b5558abfa272b1946..16152ed086488fcc7ab15061b7a831adee42b741 100644 (file)
@@ -432,7 +432,6 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Voice via BT */
        .name = "Bluetooth",
        .stream_name = "Voice",
-       .platform_name = "samsung-audio",
        .cpu_dai_name = "dfbmcs320-pcm",
        .codec_dai_name = "wm8753-voice",
        .codec_name = "wm8753-codec.0-001a",
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
new file mode 100644 (file)
index 0000000..0d12092
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *  sound/soc/samsung/smdk_wm8580pcm.c
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co. Ltd
+ *
+ *  This program is free software; you can redistribute  it and/or  modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "pcm.h"
+
+/*
+ * Board Settings:
+ *  o '1' means 'ON'
+ *  o '0' means 'OFF'
+ *  o 'X' means 'Don't care'
+ *
+ * SMDK6410, SMDK6440, SMDK6450 Base B/D: CFG1-0000, CFG2-1111
+ * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000
+ */
+
+#define SMDK_WM8580_EXT_OSC 12000000
+#define SMDK_WM8580_EXT_MCLK 4096000
+#define SMDK_WM8580_EXT_VOICE 2048000
+
+static unsigned long mclk_freq;
+static unsigned long xtal_freq;
+
+/*
+ * If MCLK clock directly gets from XTAL, we don't have to use PLL
+ * to make MCLK, but if XTAL clock source connects with other codec
+ * pin (like XTI), we should have to set codec's PLL to make MCLK.
+ * Because Samsung SoC does not support pcmcdclk output like I2S.
+ */
+
+static int smdk_wm8580_pcm_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->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int rfs, ret;
+
+       switch (params_rate(params)) {
+       case 8000:
+               break;
+       default:
+               printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
+               __func__, __LINE__, params_rate(params));
+               return -EINVAL;
+       }
+
+       rfs = mclk_freq / params_rate(params) / 2;
+
+       /* Set the codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
+                               | SND_SOC_DAIFMT_IB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* Set the cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
+                               | SND_SOC_DAIFMT_IB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       if (mclk_freq == xtal_freq) {
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
+                                               mclk_freq, SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+                                               WM8580_CLKSRC_MCLK);
+               if (ret < 0)
+                       return ret;
+       } else {
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+                                               mclk_freq, SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+                                               WM8580_CLKSRC_PLLA);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+                                               xtal_freq, mclk_freq);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Set PCM source clock on CPU */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
+                                       mclk_freq, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* Set SCLK_DIV for making bclk */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops smdk_wm8580_pcm_ops = {
+       .hw_params = smdk_wm8580_pcm_hw_params,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+       {
+               .name = "WM8580 PAIF PCM RX",
+               .stream_name = "Playback",
+               .cpu_dai_name = "samsung-pcm.0",
+               .codec_dai_name = "wm8580-hifi-playback",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8580-codec.0-001b",
+               .ops = &smdk_wm8580_pcm_ops,
+       }, {
+               .name = "WM8580 PAIF PCM TX",
+               .stream_name = "Capture",
+               .cpu_dai_name = "samsung-pcm.0",
+               .codec_dai_name = "wm8580-hifi-capture",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8580-codec.0-001b",
+               .ops = &smdk_wm8580_pcm_ops,
+       },
+};
+
+static struct snd_soc_card smdk_pcm = {
+       .name = "SMDK-PCM",
+       .dai_link = smdk_dai,
+       .num_links = 2,
+};
+
+/*
+ * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1)
+ * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4),
+ * 2.0484Mhz, directly with MCLK both Codec and SoC.
+ */
+static int __devinit snd_smdk_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+
+       xtal_freq = SMDK_WM8580_EXT_OSC;
+       mclk_freq = SMDK_WM8580_EXT_MCLK;
+
+       if (machine_is_smdkc110() || machine_is_smdkv210())
+               xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
+
+       smdk_pcm.dev = &pdev->dev;
+       ret = snd_soc_register_card(&smdk_pcm);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit snd_smdk_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&smdk_pcm);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver snd_smdk_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "samsung-smdk-pcm",
+       },
+       .probe = snd_smdk_probe,
+       .remove = __devexit_p(snd_smdk_remove),
+};
+
+static int __init smdk_audio_init(void)
+{
+       return platform_driver_register(&snd_smdk_driver);
+}
+
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+       platform_driver_unregister(&snd_smdk_driver);
+}
+
+module_exit(smdk_audio_exit);
+
+MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
new file mode 100644 (file)
index 0000000..360a333
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Speyside audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the 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/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+
+#include "../codecs/wm8915.h"
+#include "../codecs/wm9081.h"
+
+#define WM8915_HPSEL_GPIO 214
+
+static int speyside_set_bias_level(struct snd_soc_card *card,
+                                  enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+                                            32768, SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+                                         0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL\n");
+                       return ret;
+               }
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int speyside_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
+                                 32768, 256 * 48000);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL,
+                                    256 * 48000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops speyside_ops = {
+       .hw_params = speyside_hw_params,
+};
+
+static struct snd_soc_jack speyside_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin speyside_headset_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+/* Default the headphone selection to active high */
+static int speyside_jack_polarity;
+
+static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
+                               struct snd_soc_dapm_widget *sink)
+{
+       if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
+               return 1;
+       if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
+               return 1;
+
+       return 0;
+}
+
+static void speyside_set_polarity(struct snd_soc_codec *codec,
+                                 int polarity)
+{
+       speyside_jack_polarity = !polarity;
+       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+       /* Re-run DAPM to make sure we're using the correct mic bias */
+       snd_soc_dapm_sync(&codec->dapm);
+}
+
+static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+       if (ret != 0)
+               pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
+       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_HEADSET | SND_JACK_BTN_0,
+                              &speyside_headset);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&speyside_headset,
+                                   ARRAY_SIZE(speyside_headset_pins),
+                                   speyside_headset_pins);
+       if (ret)
+               return ret;
+
+       wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+
+       return 0;
+}
+
+static int speyside_late_probe(struct snd_soc_card *card)
+{
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
+
+       return 0;
+}
+
+static struct snd_soc_dai_link speyside_dai[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8915-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8915.1-001a",
+               .init = speyside_wm8915_init,
+               .ops = &speyside_ops,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm8915-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .ops = &speyside_ops,
+               .ignore_suspend = 1,
+       },
+};
+
+static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+{
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT");
+
+       /* At any time the WM9081 is active it will have this clock */
+       return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK,
+                                       48000 * 256, 0);
+}
+
+static struct snd_soc_aux_dev speyside_aux_dev[] = {
+       {
+               .name = "wm9081",
+               .codec_name = "wm9081.1-006c",
+               .init = speyside_wm9081_init,
+       },
+};
+
+static struct snd_soc_codec_conf speyside_codec_conf[] = {
+       {
+               .dev_name = "wm9081.1-006c",
+               .name_prefix = "Sub",
+       },
+};
+
+static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Main Speaker"),
+       SOC_DAPM_PIN_SWITCH("Main DMIC"),
+       SOC_DAPM_PIN_SWITCH("Main AMIC"),
+       SOC_DAPM_PIN_SWITCH("WM1250 Input"),
+       SOC_DAPM_PIN_SWITCH("WM1250 Output"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+       SND_SOC_DAPM_SPK("Main Speaker", NULL),
+
+       SND_SOC_DAPM_MIC("Main AMIC", NULL),
+       SND_SOC_DAPM_MIC("Main DMIC", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+       { "IN1RN", NULL, "MICB1" },
+       { "IN1RP", NULL, "MICB1" },
+       { "IN1RN", NULL, "MICB2" },
+       { "IN1RP", NULL, "MICB2" },
+       { "MICB1", NULL, "Headset Mic", speyside_get_micbias },
+       { "MICB2", NULL, "Headset Mic", speyside_get_micbias },
+
+       { "IN1LP", NULL, "MICB2" },
+       { "IN1RN", NULL, "MICB1" },
+       { "MICB2", NULL, "Main AMIC" },
+
+       { "DMIC1DAT", NULL, "MICB1" },
+       { "DMIC2DAT", NULL, "MICB1" },
+       { "MICB1", NULL, "Main DMIC" },
+
+       { "Headphone", NULL, "HPOUT1L" },
+       { "Headphone", NULL, "HPOUT1R" },
+
+       { "Sub IN1", NULL, "HPOUT2L" },
+       { "Sub IN2", NULL, "HPOUT2R" },
+
+       { "Main Speaker", NULL, "Sub SPKN" },
+       { "Main Speaker", NULL, "Sub SPKP" },
+       { "Main Speaker", NULL, "SPKDAT" },
+};
+
+static struct snd_soc_card speyside = {
+       .name = "Speyside",
+       .dai_link = speyside_dai,
+       .num_links = ARRAY_SIZE(speyside_dai),
+       .aux_dev = speyside_aux_dev,
+       .num_aux_devs = ARRAY_SIZE(speyside_aux_dev),
+       .codec_conf = speyside_codec_conf,
+       .num_configs = ARRAY_SIZE(speyside_codec_conf),
+
+       .set_bias_level = speyside_set_bias_level,
+
+       .controls = controls,
+       .num_controls = ARRAY_SIZE(controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
+
+       .late_probe = speyside_late_probe,
+};
+
+static __devinit int speyside_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &speyside;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit speyside_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver speyside_driver = {
+       .driver = {
+               .name = "speyside",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = speyside_probe,
+       .remove = __devexit_p(speyside_remove),
+};
+
+static int __init speyside_audio_init(void)
+{
+       return platform_driver_register(&speyside_driver);
+}
+module_init(speyside_audio_init);
+
+static void __exit speyside_audio_exit(void)
+{
+       platform_driver_unregister(&speyside_driver);
+}
+module_exit(speyside_audio_exit);
+
+MODULE_DESCRIPTION("Speyside audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:speyside");
index 23c0e83d4c19244dc6da7ec326d10f8bce840b5c..4a9da6b5f4e1147921185b5a4d65856805d629b8 100644 (file)
@@ -86,8 +86,8 @@
 #define SE     (1 << 0)        /* Fix the master clock */
 
 /* CLK_RST */
-#define B_CLK          0x00000010
-#define A_CLK          0x00000001
+#define CRB    (1 << 4)
+#define CRA    (1 << 0)
 
 /* IO SHIFT / MACRO */
 #define BI_SHIFT       12
@@ -146,11 +146,20 @@ struct fsi_priv {
        void __iomem *base;
        struct fsi_master *master;
 
-       int chan_num;
        struct fsi_stream playback;
        struct fsi_stream capture;
 
+       int chan_num:16;
+       int clk_master:1;
+
        long rate;
+
+       /* for suspend/resume */
+       u32 saved_do_fmt;
+       u32 saved_di_fmt;
+       u32 saved_ckg1;
+       u32 saved_ckg2;
+       u32 saved_out_sel;
 };
 
 struct fsi_core {
@@ -171,6 +180,14 @@ struct fsi_master {
        struct fsi_core *core;
        struct sh_fsi_platform_info *info;
        spinlock_t lock;
+
+       /* for suspend/resume */
+       u32 saved_a_mclk;
+       u32 saved_b_mclk;
+       u32 saved_iemsk;
+       u32 saved_imsk;
+       u32 saved_clk_rst;
+       u32 saved_soft_rst;
 };
 
 /*
@@ -244,6 +261,11 @@ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
        return fsi->master;
 }
 
+static int fsi_is_clk_master(struct fsi_priv *fsi)
+{
+       return fsi->clk_master;
+}
+
 static int fsi_is_port_a(struct fsi_priv *fsi)
 {
        return fsi->master->base == fsi->base;
@@ -535,20 +557,45 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 }
 
 /*
- *             ctrl function
+ *             clock function
  */
+#define fsi_module_init(m, d)  __fsi_module_clk_ctrl(m, d, 1)
+#define fsi_module_kill(m, d)  __fsi_module_clk_ctrl(m, d, 0)
+static void __fsi_module_clk_ctrl(struct fsi_master *master,
+                                 struct device *dev,
+                                 int enable)
+{
+       pm_runtime_get_sync(dev);
+
+       if (enable) {
+               /* enable only SR */
+               fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
+               fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
+       } else {
+               /* clear all registers */
+               fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
+       }
 
-static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
+       pm_runtime_put_sync(dev);
+}
+
+#define fsi_port_start(f)      __fsi_port_clk_ctrl(f, 1)
+#define fsi_port_stop(f)       __fsi_port_clk_ctrl(f, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
-       u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
        struct fsi_master *master = fsi_get_master(fsi);
+       u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
+       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
+       int is_master = fsi_is_clk_master(fsi);
 
-       if (enable)
-               fsi_master_mask_set(master, CLK_RST, val, val);
-       else
-               fsi_master_mask_set(master, CLK_RST, val, 0);
+       fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
+       if (is_master)
+               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
+/*
+ *             ctrl function
+ */
 static void fsi_fifo_init(struct fsi_priv *fsi,
                          int is_play,
                          struct snd_soc_dai *dai)
@@ -601,18 +648,6 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
        }
 }
 
-static void fsi_soft_all_reset(struct fsi_master *master)
-{
-       /* port AB reset */
-       fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
-       mdelay(10);
-
-       /* soft reset */
-       fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
-       fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
-       mdelay(10);
-}
-
 static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 {
        struct snd_pcm_runtime *runtime;
@@ -793,14 +828,13 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
        struct fsi_priv *fsi = fsi_get_priv(substream);
        int is_play = fsi_is_play(substream);
        struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate;
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
 
        fsi_irq_disable(fsi, is_play);
-       fsi_clk_ctrl(fsi, 0);
 
-       set_rate = fsi_get_info_set_rate(master);
-       if (set_rate && fsi->rate)
+       if (fsi_is_clk_master(fsi))
                set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+
        fsi->rate = 0;
 
        pm_runtime_put_sync(dai->dev);
@@ -821,8 +855,10 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                                frames_to_bytes(runtime, runtime->period_size));
                ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
                fsi_irq_enable(fsi, is_play);
+               fsi_port_start(fsi);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+               fsi_port_stop(fsi);
                fsi_irq_disable(fsi, is_play);
                fsi_stream_pop(fsi, is_play);
                break;
@@ -876,6 +912,8 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+       struct fsi_master *master = fsi_get_master(fsi);
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
        u32 flags = fsi_get_info_flags(fsi);
        u32 data = 0;
        int ret;
@@ -886,6 +924,7 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
                data = DIMD | DOMD;
+               fsi->clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
@@ -893,6 +932,13 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                ret = -EINVAL;
                goto set_fmt_exit;
        }
+
+       if (fsi_is_clk_master(fsi) && !set_rate) {
+               dev_err(dai->dev, "platform doesn't have set_rate\n");
+               ret = -EINVAL;
+               goto set_fmt_exit;
+       }
+
        fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 
        /* set format */
@@ -919,13 +965,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate;
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
        int fsi_ver = master->core->ver;
        long rate = params_rate(params);
        int ret;
 
-       set_rate = fsi_get_info_set_rate(master);
-       if (!set_rate)
+       if (!fsi_is_clk_master(fsi))
                return 0;
 
        ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
@@ -987,7 +1032,6 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 
                fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
                udelay(10);
-               fsi_clk_ctrl(fsi, 1);
                ret = 0;
        }
 
@@ -1202,9 +1246,7 @@ static int fsi_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        dev_set_drvdata(&pdev->dev, master);
 
-       pm_runtime_get_sync(&pdev->dev);
-       fsi_soft_all_reset(master);
-       pm_runtime_put_sync(&pdev->dev);
+       fsi_module_init(master, &pdev->dev);
 
        ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
                          id_entry->name, master);
@@ -1248,6 +1290,8 @@ static int fsi_remove(struct platform_device *pdev)
 
        master = dev_get_drvdata(&pdev->dev);
 
+       fsi_module_kill(master, &pdev->dev);
+
        free_irq(master->irq, master);
        pm_runtime_disable(&pdev->dev);
 
@@ -1260,6 +1304,82 @@ static int fsi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void __fsi_suspend(struct fsi_priv *fsi,
+                         struct device *dev,
+                         set_rate_func set_rate)
+{
+       fsi->saved_do_fmt       = fsi_reg_read(fsi, DO_FMT);
+       fsi->saved_di_fmt       = fsi_reg_read(fsi, DI_FMT);
+       fsi->saved_ckg1         = fsi_reg_read(fsi, CKG1);
+       fsi->saved_ckg2         = fsi_reg_read(fsi, CKG2);
+       fsi->saved_out_sel      = fsi_reg_read(fsi, OUT_SEL);
+
+       if (fsi_is_clk_master(fsi))
+               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+}
+
+static void __fsi_resume(struct fsi_priv *fsi,
+                        struct device *dev,
+                        set_rate_func set_rate)
+{
+       fsi_reg_write(fsi, DO_FMT,      fsi->saved_do_fmt);
+       fsi_reg_write(fsi, DI_FMT,      fsi->saved_di_fmt);
+       fsi_reg_write(fsi, CKG1,        fsi->saved_ckg1);
+       fsi_reg_write(fsi, CKG2,        fsi->saved_ckg2);
+       fsi_reg_write(fsi, OUT_SEL,     fsi->saved_out_sel);
+
+       if (fsi_is_clk_master(fsi))
+               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
+}
+
+static int fsi_suspend(struct device *dev)
+{
+       struct fsi_master *master = dev_get_drvdata(dev);
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+       pm_runtime_get_sync(dev);
+
+       __fsi_suspend(&master->fsia, dev, set_rate);
+       __fsi_suspend(&master->fsib, dev, set_rate);
+
+       master->saved_a_mclk    = fsi_core_read(master, a_mclk);
+       master->saved_b_mclk    = fsi_core_read(master, b_mclk);
+       master->saved_iemsk     = fsi_core_read(master, iemsk);
+       master->saved_imsk      = fsi_core_read(master, imsk);
+       master->saved_clk_rst   = fsi_master_read(master, CLK_RST);
+       master->saved_soft_rst  = fsi_master_read(master, SOFT_RST);
+
+       fsi_module_kill(master, dev);
+
+       pm_runtime_put_sync(dev);
+
+       return 0;
+}
+
+static int fsi_resume(struct device *dev)
+{
+       struct fsi_master *master = dev_get_drvdata(dev);
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+       pm_runtime_get_sync(dev);
+
+       fsi_module_init(master, dev);
+
+       fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
+       fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
+       fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
+       fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
+       fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
+       fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+
+       __fsi_resume(&master->fsia, dev, set_rate);
+       __fsi_resume(&master->fsib, dev, set_rate);
+
+       pm_runtime_put_sync(dev);
+
+       return 0;
+}
+
 static int fsi_runtime_nop(struct device *dev)
 {
        /* Runtime PM callback shared between ->runtime_suspend()
@@ -1273,6 +1393,8 @@ static int fsi_runtime_nop(struct device *dev)
 }
 
 static struct dev_pm_ops fsi_pm_ops = {
+       .suspend                = fsi_suspend,
+       .resume                 = fsi_resume,
        .runtime_suspend        = fsi_runtime_nop,
        .runtime_resume         = fsi_runtime_nop,
 };
index 5d76da43b14c1ddfa0e53c0c60a358263bb7d488..06b7b81a16016f714b9bb2597dc705c0bab20ffb 100644 (file)
 
 #include <trace/events/asoc.h>
 
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
+#ifdef CONFIG_SPI_MASTER
+static int do_spi_write(void *control, const char *data, int len)
 {
+       struct spi_device *spi = control;
        int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
 
-       ret = snd_soc_cache_read(codec, reg, &val);
+       ret = spi_write(spi, data, len);
        if (ret < 0)
-               return -1;
-       return val;
+               return ret;
+
+       return len;
 }
+#endif
 
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value, const void *data, int len)
 {
-       u8 data[2];
        int ret;
 
-       data[0] = (reg << 4) | ((value >> 8) & 0x000f);
-       data[1] = value & 0x00ff;
-
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
+           reg < codec->driver->reg_cache_size &&
+           !codec->cache_bypass) {
                ret = snd_soc_cache_write(codec, reg, value);
                if (ret < 0)
                        return -1;
@@ -64,8 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
                return 0;
        }
 
-       ret = codec->hw_write(codec->control_data, data, 2);
-       if (ret == 2)
+       ret = codec->hw_write(codec->control_data, data, len);
+       if (ret == len)
                return 0;
        if (ret < 0)
                return ret;
@@ -73,50 +61,19 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_4_12_spi_write(void *control_data, const char *data,
-                                int len)
-{
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[1];
-       msg[1] = data[0];
-
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-#else
-#define snd_soc_4_12_spi_write NULL
-#endif
-
-static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
+static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
 {
        int ret;
        unsigned int val;
 
        if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
+           snd_soc_codec_volatile_register(codec, reg) ||
+           codec->cache_bypass) {
+               if (codec->cache_only)
+                       return -1;
 
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
+               BUG_ON(!codec->hw_read);
+               return codec->hw_read(codec, reg);
        }
 
        ret = snd_soc_cache_read(codec, reg, &val);
@@ -125,259 +82,117 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
        return val;
 }
 
-static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
+static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
+                                     unsigned int reg)
 {
-       u8 data[2];
-       int ret;
-
-       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-       data[1] = value & 0x00ff;
-
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, 2);
-       if (ret == 2)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
+       return do_hw_read(codec, reg);
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_7_9_spi_write(void *control_data, const char *data,
-                                int len)
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+                             unsigned int value)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
+       u16 data;
 
-       if (len <= 0)
-               return 0;
+       data = cpu_to_be16((reg << 12) | (value & 0xffffff));
 
-       msg[0] = data[0];
-       msg[1] = data[1];
+       return do_hw_write(codec, reg, value, &data, 2);
+}
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
+static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       return do_hw_read(codec, reg);
+}
 
-       t.tx_buf = &msg[0];
-       t.len = len;
+static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u8 data[2];
 
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
 
-       return len;
+       return do_hw_write(codec, reg, value, data, 2);
 }
-#else
-#define snd_soc_7_9_spi_write NULL
-#endif
 
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
        u8 data[2];
-       int ret;
 
        reg &= 0xff;
        data[0] = reg;
        data[1] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 2);
 }
 
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       reg &= 0xff;
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_8_spi_write(void *control_data, const char *data,
-                                int len)
-{
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_hw_read(codec, reg);
 }
-#else
-#define snd_soc_8_8_spi_write NULL
-#endif
 
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
        u8 data[3];
-       int ret;
 
        data[0] = reg;
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       if (codec->hw_write(codec->control_data, data, 3) == 3)
-               return 0;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 3);
 }
 
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               BUG_ON(!codec->hw_read);
-               return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_16_spi_write(void *control_data, const char *data,
-                                int len)
-{
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[3];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-       msg[2] = data[2];
-
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_hw_read(codec, reg);
 }
-#else
-#define snd_soc_8_16_spi_write NULL
-#endif
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
-                                         unsigned int r)
+static unsigned int do_i2c_read(struct snd_soc_codec *codec,
+                               void *reg, int reglen,
+                               void *data, int datalen)
 {
        struct i2c_msg xfer[2];
-       u8 reg = r;
-       u8 data;
        int ret;
        struct i2c_client *client = codec->control_data;
 
        /* Write register */
        xfer[0].addr = client->addr;
        xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
+       xfer[0].len = reglen;
+       xfer[0].buf = reg;
 
        /* Read data */
        xfer[1].addr = client->addr;
        xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 1;
-       xfer[1].buf = &data;
+       xfer[1].len = datalen;
+       xfer[1].buf = data;
 
        ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       if (ret == 2)
                return 0;
-       }
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+#endif
 
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
+                                        unsigned int r)
+{
+       u8 reg = r;
+       u8 data;
+       int ret;
+
+       ret = do_i2c_read(codec, &reg, 1, &data, 1);
+       if (ret < 0)
+               return 0;
        return data;
 }
 #else
@@ -388,30 +203,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u8 reg = r;
        u16 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
 
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 2;
-       xfer[1].buf = (u8 *)&data;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 1, &data, 2);
+       if (ret < 0)
                return 0;
-       }
-
        return (data >> 8) | ((data & 0xff) << 8);
 }
 #else
@@ -422,30 +220,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u16 reg = r;
        u8 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 2;
-       xfer[0].buf = (u8 *)&reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 1;
-       xfer[1].buf = &data;
 
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 2, &data, 1);
+       if (ret < 0)
                return 0;
-       }
-
        return data;
 }
 #else
@@ -453,120 +234,34 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 #endif
 
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
+                                     unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       reg &= 0xff;
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
+                             unsigned int value)
 {
        u8 data[3];
-       int ret;
 
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = value;
 
-       reg &= 0xff;
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, 3);
-       if (ret == 3)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_8_spi_write(void *control_data, const char *data,
-                                int len)
-{
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[3];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-       msg[2] = data[2];
-
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_hw_write(codec, reg, value, data, 3);
 }
-#else
-#define snd_soc_16_8_spi_write NULL
-#endif
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
                                           unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u16 reg = cpu_to_be16(r);
        u16 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 2;
-       xfer[0].buf = (u8 *)&reg;
 
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 2;
-       xfer[1].buf = (u8 *)&data;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 2, &data, 2);
+       if (ret < 0)
                return 0;
-       }
-
        return be16_to_cpu(data);
 }
 #else
@@ -576,52 +271,59 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
                                       unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               BUG_ON(!codec->hw_read);
-               return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                               unsigned int value)
 {
        u8 data[4];
-       int ret;
 
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = (value >> 8) & 0xff;
        data[3] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
+       return do_hw_write(codec, reg, value, data, 4);
+}
 
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
+/* Primitive bulk write support for soc-cache.  The data pointed to by
+ * `data' needs to already be in the form the hardware expects
+ * including any leading register specific data.  Any data written
+ * through this function will not go through the cache as it only
+ * handles writing to volatile or out of bounds registers.
+ */
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+                                    const void *data, size_t len)
+{
+       int ret;
+
+       /* To ensure that we don't get out of sync with the cache, check
+        * whether the base register is volatile or if we've directly asked
+        * to bypass the cache.  Out of bounds registers are considered
+        * volatile.
+        */
+       if (!codec->cache_bypass
+           && !snd_soc_codec_volatile_register(codec, reg)
+           && reg < codec->driver->reg_cache_size)
+               return -EINVAL;
+
+       switch (codec->control_type) {
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+       case SND_SOC_I2C:
+               ret = i2c_master_send(codec->control_data, data, len);
+               break;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       case SND_SOC_SPI:
+               ret = spi_write(codec->control_data, data, len);
+               break;
+#endif
+       default:
+               BUG();
        }
 
-       ret = codec->hw_write(codec->control_data, data, 4);
-       if (ret == 4)
+       if (ret == len)
                return 0;
        if (ret < 0)
                return ret;
@@ -629,79 +331,40 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_16_spi_write(void *control_data, const char *data,
-                                int len)
-{
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[4];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-       msg[2] = data[2];
-       msg[3] = data[3];
-
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-#else
-#define snd_soc_16_16_spi_write NULL
-#endif
-
 static struct {
        int addr_bits;
        int data_bits;
        int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
-       int (*spi_write)(void *, const char *, int);
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 } io_types[] = {
        {
                .addr_bits = 4, .data_bits = 12,
                .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
-               .spi_write = snd_soc_4_12_spi_write,
        },
        {
                .addr_bits = 7, .data_bits = 9,
                .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
-               .spi_write = snd_soc_7_9_spi_write,
        },
        {
                .addr_bits = 8, .data_bits = 8,
                .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
                .i2c_read = snd_soc_8_8_read_i2c,
-               .spi_write = snd_soc_8_8_spi_write,
        },
        {
                .addr_bits = 8, .data_bits = 16,
                .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
                .i2c_read = snd_soc_8_16_read_i2c,
-               .spi_write = snd_soc_8_16_spi_write,
        },
        {
                .addr_bits = 16, .data_bits = 8,
                .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
                .i2c_read = snd_soc_16_8_read_i2c,
-               .spi_write = snd_soc_16_8_spi_write,
        },
        {
                .addr_bits = 16, .data_bits = 16,
                .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
                .i2c_read = snd_soc_16_16_read_i2c,
-               .spi_write = snd_soc_16_16_spi_write,
        },
 };
 
@@ -709,7 +372,6 @@ static struct {
  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
  *
  * @codec: CODEC to configure.
- * @type: Type of cache.
  * @addr_bits: Number of bits of register address data.
  * @data_bits: Number of bits of data per register.
  * @control: Control bus used.
@@ -744,6 +406,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 
        codec->write = io_types[i].write;
        codec->read = io_types[i].read;
+       codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
 
        switch (control) {
        case SND_SOC_CUSTOM:
@@ -762,8 +425,9 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_SPI:
-               if (io_types[i].spi_write)
-                       codec->hw_write = io_types[i].spi_write;
+#ifdef CONFIG_SPI_MASTER
+               codec->hw_write = do_spi_write;
+#endif
 
                codec->control_data = container_of(codec->dev,
                                                   struct spi_device,
@@ -889,6 +553,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
                rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
                if (rbnode->value == rbnode->defval)
                        continue;
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, rbnode->reg));
                ret = snd_soc_cache_read(codec, rbnode->reg, &val);
                if (ret)
                        return ret;
@@ -1149,6 +815,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
 
        lzo_blocks = codec->reg_cache;
        for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, i));
                ret = snd_soc_cache_read(codec, i, &val);
                if (ret)
                        return ret;
@@ -1407,6 +1075,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
 
        codec_drv = codec->driver;
        for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, i));
                ret = snd_soc_cache_read(codec, i, &val);
                if (ret)
                        return ret;
@@ -1523,7 +1193,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
                                codec->cache_ops->name, codec->name);
                return codec->cache_ops->init(codec);
        }
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 /*
@@ -1538,7 +1208,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
                                codec->cache_ops->name, codec->name);
                return codec->cache_ops->exit(codec);
        }
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 /**
@@ -1562,7 +1232,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
        }
 
        mutex_unlock(&codec->cache_rw_mutex);
-       return -EINVAL;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
 
@@ -1587,7 +1257,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
        }
 
        mutex_unlock(&codec->cache_rw_mutex);
-       return -EINVAL;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
 
@@ -1610,7 +1280,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec)
        }
 
        if (!codec->cache_ops || !codec->cache_ops->sync)
-               return -EINVAL;
+               return -ENOSYS;
 
        if (codec->cache_ops->name)
                name = codec->cache_ops->name;
@@ -1677,3 +1347,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
        return codec->driver->reg_access_default[index].read;
 }
 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
+
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+                                     unsigned int reg)
+{
+       int index;
+
+       if (reg >= codec->driver->reg_cache_size)
+               return 1;
+       index = snd_soc_get_reg_access_index(codec, reg);
+       if (index < 0)
+               return 0;
+       return codec->driver->reg_access_default[index].write;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);
index d8562ce4de7ab9ea5796e0521261fe520d8a3330..bb7cd58129459cbd9f0fb729ad61d4ed7070ee18 100644 (file)
@@ -242,7 +242,7 @@ static ssize_t codec_reg_write_file(struct file *file,
                const char __user *user_buf, size_t count, loff_t *ppos)
 {
        char buf[32];
-       int buf_size;
+       size_t buf_size;
        char *start = buf;
        unsigned long reg, value;
        int step = 1;
@@ -302,13 +302,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
                printk(KERN_WARNING
                       "ASoC: Failed to create codec register debugfs file\n");
 
-       codec->dapm.debugfs_dapm = debugfs_create_dir("dapm",
-                                                codec->debugfs_codec_root);
-       if (!codec->dapm.debugfs_dapm)
-               printk(KERN_WARNING
-                      "Failed to create DAPM debugfs directory\n");
-
-       snd_soc_dapm_debugfs_init(&codec->dapm);
+       snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
 
 static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
@@ -555,7 +549,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (platform->driver->ops->open) {
+       if (platform->driver->ops && platform->driver->ops->open) {
                ret = platform->driver->ops->open(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
@@ -685,7 +679,7 @@ machine_err:
                codec_dai->driver->ops->shutdown(substream, codec_dai);
 
 codec_dai_err:
-       if (platform->driver->ops->close)
+       if (platform->driver->ops && platform->driver->ops->close)
                platform->driver->ops->close(substream);
 
 platform_err:
@@ -767,7 +761,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
                rtd->dai_link->ops->shutdown(substream);
 
-       if (platform->driver->ops->close)
+       if (platform->driver->ops && platform->driver->ops->close)
                platform->driver->ops->close(substream);
        cpu_dai->runtime = NULL;
 
@@ -810,7 +804,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                }
        }
 
-       if (platform->driver->ops->prepare) {
+       if (platform->driver->ops && platform->driver->ops->prepare) {
                ret = platform->driver->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform prepare error\n");
@@ -899,7 +893,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (platform->driver->ops->hw_params) {
+       if (platform->driver->ops && platform->driver->ops->hw_params) {
                ret = platform->driver->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform %s hw params failed\n",
@@ -952,7 +946,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
                rtd->dai_link->ops->hw_free(substream);
 
        /* free any DMA resources */
-       if (platform->driver->ops->hw_free)
+       if (platform->driver->ops && platform->driver->ops->hw_free)
                platform->driver->ops->hw_free(substream);
 
        /* now free hw params for the DAIs  */
@@ -980,7 +974,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                        return ret;
        }
 
-       if (platform->driver->ops->trigger) {
+       if (platform->driver->ops && platform->driver->ops->trigger) {
                ret = platform->driver->ops->trigger(substream, cmd);
                if (ret < 0)
                        return ret;
@@ -1009,7 +1003,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
        snd_pcm_uframes_t offset = 0;
        snd_pcm_sframes_t delay = 0;
 
-       if (platform->driver->ops->pointer)
+       if (platform->driver->ops && platform->driver->ops->pointer)
                offset = platform->driver->ops->pointer(substream);
 
        if (cpu_dai->driver->ops->delay)
@@ -1299,6 +1293,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai, *cpu_dai;
+       const char *platform_name;
 
        if (rtd->complete)
                return 1;
@@ -1351,13 +1346,18 @@ find_codec:
                        dai_link->codec_name);
 
 find_platform:
-       /* do we already have the CODEC DAI for this link ? */
-       if (rtd->platform) {
+       /* do we need a platform? */
+       if (rtd->platform)
                goto out;
-       }
-       /* no, then find CPU DAI from registered DAIs*/
+
+       /* if there's no platform we match on the empty platform */
+       platform_name = dai_link->platform_name;
+       if (!platform_name)
+               platform_name = "snd-soc-dummy";
+
+       /* no, then find one from the set of registered platforms */
        list_for_each_entry(platform, &platform_list, list) {
-               if (!strcmp(platform->name, dai_link->platform_name)) {
+               if (!strcmp(platform->name, platform_name)) {
                        rtd->platform = platform;
                        goto out;
                }
@@ -1453,6 +1453,16 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 }
 
+static void soc_remove_dai_links(struct snd_soc_card *card)
+{
+       int i;
+
+       for (i = 0; i < card->num_rtd; i++)
+               soc_remove_dai_link(card, i);
+
+       card->num_rtd = 0;
+}
+
 static void soc_set_name_prefix(struct snd_soc_card *card,
                                struct snd_soc_codec *codec)
 {
@@ -1483,6 +1493,12 @@ static int soc_probe_codec(struct snd_soc_card *card,
        if (!try_module_get(codec->dev->driver->owner))
                return -ENODEV;
 
+       soc_init_codec_debugfs(codec);
+
+       if (driver->dapm_widgets)
+               snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
+                                         driver->num_dapm_widgets);
+
        if (driver->probe) {
                ret = driver->probe(codec);
                if (ret < 0) {
@@ -1493,15 +1509,13 @@ static int soc_probe_codec(struct snd_soc_card *card,
                }
        }
 
-       if (driver->dapm_widgets)
-               snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
-                                         driver->num_dapm_widgets);
+       if (driver->controls)
+               snd_soc_add_controls(codec, driver->controls,
+                                    driver->num_controls);
        if (driver->dapm_routes)
                snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
                                        driver->num_dapm_routes);
 
-       soc_init_codec_debugfs(codec);
-
        /* mark codec as probed and add to card codec list */
        codec->probed = 1;
        list_add(&codec->card_list, &card->codec_dev_list);
@@ -1510,6 +1524,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
        return 0;
 
 err_probe:
+       soc_cleanup_codec_debugfs(codec);
        module_put(codec->dev->driver->owner);
 
        return ret;
@@ -1860,11 +1875,19 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        card->dapm.card = card;
        list_add(&card->dapm.list, &card->dapm_list);
 
+#ifdef CONFIG_DEBUG_FS
+       snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
+#endif
+
 #ifdef CONFIG_PM_SLEEP
        /* deferred resume work */
        INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 #endif
 
+       if (card->dapm_widgets)
+               snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
+                                         card->num_dapm_widgets);
+
        /* initialise the sound card only once */
        if (card->probe) {
                ret = card->probe(card);
@@ -1890,27 +1913,24 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
-       if (card->dapm_widgets)
-               snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
-                                         card->num_dapm_widgets);
+       /* We should have a non-codec control add function but we don't */
+       if (card->controls)
+               snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
+                                                     struct snd_soc_codec,
+                                                     card_list),
+                                    card->controls,
+                                    card->num_controls);
+
        if (card->dapm_routes)
                snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                                        card->num_dapm_routes);
 
-#ifdef CONFIG_DEBUG_FS
-       card->dapm.debugfs_dapm = debugfs_create_dir("dapm",
-                                                    card->debugfs_card_root);
-       if (!card->dapm.debugfs_dapm)
-               printk(KERN_WARNING
-                      "Failed to create card DAPM debugfs directory\n");
-
-       snd_soc_dapm_debugfs_init(&card->dapm);
-#endif
-
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
-                "%s",  card->name);
-       snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
                 "%s", card->name);
+       snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+                "%s", card->long_name ? card->long_name : card->name);
+       snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
+                "%s", card->driver_name ? card->driver_name : card->name);
 
        if (card->late_probe) {
                ret = card->late_probe(card);
@@ -1949,8 +1969,7 @@ probe_aux_dev_err:
                soc_remove_aux_dev(card, i);
 
 probe_dai_err:
-       for (i = 0; i < card->num_links; i++)
-               soc_remove_dai_link(card, i);
+       soc_remove_dai_links(card);
 
 card_probe_error:
        if (card->remove)
@@ -2012,8 +2031,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
                soc_remove_aux_dev(card, i);
 
        /* remove and free each DAI */
-       for (i = 0; i < card->num_rtd; i++)
-               soc_remove_dai_link(card, i);
+       soc_remove_dai_links(card);
 
        soc_cleanup_card_debugfs(card);
 
@@ -2021,6 +2039,8 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
        if (card->remove)
                card->remove(card);
 
+       snd_soc_dapm_free(&card->dapm);
+
        kfree(card->rtd);
        snd_card_free(card->snd_card);
        return 0;
@@ -2105,13 +2125,15 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
        rtd->pcm = pcm;
        pcm->private_data = rtd;
-       soc_pcm_ops.mmap = platform->driver->ops->mmap;
-       soc_pcm_ops.pointer = platform->driver->ops->pointer;
-       soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
-       soc_pcm_ops.copy = platform->driver->ops->copy;
-       soc_pcm_ops.silence = platform->driver->ops->silence;
-       soc_pcm_ops.ack = platform->driver->ops->ack;
-       soc_pcm_ops.page = platform->driver->ops->page;
+       if (platform->driver->ops) {
+               soc_pcm_ops.mmap = platform->driver->ops->mmap;
+               soc_pcm_ops.pointer = platform->driver->ops->pointer;
+               soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+               soc_pcm_ops.copy = platform->driver->ops->copy;
+               soc_pcm_ops.silence = platform->driver->ops->silence;
+               soc_pcm_ops.ack = platform->driver->ops->ack;
+               soc_pcm_ops.page = platform->driver->ops->page;
+       }
 
        if (playback)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -2119,10 +2141,13 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        if (capture)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-       ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: platform pcm constructor failed\n");
-               return ret;
+       if (platform->driver->pcm_new) {
+               ret = platform->driver->pcm_new(rtd->card->snd_card,
+                                               codec_dai, pcm);
+               if (ret < 0) {
+                       pr_err("asoc: platform pcm constructor failed\n");
+                       return ret;
+               }
        }
 
        pcm->private_free = platform->driver->pcm_free;
@@ -2149,6 +2174,42 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
 
+/**
+ * snd_soc_codec_readable_register: Report if a register is readable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is readable.
+ */
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       if (codec->readable_register)
+               return codec->readable_register(codec, reg);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
+
+/**
+ * snd_soc_codec_writable_register: Report if a register is writable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is writable.
+ */
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       if (codec->writable_register)
+               return codec->writable_register(codec, reg);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
+
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -2231,6 +2292,13 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_write);
 
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+                                   unsigned int reg, const void *data, size_t len)
+{
+       return codec->bulk_write_raw(codec, reg, data, len);
+}
+EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
+
 /**
  * snd_soc_update_bits - update codec register bits
  * @codec: audio codec
@@ -3291,6 +3359,8 @@ int snd_soc_register_card(struct snd_soc_card *card)
        if (!card->name || !card->dev)
                return -EINVAL;
 
+       dev_set_drvdata(card->dev, card);
+
        snd_soc_initialize_card_lists(card);
 
        soc_init_card_debugfs(card);
@@ -3412,7 +3482,7 @@ int snd_soc_register_dai(struct device *dev,
 
        dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
        if (dai == NULL)
-                       return -ENOMEM;
+               return -ENOMEM;
 
        /* create DAI component name */
        dai->name = fmt_single_name(dev, &dai->id);
@@ -3551,7 +3621,7 @@ int snd_soc_register_platform(struct device *dev,
 
        platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
        if (platform == NULL)
-                       return -ENOMEM;
+               return -ENOMEM;
 
        /* create platform component name */
        platform->name = fmt_single_name(dev, &platform->id);
@@ -3669,6 +3739,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->read = codec_drv->read;
        codec->volatile_register = codec_drv->volatile_register;
        codec->readable_register = codec_drv->readable_register;
+       codec->writable_register = codec_drv->writable_register;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
@@ -3703,6 +3774,8 @@ int snd_soc_register_codec(struct device *dev,
                        codec->volatile_register = snd_soc_default_volatile_register;
                if (!codec->readable_register)
                        codec->readable_register = snd_soc_default_readable_register;
+               if (!codec->writable_register)
+                       codec->writable_register = snd_soc_default_writable_register;
        }
 
        for (i = 0; i < num_dai; i++) {
@@ -3791,12 +3864,16 @@ static int __init snd_soc_init(void)
                pr_warn("ASoC: Failed to create platform list debugfs file\n");
 #endif
 
+       snd_soc_util_init();
+
        return platform_driver_register(&soc_driver);
 }
 module_init(snd_soc_init);
 
 static void __exit snd_soc_exit(void)
 {
+       snd_soc_util_exit();
+
 #ifdef CONFIG_DEBUG_FS
        debugfs_remove_recursive(snd_soc_debugfs_root);
 #endif
index 81c4052c127ccc150a63ca50780ddcc9357f25f7..456617e63789893c7d90f547cbc00f3c7ba168d5 100644 (file)
@@ -187,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_mixer_named_ctl: {
                int val;
                struct soc_mixer_control *mc = (struct soc_mixer_control *)
-                       w->kcontrols[i].private_value;
+                       w->kcontrol_news[i].private_value;
                unsigned int reg = mc->reg;
                unsigned int shift = mc->shift;
                int max = mc->max;
@@ -204,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        }
        break;
        case snd_soc_dapm_mux: {
-               struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+               struct soc_enum *e = (struct soc_enum *)
+                       w->kcontrol_news[i].private_value;
                int val, item, bitmask;
 
                for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
@@ -220,7 +221,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        }
        break;
        case snd_soc_dapm_virt_mux: {
-               struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+               struct soc_enum *e = (struct soc_enum *)
+                       w->kcontrol_news[i].private_value;
 
                p->connect = 0;
                /* since a virtual mux has no backing registers to
@@ -235,7 +237,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        break;
        case snd_soc_dapm_value_mux: {
                struct soc_enum *e = (struct soc_enum *)
-                       w->kcontrols[i].private_value;
+                       w->kcontrol_news[i].private_value;
                int val, item;
 
                val = snd_soc_read(w->codec, e->reg);
@@ -310,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
 
        /* search for mixer kcontrol */
        for (i = 0; i < dest->num_kcontrols; i++) {
-               if (!strcmp(control_name, dest->kcontrols[i].name)) {
+               if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
                        list_add(&path->list, &dapm->card->paths);
                        list_add(&path->list_sink, &dest->sources);
                        list_add(&path->list_source, &src->sinks);
-                       path->name = dest->kcontrols[i].name;
+                       path->name = dest->kcontrol_news[i].name;
                        dapm_set_path_status(dest, path, i);
                        return 0;
                }
@@ -322,43 +324,26 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
        return -ENODEV;
 }
 
-/* update dapm codec register bits */
-static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
+static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
+       const struct snd_kcontrol_new *kcontrol_new,
+       struct snd_kcontrol **kcontrol)
 {
-       int change, power;
-       unsigned int old, new;
-       struct snd_soc_codec *codec = widget->codec;
-       struct snd_soc_dapm_context *dapm = widget->dapm;
-       struct snd_soc_card *card = dapm->card;
-
-       /* check for valid widgets */
-       if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
-               widget->id == snd_soc_dapm_output ||
-               widget->id == snd_soc_dapm_hp ||
-               widget->id == snd_soc_dapm_mic ||
-               widget->id == snd_soc_dapm_line ||
-               widget->id == snd_soc_dapm_spk)
-               return 0;
-
-       power = widget->power;
-       if (widget->invert)
-               power = (power ? 0:1);
+       struct snd_soc_dapm_widget *w;
+       int i;
 
-       old = snd_soc_read(codec, widget->reg);
-       new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
+       *kcontrol = NULL;
 
-       change = old != new;
-       if (change) {
-               pop_dbg(dapm->dev, card->pop_time,
-                       "pop test %s : %s in %d ms\n",
-                       widget->name, widget->power ? "on" : "off",
-                       card->pop_time);
-               pop_wait(card->pop_time);
-               snd_soc_write(codec, widget->reg, new);
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               for (i = 0; i < w->num_kcontrols; i++) {
+                       if (&w->kcontrol_news[i] == kcontrol_new) {
+                               if (w->kcontrols)
+                                       *kcontrol = w->kcontrols[i];
+                               return 1;
+                       }
+               }
        }
-       dev_dbg(dapm->dev, "reg %x old %x new %x change %d\n", widget->reg,
-               old, new, change);
-       return change;
+
+       return 0;
 }
 
 /* create new dapm mixer control */
@@ -370,6 +355,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_path *path;
        struct snd_card *card = dapm->card->snd_card;
        const char *prefix;
+       struct snd_soc_dapm_widget_list *wlist;
+       size_t wlistsize;
 
        if (dapm->codec)
                prefix = dapm->codec->name_prefix;
@@ -388,23 +375,37 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
                list_for_each_entry(path, &w->sources, list_sink) {
 
                        /* mixer/mux paths name must match control name */
-                       if (path->name != (char*)w->kcontrols[i].name)
+                       if (path->name != (char *)w->kcontrol_news[i].name)
                                continue;
 
+                       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+                                   sizeof(struct snd_soc_dapm_widget *),
+                       wlist = kzalloc(wlistsize, GFP_KERNEL);
+                       if (wlist == NULL) {
+                               dev_err(dapm->dev,
+                                       "asoc: can't allocate widget list for %s\n",
+                                       w->name);
+                               return -ENOMEM;
+                       }
+                       wlist->num_widgets = 1;
+                       wlist->widgets[0] = w;
+
                        /* 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;
+                       name_len = strlen(w->kcontrol_news[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)
+                       if (path->long_name == NULL) {
+                               kfree(wlist);
                                return -ENOMEM;
+                       }
 
                        switch (w->id) {
                        default:
@@ -416,27 +417,30 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
                                 */
                                snprintf(path->long_name, name_len, "%s %s",
                                         w->name + prefix_len,
-                                        w->kcontrols[i].name);
+                                        w->kcontrol_news[i].name);
                                break;
                        case snd_soc_dapm_mixer_named_ctl:
                                snprintf(path->long_name, name_len, "%s",
-                                        w->kcontrols[i].name);
+                                        w->kcontrol_news[i].name);
                                break;
                        }
 
                        path->long_name[name_len - 1] = '\0';
 
-                       path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
-                                                     path->long_name, prefix);
+                       path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
+                                                     wlist, path->long_name,
+                                                     prefix);
                        ret = snd_ctl_add(card, path->kcontrol);
                        if (ret < 0) {
                                dev_err(dapm->dev,
                                        "asoc: failed to add dapm kcontrol %s: %d\n",
                                        path->long_name, ret);
+                               kfree(wlist);
                                kfree(path->long_name);
                                path->long_name = NULL;
                                return ret;
                        }
+                       w->kcontrols[i] = path->kcontrol;
                }
        }
        return ret;
@@ -451,42 +455,80 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
        struct snd_card *card = dapm->card->snd_card;
        const char *prefix;
        size_t prefix_len;
-       int ret = 0;
-
-       if (!w->num_kcontrols) {
-               dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
+       int ret;
+       struct snd_soc_dapm_widget_list *wlist;
+       int shared, wlistentries;
+       size_t wlistsize;
+       char *name;
+
+       if (w->num_kcontrols != 1) {
+               dev_err(dapm->dev,
+                       "asoc: mux %s has incorrect number of controls\n",
+                       w->name);
                return -EINVAL;
        }
 
-       if (dapm->codec)
-               prefix = dapm->codec->name_prefix;
-       else
-               prefix = NULL;
+       shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0],
+                                        &kcontrol);
+       if (kcontrol) {
+               wlist = kcontrol->private_data;
+               wlistentries = wlist->num_widgets + 1;
+       } else {
+               wlist = NULL;
+               wlistentries = 1;
+       }
+       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+               wlistentries * sizeof(struct snd_soc_dapm_widget *),
+       wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
+       if (wlist == NULL) {
+               dev_err(dapm->dev,
+                       "asoc: can't allocate widget list for %s\n", w->name);
+               return -ENOMEM;
+       }
+       wlist->num_widgets = wlistentries;
+       wlist->widgets[wlistentries - 1] = w;
 
-       if (prefix)
-               prefix_len = strlen(prefix) + 1;
-       else
-               prefix_len = 0;
+       if (!kcontrol) {
+               if (dapm->codec)
+                       prefix = dapm->codec->name_prefix;
+               else
+                       prefix = NULL;
+
+               if (shared) {
+                       name = w->kcontrol_news[0].name;
+                       prefix_len = 0;
+               } else {
+                       name = w->name;
+                       if (prefix)
+                               prefix_len = strlen(prefix) + 1;
+                       else
+                               prefix_len = 0;
+               }
 
-       /* The control will get a prefix from the control creation
-        * process but we're also using the same prefix for widgets so
-        * cut the prefix off the front of the widget name.
-        */
-       kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len,
-                               prefix);
-       ret = snd_ctl_add(card, kcontrol);
+               /*
+                * The control will get a prefix from the control creation
+                * process but we're also using the same prefix for widgets so
+                * cut the prefix off the front of the widget name.
+                */
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
+                                       name + prefix_len, prefix);
+               ret = snd_ctl_add(card, kcontrol);
+               if (ret < 0) {
+                       dev_err(dapm->dev,
+                               "asoc: failed to add kcontrol %s\n", w->name);
+                       kfree(wlist);
+                       return ret;
+               }
+       }
 
-       if (ret < 0)
-               goto err;
+       kcontrol->private_data = wlist;
+
+       w->kcontrols[0] = kcontrol;
 
        list_for_each_entry(path, &w->sources, list_sink)
                path->kcontrol = kcontrol;
 
-       return ret;
-
-err:
-       dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name);
-       return ret;
+       return 0;
 }
 
 /* create new dapm volume control */
@@ -644,57 +686,6 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
-/* Standard power change method, used to apply power changes to most
- * widgets.
- */
-static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
-{
-       int ret;
-
-       /* call any power change event handlers */
-       if (w->event)
-               dev_dbg(w->dapm->dev, "power %s event for %s flags %x\n",
-                        w->power ? "on" : "off",
-                        w->name, w->event_flags);
-
-       /* power up pre event */
-       if (w->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 (!w->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;
-       }
-
-       dapm_update_bits(w);
-
-       /* power up post event */
-       if (w->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 (!w->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;
-}
-
 /* Generic check to see if a widget should be powered.
  */
 static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
@@ -981,16 +972,6 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
                                               NULL, SND_SOC_DAPM_POST_PMD);
                        break;
 
-               case snd_soc_dapm_input:
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_hp:
-               case snd_soc_dapm_mic:
-               case snd_soc_dapm_line:
-               case snd_soc_dapm_spk:
-                       /* No register support currently */
-                       ret = dapm_generic_apply_power(w);
-                       break;
-
                default:
                        /* Queue it up for application */
                        cur_sort = sort[w->id];
@@ -1201,6 +1182,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                }
        }
 
+       /* Force all contexts in the card to the same bias state */
+       power = 0;
+       list_for_each_entry(d, &card->dapm_list, list)
+               if (d->dev_power)
+                       power = 1;
+       list_for_each_entry(d, &card->dapm_list, list)
+               d->dev_power = power;
+
+
        /* Run all the bias changes in parallel */
        list_for_each_entry(d, &dapm->card->dapm_list, list)
                async_schedule_domain(dapm_pre_sequence_async, d,
@@ -1304,31 +1294,104 @@ static const struct file_operations dapm_widget_power_fops = {
        .llseek = default_llseek,
 };
 
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
+static int dapm_bias_open_file(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct snd_soc_dapm_context *dapm = file->private_data;
+       char *level;
+
+       switch (dapm->bias_level) {
+       case SND_SOC_BIAS_ON:
+               level = "On\n";
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               level = "Prepare\n";
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               level = "Standby\n";
+               break;
+       case SND_SOC_BIAS_OFF:
+               level = "Off\n";
+               break;
+       default:
+               BUG();
+               level = "Unknown\n";
+               break;
+       }
+
+       return simple_read_from_buffer(user_buf, count, ppos, level,
+                                      strlen(level));
+}
+
+static const struct file_operations dapm_bias_fops = {
+       .open = dapm_bias_open_file,
+       .read = dapm_bias_read_file,
+       .llseek = default_llseek,
+};
+
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+       struct dentry *parent)
 {
-       struct snd_soc_dapm_widget *w;
        struct dentry *d;
 
-       if (!dapm->debugfs_dapm)
+       dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
+
+       if (!dapm->debugfs_dapm) {
+               printk(KERN_WARNING
+                      "Failed to create DAPM debugfs directory\n");
                return;
+       }
 
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (!w->name || w->dapm != dapm)
-                       continue;
+       d = debugfs_create_file("bias_level", 0444,
+                               dapm->debugfs_dapm, dapm,
+                               &dapm_bias_fops);
+       if (!d)
+               dev_warn(dapm->dev,
+                        "ASoC: Failed to create bias level debugfs file\n");
+}
 
-               d = debugfs_create_file(w->name, 0444,
-                                       dapm->debugfs_dapm, w,
-                                       &dapm_widget_power_fops);
-               if (!d)
-                       dev_warn(w->dapm->dev,
-                               "ASoC: Failed to create %s debugfs file\n",
-                               w->name);
-       }
+static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct dentry *d;
+
+       if (!dapm->debugfs_dapm || !w->name)
+               return;
+
+       d = debugfs_create_file(w->name, 0444,
+                               dapm->debugfs_dapm, w,
+                               &dapm_widget_power_fops);
+       if (!d)
+               dev_warn(w->dapm->dev,
+                       "ASoC: Failed to create %s debugfs file\n",
+                       w->name);
+}
+
+static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
+{
+       debugfs_remove_recursive(dapm->debugfs_dapm);
 }
+
 #else
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+       struct dentry *parent)
+{
+}
+
+static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
+{
+}
+
+static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
 {
 }
+
 #endif
 
 /* test and update the power status of a mux widget */
@@ -1496,32 +1559,49 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                        kfree(p->long_name);
                        kfree(p);
                }
+               kfree(w->kcontrols);
                kfree(w->name);
                kfree(w);
        }
 }
 
-static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
-                               const char *pin, int status)
+static struct snd_soc_dapm_widget *dapm_find_widget(
+                       struct snd_soc_dapm_context *dapm, const char *pin,
+                       bool search_other_contexts)
 {
        struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_widget *fallback = NULL;
 
        list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (w->dapm != dapm)
-                       continue;
                if (!strcmp(w->name, pin)) {
-                       dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n",
-                               pin, status);
-                       w->connected = status;
-                       /* Allow disabling of forced pins */
-                       if (status == 0)
-                               w->force = 0;
-                       return 0;
+                       if (w->dapm == dapm)
+                               return w;
+                       else
+                               fallback = w;
                }
        }
 
-       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-       return -EINVAL;
+       if (search_other_contexts)
+               return fallback;
+
+       return NULL;
+}
+
+static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+                               const char *pin, int status)
+{
+       struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+
+       if (!w) {
+               dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+               return -EINVAL;
+       }
+
+       w->connected = status;
+       if (status == 0)
+               w->force = 0;
+
+       return 0;
 }
 
 /**
@@ -1627,7 +1707,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        }
 
        /* connect dynamic paths */
-       switch(wsink->id) {
+       switch (wsink->id) {
        case snd_soc_dapm_adc:
        case snd_soc_dapm_dac:
        case snd_soc_dapm_pga:
@@ -1650,7 +1730,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_virt_mux:
        case snd_soc_dapm_value_mux:
                ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
-                       &wsink->kcontrols[0]);
+                       &wsink->kcontrol_news[0]);
                if (ret != 0)
                        goto err;
                break;
@@ -1730,6 +1810,14 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                if (w->new)
                        continue;
 
+               if (w->num_kcontrols) {
+                       w->kcontrols = kzalloc(w->num_kcontrols *
+                                               sizeof(struct snd_kcontrol *),
+                                               GFP_KERNEL);
+                       if (!w->kcontrols)
+                               return -ENOMEM;
+               }
+
                switch(w->id) {
                case snd_soc_dapm_switch:
                case snd_soc_dapm_mixer:
@@ -1785,6 +1873,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                }
 
                w->new = 1;
+
+               dapm_debugfs_add_widget(w);
        }
 
        dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
@@ -1804,7 +1894,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -1843,7 +1934,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -1854,6 +1947,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int val;
        int connect, change;
        struct snd_soc_dapm_update update;
+       int wi;
 
        val = (ucontrol->value.integer.value[0] & mask);
 
@@ -1862,31 +1956,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        mask = mask << shift;
        val = val << shift;
 
-       mutex_lock(&widget->codec->mutex);
-       widget->value = val;
+       if (val)
+               /* new connection */
+               connect = invert ? 0 : 1;
+       else
+               /* old connection must be powered down */
+               connect = invert ? 1 : 0;
+
+       mutex_lock(&codec->mutex);
 
        change = snd_soc_test_bits(widget->codec, reg, mask, val);
        if (change) {
-               if (val)
-                       /* new connection */
-                       connect = invert ? 0:1;
-               else
-                       /* old connection must be powered down */
-                       connect = invert ? 1:0;
+               for (wi = 0; wi < wlist->num_widgets; wi++) {
+                       widget = wlist->widgets[wi];
 
-               update.kcontrol = kcontrol;
-               update.widget = widget;
-               update.reg = reg;
-               update.mask = mask;
-               update.val = val;
-               widget->dapm->update = &update;
+                       widget->value = val;
 
-               dapm_mixer_update_power(widget, kcontrol, connect);
+                       update.kcontrol = kcontrol;
+                       update.widget = widget;
+                       update.reg = reg;
+                       update.mask = mask;
+                       update.val = val;
+                       widget->dapm->update = &update;
 
-               widget->dapm->update = NULL;
+                       dapm_mixer_update_power(widget, kcontrol, connect);
+
+                       widget->dapm->update = NULL;
+               }
        }
 
-       mutex_unlock(&widget->codec->mutex);
+       mutex_unlock(&codec->mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -1903,7 +2002,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, bitmask;
 
@@ -1931,11 +2031,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask, bitmask;
        struct snd_soc_dapm_update update;
+       int wi;
 
        for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
@@ -1951,22 +2054,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
                mask |= (bitmask - 1) << e->shift_r;
        }
 
-       mutex_lock(&widget->codec->mutex);
-       widget->value = val;
+       mutex_lock(&codec->mutex);
+
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       if (change) {
+               for (wi = 0; wi < wlist->num_widgets; wi++) {
+                       widget = wlist->widgets[wi];
 
-       update.kcontrol = kcontrol;
-       update.widget = widget;
-       update.reg = e->reg;
-       update.mask = mask;
-       update.val = val;
-       widget->dapm->update = &update;
+                       widget->value = val;
 
-       dapm_mux_update_power(widget, kcontrol, change, mux, e);
+                       update.kcontrol = kcontrol;
+                       update.widget = widget;
+                       update.reg = e->reg;
+                       update.mask = mask;
+                       update.val = val;
+                       widget->dapm->update = &update;
 
-       widget->dapm->update = NULL;
+                       dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-       mutex_unlock(&widget->codec->mutex);
+                       widget->dapm->update = NULL;
+               }
+       }
+
+       mutex_unlock(&codec->mutex);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -1981,7 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 
        ucontrol->value.enumerated.item[0] = widget->value;
 
@@ -1999,22 +2110,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
 int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
        struct soc_enum *e =
                (struct soc_enum *)kcontrol->private_value;
        int change;
        int ret = 0;
+       int wi;
 
        if (ucontrol->value.enumerated.item[0] >= e->max)
                return -EINVAL;
 
-       mutex_lock(&widget->codec->mutex);
+       mutex_lock(&codec->mutex);
 
        change = widget->value != ucontrol->value.enumerated.item[0];
-       widget->value = ucontrol->value.enumerated.item[0];
-       dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
+       if (change) {
+               for (wi = 0; wi < wlist->num_widgets; wi++) {
+                       widget = wlist->widgets[wi];
 
-       mutex_unlock(&widget->codec->mutex);
+                       widget->value = ucontrol->value.enumerated.item[0];
+
+                       dapm_mux_update_power(widget, kcontrol, change,
+                                             widget->value, e);
+               }
+       }
+
+       mutex_unlock(&codec->mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2035,7 +2157,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val, mux;
 
@@ -2075,11 +2198,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
+       int wi;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -2093,22 +2219,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
                mask |= e->mask << e->shift_r;
        }
 
-       mutex_lock(&widget->codec->mutex);
-       widget->value = val;
+       mutex_lock(&codec->mutex);
+
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       if (change) {
+               for (wi = 0; wi < wlist->num_widgets; wi++) {
+                       widget = wlist->widgets[wi];
 
-       update.kcontrol = kcontrol;
-       update.widget = widget;
-       update.reg = e->reg;
-       update.mask = mask;
-       update.val = val;
-       widget->dapm->update = &update;
+                       widget->value = val;
 
-       dapm_mux_update_power(widget, kcontrol, change, mux, e);
+                       update.kcontrol = kcontrol;
+                       update.widget = widget;
+                       update.reg = e->reg;
+                       update.mask = mask;
+                       update.val = val;
+                       widget->dapm->update = &update;
 
-       widget->dapm->update = NULL;
+                       dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+                       widget->dapm->update = NULL;
+               }
+       }
 
-       mutex_unlock(&widget->codec->mutex);
+       mutex_unlock(&codec->mutex);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2346,22 +2479,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
 int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin)
 {
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (w->dapm != dapm)
-                       continue;
-               if (!strcmp(w->name, pin)) {
-                       dev_dbg(w->dapm->dev,
-                               "dapm: force enable pin %s\n", pin);
-                       w->connected = 1;
-                       w->force = 1;
-                       return 0;
-               }
+       if (!w) {
+               dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+               return -EINVAL;
        }
 
-       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-       return -EINVAL;
+       dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
+       w->connected = 1;
+       w->force = 1;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
 
@@ -2413,14 +2542,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
                                const char *pin)
 {
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (w->dapm != dapm)
-                       continue;
-               if (!strcmp(w->name, pin))
-                       return w->connected;
-       }
+       if (w)
+               return w->connected;
 
        return 0;
 }
@@ -2440,19 +2565,16 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin)
 {
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
 
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (w->dapm != dapm)
-                       continue;
-               if (!strcmp(w->name, pin)) {
-                       w->ignore_suspend = 1;
-                       return 0;
-               }
+       if (!w) {
+               dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+               return -EINVAL;
        }
 
-       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
-       return -EINVAL;
+       w->ignore_suspend = 1;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
@@ -2465,6 +2587,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 {
        snd_soc_dapm_sys_remove(dapm->dev);
+       dapm_debugfs_cleanup(dapm);
        dapm_free_widgets(dapm);
        list_del(&dapm->list);
 }
index fc017c0a7b5d332082ace1a212dff7eb268fb7c4..7c17b98d584609c4a9fd78afe5c019a43728db1f 100644 (file)
@@ -325,7 +325,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                                              gpio_handler,
                                              IRQF_TRIGGER_RISING |
                                              IRQF_TRIGGER_FALLING,
-                                             jack->codec->dev->driver->name,
+                                             gpios[i].name,
                                              &gpios[i]);
                if (ret)
                        goto err;
index 3f45e6a439bff6b1e3f8060063c25855350db6ca..ec921ec99c2621eaa58b7d0c5e4eb97b861971de 100644 (file)
@@ -13,6 +13,7 @@
  *  option) any later version.
  */
 
+#include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -55,3 +56,55 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
                return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
+
+static struct snd_soc_platform_driver dummy_platform;
+
+static __devinit int snd_soc_dummy_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &dummy_platform);
+}
+
+static __devexit int snd_soc_dummy_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver soc_dummy_driver = {
+       .driver = {
+               .name = "snd-soc-dummy",
+               .owner = THIS_MODULE,
+       },
+       .probe = snd_soc_dummy_probe,
+       .remove = __devexit_p(snd_soc_dummy_remove),
+};
+
+static struct platform_device *soc_dummy_dev;
+
+int __init snd_soc_util_init(void)
+{
+       int ret;
+
+       soc_dummy_dev = platform_device_alloc("snd-soc-dummy", -1);
+       if (!soc_dummy_dev)
+               return -ENOMEM;
+
+       ret = platform_device_add(soc_dummy_dev);
+       if (ret != 0) {
+               platform_device_put(soc_dummy_dev);
+               return ret;
+       }
+
+       ret = platform_driver_register(&soc_dummy_driver);
+       if (ret != 0)
+               platform_device_unregister(soc_dummy_dev);
+
+       return ret;
+}
+
+void __exit snd_soc_util_exit(void)
+{
+       platform_device_unregister(soc_dummy_dev);
+       platform_driver_unregister(&soc_dummy_driver);
+}
index 66b504f06c23ce6178cb236cfeeac5938764727e..035d39a4beb45285bb2e780da61de084e3784e73 100644 (file)
@@ -1,26 +1,40 @@
-config SND_TEGRA_SOC
+config SND_SOC_TEGRA
        tristate "SoC Audio for the Tegra System-on-Chip"
        depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
-       default m
        help
          Say Y or M here if you want support for SoC audio on Tegra.
 
-config SND_TEGRA_SOC_I2S
+config SND_SOC_TEGRA_I2S
        tristate
-       depends on SND_TEGRA_SOC
-       default m
+       depends on SND_SOC_TEGRA
        help
          Say Y or M if you want to add support for codecs attached to the
          Tegra I2S interface. You will also need to select the individual
          machine drivers to support below.
 
-config SND_TEGRA_SOC_HARMONY
-       tristate "SoC Audio support for Tegra Harmony reference board"
-       depends on SND_TEGRA_SOC && MACH_HARMONY && I2C
-       default m
-       select SND_TEGRA_SOC_I2S
+config MACH_HAS_SND_SOC_TEGRA_WM8903
+       bool
+       help
+         Machines that use the SND_SOC_TEGRA_WM8903 driver should select
+         this config option, in order to allow the user to enable
+         SND_SOC_TEGRA_WM8903.
+
+config SND_SOC_TEGRA_WM8903
+       tristate "SoC Audio support for Tegra boards using a WM8903 codec"
+       depends on SND_SOC_TEGRA && I2C
+       depends on MACH_HAS_SND_SOC_TEGRA_WM8903
+       select SND_SOC_TEGRA_I2S
        select SND_SOC_WM8903
        help
-         Say Y or M here if you want to add support for SoC audio on the
-         Tegra Harmony reference board.
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the WM8093 codec. Currently, the supported boards are
+         Harmony, Ventana, Seaboard, Kaen, and Aebl.
 
+config SND_SOC_TEGRA_TRIMSLICE
+       tristate "SoC Audio support for TrimSlice board"
+       depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
+       select SND_SOC_TEGRA_I2S
+       select SND_SOC_TLV320AIC23
+       help
+         Say Y or M here if you want to add support for SoC audio on the
+         TrimSlice platform.
index fd183d3ab4f1f48571521dff099e49cb5c0c689a..fa6574d92a31a9b0ecd04f25ba2cada6466e828e 100644 (file)
@@ -4,12 +4,14 @@ snd-soc-tegra-pcm-objs := tegra_pcm.o
 snd-soc-tegra-i2s-objs := tegra_i2s.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
 
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o
-obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
+obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
 
 # Tegra machine Support
-snd-soc-tegra-harmony-objs := harmony.o
+snd-soc-tegra-wm8903-objs := tegra_wm8903.o
+snd-soc-tegra-trimslice-objs := trimslice.o
 
-obj-$(CONFIG_SND_TEGRA_SOC_HARMONY) += snd-soc-tegra-harmony.o
+obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
+obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c
deleted file mode 100644 (file)
index 556a571..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * harmony.c - Harmony machine ASoC driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <asm/mach-types.h>
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-
-#include <mach/harmony_audio.h>
-
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "../codecs/wm8903.h"
-
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
-#include "tegra_asoc_utils.h"
-
-#define DRV_NAME "tegra-snd-harmony"
-
-#define GPIO_SPKR_EN    BIT(0)
-#define GPIO_INT_MIC_EN BIT(1)
-#define GPIO_EXT_MIC_EN BIT(2)
-
-struct tegra_harmony {
-       struct tegra_asoc_utils_data util_data;
-       struct harmony_audio_platform_data *pdata;
-       int gpio_requested;
-};
-
-static int harmony_asoc_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->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_card *card = codec->card;
-       struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-       int srate, mclk, mclk_change;
-       int err;
-
-       srate = params_rate(params);
-       switch (srate) {
-       case 64000:
-       case 88200:
-       case 96000:
-               mclk = 128 * srate;
-               break;
-       default:
-               mclk = 256 * srate;
-               break;
-       }
-       /* FIXME: Codec only requires >= 3MHz if OSR==0 */
-       while (mclk < 6000000)
-               mclk *= 2;
-
-       err = tegra_asoc_utils_set_rate(&harmony->util_data, srate, mclk,
-                                       &mclk_change);
-       if (err < 0) {
-               dev_err(card->dev, "Can't configure clocks\n");
-               return err;
-       }
-
-       err = snd_soc_dai_set_fmt(codec_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "codec_dai fmt not set\n");
-               return err;
-       }
-
-       err = snd_soc_dai_set_fmt(cpu_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "cpu_dai fmt not set\n");
-               return err;
-       }
-
-       if (mclk_change) {
-               err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
-                                            SND_SOC_CLOCK_IN);
-               if (err < 0) {
-                       dev_err(card->dev, "codec_dai clock not set\n");
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops harmony_asoc_ops = {
-       .hw_params = harmony_asoc_hw_params,
-};
-
-static struct snd_soc_jack harmony_hp_jack;
-
-static struct snd_soc_jack_pin harmony_hp_jack_pins[] = {
-       {
-               .pin = "Headphone Jack",
-               .mask = SND_JACK_HEADPHONE,
-       },
-};
-
-static struct snd_soc_jack_gpio harmony_hp_jack_gpios[] = {
-       {
-               .name = "headphone detect",
-               .report = SND_JACK_HEADPHONE,
-               .debounce_time = 150,
-               .invert = 1,
-       }
-};
-
-static struct snd_soc_jack harmony_mic_jack;
-
-static struct snd_soc_jack_pin harmony_mic_jack_pins[] = {
-       {
-               .pin = "Mic Jack",
-               .mask = SND_JACK_MICROPHONE,
-       },
-};
-
-static int harmony_event_int_spk(struct snd_soc_dapm_widget *w,
-                                       struct snd_kcontrol *k, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       struct snd_soc_card *card = codec->card;
-       struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-       struct harmony_audio_platform_data *pdata = harmony->pdata;
-
-       gpio_set_value_cansleep(pdata->gpio_spkr_en,
-                               SND_SOC_DAPM_EVENT_ON(event));
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget harmony_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Int Spk", harmony_event_int_spk),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route harmony_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "ROP"},
-       {"Int Spk", NULL, "RON"},
-       {"Int Spk", NULL, "LOP"},
-       {"Int Spk", NULL, "LON"},
-       {"Mic Bias", NULL, "Mic Jack"},
-       {"IN1L", NULL, "Mic Bias"},
-};
-
-static const struct snd_kcontrol_new harmony_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Int Spk"),
-};
-
-static int harmony_asoc_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       struct snd_soc_card *card = codec->card;
-       struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-       struct harmony_audio_platform_data *pdata = harmony->pdata;
-       int ret;
-
-       ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
-       if (ret) {
-               dev_err(card->dev, "cannot get spkr_en gpio\n");
-               return ret;
-       }
-       harmony->gpio_requested |= GPIO_SPKR_EN;
-
-       gpio_direction_output(pdata->gpio_spkr_en, 0);
-
-       ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
-       if (ret) {
-               dev_err(card->dev, "cannot get int_mic_en gpio\n");
-               return ret;
-       }
-       harmony->gpio_requested |= GPIO_INT_MIC_EN;
-
-       /* Disable int mic; enable signal is active-high */
-       gpio_direction_output(pdata->gpio_int_mic_en, 0);
-
-       ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
-       if (ret) {
-               dev_err(card->dev, "cannot get ext_mic_en gpio\n");
-               return ret;
-       }
-       harmony->gpio_requested |= GPIO_EXT_MIC_EN;
-
-       /* Enable ext mic; enable signal is active-low */
-       gpio_direction_output(pdata->gpio_ext_mic_en, 0);
-
-       ret = snd_soc_add_controls(codec, harmony_controls,
-                                  ARRAY_SIZE(harmony_controls));
-       if (ret < 0)
-               return ret;
-
-       snd_soc_dapm_new_controls(dapm, harmony_dapm_widgets,
-                                       ARRAY_SIZE(harmony_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, harmony_audio_map,
-                               ARRAY_SIZE(harmony_audio_map));
-
-       harmony_hp_jack_gpios[0].gpio = pdata->gpio_hp_det;
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-                        &harmony_hp_jack);
-       snd_soc_jack_add_pins(&harmony_hp_jack,
-                             ARRAY_SIZE(harmony_hp_jack_pins),
-                             harmony_hp_jack_pins);
-       snd_soc_jack_add_gpios(&harmony_hp_jack,
-                              ARRAY_SIZE(harmony_hp_jack_gpios),
-                              harmony_hp_jack_gpios);
-
-       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                        &harmony_mic_jack);
-       snd_soc_jack_add_pins(&harmony_mic_jack,
-                             ARRAY_SIZE(harmony_mic_jack_pins),
-                             harmony_mic_jack_pins);
-       wm8903_mic_detect(codec, &harmony_mic_jack, SND_JACK_MICROPHONE, 0);
-
-       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
-
-       snd_soc_dapm_nc_pin(dapm, "IN3L");
-       snd_soc_dapm_nc_pin(dapm, "IN3R");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
-
-       snd_soc_dapm_sync(dapm);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link harmony_wm8903_dai = {
-       .name = "WM8903",
-       .stream_name = "WM8903 PCM",
-       .codec_name = "wm8903.0-001a",
-       .platform_name = "tegra-pcm-audio",
-       .cpu_dai_name = "tegra-i2s.0",
-       .codec_dai_name = "wm8903-hifi",
-       .init = harmony_asoc_init,
-       .ops = &harmony_asoc_ops,
-};
-
-static struct snd_soc_card snd_soc_harmony = {
-       .name = "tegra-harmony",
-       .dai_link = &harmony_wm8903_dai,
-       .num_links = 1,
-};
-
-static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &snd_soc_harmony;
-       struct tegra_harmony *harmony;
-       struct harmony_audio_platform_data *pdata;
-       int ret;
-
-       if (!machine_is_harmony()) {
-               dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
-               return -ENODEV;
-       }
-
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_err(&pdev->dev, "no platform data supplied\n");
-               return -EINVAL;
-       }
-
-       harmony = kzalloc(sizeof(struct tegra_harmony), GFP_KERNEL);
-       if (!harmony) {
-               dev_err(&pdev->dev, "Can't allocate tegra_harmony\n");
-               return -ENOMEM;
-       }
-
-       harmony->pdata = pdata;
-
-       ret = tegra_asoc_utils_init(&harmony->util_data, &pdev->dev);
-       if (ret)
-               goto err_free_harmony;
-
-       card->dev = &pdev->dev;
-       platform_set_drvdata(pdev, card);
-       snd_soc_card_set_drvdata(card, harmony);
-
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               goto err_clear_drvdata;
-       }
-
-       return 0;
-
-err_clear_drvdata:
-       snd_soc_card_set_drvdata(card, NULL);
-       platform_set_drvdata(pdev, NULL);
-       card->dev = NULL;
-       tegra_asoc_utils_fini(&harmony->util_data);
-err_free_harmony:
-       kfree(harmony);
-       return ret;
-}
-
-static int __devexit tegra_snd_harmony_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
-       struct harmony_audio_platform_data *pdata = harmony->pdata;
-
-       snd_soc_unregister_card(card);
-
-       snd_soc_card_set_drvdata(card, NULL);
-       platform_set_drvdata(pdev, NULL);
-       card->dev = NULL;
-
-       tegra_asoc_utils_fini(&harmony->util_data);
-
-       if (harmony->gpio_requested & GPIO_EXT_MIC_EN)
-               gpio_free(pdata->gpio_ext_mic_en);
-       if (harmony->gpio_requested & GPIO_INT_MIC_EN)
-               gpio_free(pdata->gpio_int_mic_en);
-       if (harmony->gpio_requested & GPIO_SPKR_EN)
-               gpio_free(pdata->gpio_spkr_en);
-
-       kfree(harmony);
-
-       return 0;
-}
-
-static struct platform_driver tegra_snd_harmony_driver = {
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-               .pm = &snd_soc_pm_ops,
-       },
-       .probe = tegra_snd_harmony_probe,
-       .remove = __devexit_p(tegra_snd_harmony_remove),
-};
-
-static int __init snd_tegra_harmony_init(void)
-{
-       return platform_driver_register(&tegra_snd_harmony_driver);
-}
-module_init(snd_tegra_harmony_init);
-
-static void __exit snd_tegra_harmony_exit(void)
-{
-       platform_driver_unregister(&tegra_snd_harmony_driver);
-}
-module_exit(snd_tegra_harmony_exit);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Harmony machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
index 52f0a3f9ce403ca3a2638dd587be3caa780122f1..dfa85cbb05c807cbb4239963e64480814969d4f7 100644 (file)
 #include "tegra_asoc_utils.h"
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
-                             int mclk, int *mclk_change)
+                             int mclk)
 {
        int new_baseclock;
+       bool clk_change;
        int err;
 
        switch (srate) {
@@ -52,10 +53,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
                return -EINVAL;
        }
 
-       *mclk_change = ((new_baseclock != data->set_baseclock) ||
+       clk_change = ((new_baseclock != data->set_baseclock) ||
                        (mclk != data->set_mclk));
-       if (!*mclk_change)
-           return 0;
+       if (!clk_change)
+               return 0;
 
        data->set_baseclock = 0;
        data->set_mclk = 0;
index bbba7afdfc2cd8559c63f088228d641581110589..4818195da25c3be3542b403112aa7d68e742122d 100644 (file)
@@ -36,7 +36,7 @@ struct tegra_asoc_utils_data {
 };
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
-                             int mclk, int *mclk_change);
+                             int mclk);
 int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                          struct device *dev);
 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
index 4f5e2c90b0207ce0be0b39bf90a946d27b8ece2a..6b817e20548ca07fa94938caf8202bc37b9b0386 100644 (file)
@@ -114,7 +114,7 @@ static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
                debugfs_remove(i2s->debug);
 }
 #else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
+static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
 {
 }
 
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
new file mode 100644 (file)
index 0000000..0d6738a
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+#include <mach/tegra_wm8903_pdata.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8903.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-wm8903"
+
+#define GPIO_SPKR_EN    BIT(0)
+#define GPIO_HP_MUTE    BIT(1)
+#define GPIO_INT_MIC_EN BIT(2)
+#define GPIO_EXT_MIC_EN BIT(3)
+
+struct tegra_wm8903 {
+       struct tegra_asoc_utils_data util_data;
+       struct tegra_wm8903_platform_data *pdata;
+       int gpio_requested;
+};
+
+static int tegra_wm8903_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->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       switch (srate) {
+       case 64000:
+       case 88200:
+       case 96000:
+               mclk = 128 * srate;
+               break;
+       default:
+               mclk = 256 * srate;
+               break;
+       }
+       /* FIXME: Codec only requires >= 3MHz if OSR==0 */
+       while (mclk < 6000000)
+               mclk *= 2;
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_fmt(codec_dai,
+                                       SND_SOC_DAIFMT_I2S |
+                                       SND_SOC_DAIFMT_NB_NF |
+                                       SND_SOC_DAIFMT_CBS_CFS);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai fmt not set\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_fmt(cpu_dai,
+                                       SND_SOC_DAIFMT_I2S |
+                                       SND_SOC_DAIFMT_NB_NF |
+                                       SND_SOC_DAIFMT_CBS_CFS);
+       if (err < 0) {
+               dev_err(card->dev, "cpu_dai fmt not set\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_wm8903_ops = {
+       .hw_params = tegra_wm8903_hw_params,
+};
+
+static struct snd_soc_jack tegra_wm8903_hp_jack;
+
+static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = {
+       .name = "headphone detect",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+       .invert = 1,
+};
+
+static struct snd_soc_jack tegra_wm8903_mic_jack;
+
+static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+       if (!(machine->gpio_requested & GPIO_SPKR_EN))
+               return 0;
+
+       gpio_set_value_cansleep(pdata->gpio_spkr_en,
+                               SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+       if (!(machine->gpio_requested & GPIO_HP_MUTE))
+               return 0;
+
+       gpio_set_value_cansleep(pdata->gpio_hp_mute,
+                               !SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk),
+       SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route harmony_audio_map[] = {
+       {"Headphone Jack", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "HPOUTL"},
+       {"Int Spk", NULL, "ROP"},
+       {"Int Spk", NULL, "RON"},
+       {"Int Spk", NULL, "LOP"},
+       {"Int Spk", NULL, "LON"},
+       {"Mic Bias", NULL, "Mic Jack"},
+       {"IN1L", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route seaboard_audio_map[] = {
+       {"Headphone Jack", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "HPOUTL"},
+       {"Int Spk", NULL, "ROP"},
+       {"Int Spk", NULL, "RON"},
+       {"Int Spk", NULL, "LOP"},
+       {"Int Spk", NULL, "LON"},
+       {"Mic Bias", NULL, "Mic Jack"},
+       {"IN1R", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route kaen_audio_map[] = {
+       {"Headphone Jack", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "HPOUTL"},
+       {"Int Spk", NULL, "ROP"},
+       {"Int Spk", NULL, "RON"},
+       {"Int Spk", NULL, "LOP"},
+       {"Int Spk", NULL, "LON"},
+       {"Mic Bias", NULL, "Mic Jack"},
+       {"IN2R", NULL, "Mic Bias"},
+};
+
+static const struct snd_soc_dapm_route aebl_audio_map[] = {
+       {"Headphone Jack", NULL, "HPOUTR"},
+       {"Headphone Jack", NULL, "HPOUTL"},
+       {"Int Spk", NULL, "LINEOUTR"},
+       {"Int Spk", NULL, "LINEOUTL"},
+       {"Mic Bias", NULL, "Mic Jack"},
+       {"IN1R", NULL, "Mic Bias"},
+};
+
+static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Int Spk"),
+};
+
+static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+       int ret;
+
+       if (gpio_is_valid(pdata->gpio_spkr_en)) {
+               ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get spkr_en gpio\n");
+                       return ret;
+               }
+               machine->gpio_requested |= GPIO_SPKR_EN;
+
+               gpio_direction_output(pdata->gpio_spkr_en, 0);
+       }
+
+       if (gpio_is_valid(pdata->gpio_hp_mute)) {
+               ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
+               if (ret) {
+                       dev_err(card->dev, "cannot get hp_mute gpio\n");
+                       return ret;
+               }
+               machine->gpio_requested |= GPIO_HP_MUTE;
+
+               gpio_direction_output(pdata->gpio_hp_mute, 0);
+       }
+
+       if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+               ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get int_mic_en gpio\n");
+                       return ret;
+               }
+               machine->gpio_requested |= GPIO_INT_MIC_EN;
+
+               /* Disable int mic; enable signal is active-high */
+               gpio_direction_output(pdata->gpio_int_mic_en, 0);
+       }
+
+       if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+               ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get ext_mic_en gpio\n");
+                       return ret;
+               }
+               machine->gpio_requested |= GPIO_EXT_MIC_EN;
+
+               /* Enable ext mic; enable signal is active-low */
+               gpio_direction_output(pdata->gpio_ext_mic_en, 0);
+       }
+
+       if (gpio_is_valid(pdata->gpio_hp_det)) {
+               tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+               snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+                               &tegra_wm8903_hp_jack);
+               snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
+                                       ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
+                                       tegra_wm8903_hp_jack_pins);
+               snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
+                                       1,
+                                       &tegra_wm8903_hp_jack_gpio);
+       }
+
+       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+                        &tegra_wm8903_mic_jack);
+       snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
+                             ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
+                             tegra_wm8903_mic_jack_pins);
+       wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
+                               0);
+
+       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+
+       /* FIXME: Calculate automatically based on DAPM routes? */
+       if (!machine_is_harmony() && !machine_is_ventana())
+               snd_soc_dapm_nc_pin(dapm, "IN1L");
+       if (!machine_is_seaboard() && !machine_is_aebl())
+               snd_soc_dapm_nc_pin(dapm, "IN1R");
+       snd_soc_dapm_nc_pin(dapm, "IN2L");
+       if (!machine_is_kaen())
+               snd_soc_dapm_nc_pin(dapm, "IN2R");
+       snd_soc_dapm_nc_pin(dapm, "IN3L");
+       snd_soc_dapm_nc_pin(dapm, "IN3R");
+
+       if (machine_is_aebl()) {
+               snd_soc_dapm_nc_pin(dapm, "LON");
+               snd_soc_dapm_nc_pin(dapm, "RON");
+               snd_soc_dapm_nc_pin(dapm, "ROP");
+               snd_soc_dapm_nc_pin(dapm, "LOP");
+       } else {
+               snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
+               snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
+       }
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_wm8903_dai = {
+       .name = "WM8903",
+       .stream_name = "WM8903 PCM",
+       .codec_name = "wm8903.0-001a",
+       .platform_name = "tegra-pcm-audio",
+       .cpu_dai_name = "tegra-i2s.0",
+       .codec_dai_name = "wm8903-hifi",
+       .init = tegra_wm8903_init,
+       .ops = &tegra_wm8903_ops,
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8903 = {
+       .name = "tegra-wm8903",
+       .dai_link = &tegra_wm8903_dai,
+       .num_links = 1,
+
+       .controls = tegra_wm8903_controls,
+       .num_controls = ARRAY_SIZE(tegra_wm8903_controls),
+       .dapm_widgets = tegra_wm8903_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets),
+};
+
+static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_tegra_wm8903;
+       struct tegra_wm8903 *machine;
+       struct tegra_wm8903_platform_data *pdata;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
+       machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
+               return -ENOMEM;
+       }
+
+       machine->pdata = pdata;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err_free_machine;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       if (machine_is_harmony() || machine_is_ventana()) {
+               card->dapm_routes = harmony_audio_map;
+               card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+       } else if (machine_is_seaboard()) {
+               card->dapm_routes = seaboard_audio_map;
+               card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
+       } else if (machine_is_kaen()) {
+               card->dapm_routes = kaen_audio_map;
+               card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
+       } else {
+               card->dapm_routes = aebl_audio_map;
+               card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+       }
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err_free_machine:
+       kfree(machine);
+       return ret;
+}
+
+static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       if (machine->gpio_requested & GPIO_EXT_MIC_EN)
+               gpio_free(pdata->gpio_ext_mic_en);
+       if (machine->gpio_requested & GPIO_INT_MIC_EN)
+               gpio_free(pdata->gpio_int_mic_en);
+       if (machine->gpio_requested & GPIO_HP_MUTE)
+               gpio_free(pdata->gpio_hp_mute);
+       if (machine->gpio_requested & GPIO_SPKR_EN)
+               gpio_free(pdata->gpio_spkr_en);
+
+       kfree(machine);
+
+       return 0;
+}
+
+static struct platform_driver tegra_wm8903_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = tegra_wm8903_driver_probe,
+       .remove = __devexit_p(tegra_wm8903_driver_remove),
+};
+
+static int __init tegra_wm8903_modinit(void)
+{
+       return platform_driver_register(&tegra_wm8903_driver);
+}
+module_init(tegra_wm8903_modinit);
+
+static void __exit tegra_wm8903_modexit(void)
+{
+       platform_driver_unregister(&tegra_wm8903_driver);
+}
+module_exit(tegra_wm8903_modexit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
new file mode 100644 (file)
index 0000000..8fc07e9
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * trimslice.c - TrimSlice machine ASoC driver
+ *
+ * Copyright (C) 2011 - CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on code copyright/by:
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/tlv320aic23.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-trimslice"
+
+struct tegra_trimslice {
+       struct tegra_asoc_utils_data util_data;
+};
+
+static int trimslice_asoc_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->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       mclk = 128 * srate;
+
+       err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_fmt(codec_dai,
+                                       SND_SOC_DAIFMT_I2S |
+                                       SND_SOC_DAIFMT_NB_NF |
+                                       SND_SOC_DAIFMT_CBS_CFS);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai fmt not set\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_fmt(cpu_dai,
+                                       SND_SOC_DAIFMT_I2S |
+                                       SND_SOC_DAIFMT_NB_NF |
+                                       SND_SOC_DAIFMT_CBS_CFS);
+       if (err < 0) {
+               dev_err(card->dev, "cpu_dai fmt not set\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops trimslice_asoc_ops = {
+       .hw_params = trimslice_asoc_hw_params,
+};
+
+static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Line Out", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route trimslice_audio_map[] = {
+       {"Line Out", NULL, "LOUT"},
+       {"Line Out", NULL, "ROUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+};
+
+static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_nc_pin(dapm, "LHPOUT");
+       snd_soc_dapm_nc_pin(dapm, "RHPOUT");
+       snd_soc_dapm_nc_pin(dapm, "MICIN");
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .codec_name = "tlv320aic23-codec.2-001a",
+       .platform_name = "tegra-pcm-audio",
+       .cpu_dai_name = "tegra-i2s.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .init = trimslice_asoc_init,
+       .ops = &trimslice_asoc_ops,
+};
+
+static struct snd_soc_card snd_soc_trimslice = {
+       .name = "tegra-trimslice",
+       .dai_link = &trimslice_tlv320aic23_dai,
+       .num_links = 1,
+
+       .dapm_widgets = trimslice_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),
+       .dapm_routes = trimslice_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),
+};
+
+static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_trimslice;
+       struct tegra_trimslice *trimslice;
+       int ret;
+
+       trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL);
+       if (!trimslice) {
+               dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
+               return -ENOMEM;
+       }
+
+       ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
+       if (ret)
+               goto err_free_trimslice;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, trimslice);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&trimslice->util_data);
+err_free_trimslice:
+       kfree(trimslice);
+       return ret;
+}
+
+static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&trimslice->util_data);
+
+       kfree(trimslice);
+
+       return 0;
+}
+
+static struct platform_driver tegra_snd_trimslice_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = tegra_snd_trimslice_probe,
+       .remove = __devexit_p(tegra_snd_trimslice_remove),
+};
+
+static int __init snd_tegra_trimslice_init(void)
+{
+       return platform_driver_register(&tegra_snd_trimslice_driver);
+}
+module_init(snd_tegra_trimslice_init);
+
+static void __exit snd_tegra_trimslice_exit(void)
+{
+       platform_driver_unregister(&tegra_snd_trimslice_driver);
+}
+module_exit(snd_tegra_trimslice_exit);
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Trimslice machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 248463511186380b707d71dd2f240dd5596dabf5..ac828eff1a6347e080b74c78214b75a49fa9e663 100644 (file)
@@ -65,6 +65,15 @@ init_data[] = {
        { 0 } /* TERMINATING ENTRY */
 };
 
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum {
+       DIGITAL_THRU_ONLY_SAMPLERATE = 3
+};
+
 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 {
        struct comm_runtime *comm_rt = rt->chip->comm;
@@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
        }
 }
 
+static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
+{
+       int ret;
+       struct usb_device *device = rt->chip->dev;
+       struct comm_runtime *comm_rt = rt->chip->comm;
+
+       if (rate < 0 || rate >= CONTROL_N_RATES)
+               return -EINVAL;
+
+       ret = usb_set_interface(device, 1, rates_altsetting[rate]);
+       if (ret < 0)
+               return ret;
+
+       /* set soundcard clock */
+       ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
+                       rates_6fire_vh[rate]);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int usb6fire_control_set_channels(
+       struct control_runtime *rt, int n_analog_out,
+       int n_analog_in, bool spdif_out, bool spdif_in)
+{
+       int ret;
+       struct comm_runtime *comm_rt = rt->chip->comm;
+
+       /* enable analog inputs and outputs
+        * (one bit per stereo-channel) */
+       ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+                       (1 << (n_analog_out / 2)) - 1,
+                       (1 << (n_analog_in / 2)) - 1);
+       if (ret < 0)
+               return ret;
+
+       /* disable digital inputs and outputs */
+       /* TODO: use spdif_x to enable/disable digital channels */
+       ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int usb6fire_control_streaming_update(struct control_runtime *rt)
+{
+       struct comm_runtime *comm_rt = rt->chip->comm;
+
+       if (comm_rt) {
+               if (!rt->usb_streaming && rt->digital_thru_switch)
+                       usb6fire_control_set_rate(rt,
+                               DIGITAL_THRU_ONLY_SAMPLERATE);
+               return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
+                       (rt->usb_streaming ? 0x01 : 0x00) |
+                       (rt->digital_thru_switch ? 0x08 : 0x00));
+       }
+       return -EINVAL;
+}
+
 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_info *uinfo)
 {
@@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+       int changed = 0;
+
+       if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
+               rt->digital_thru_switch = ucontrol->value.integer.value[0];
+               usb6fire_control_streaming_update(rt);
+               changed = 1;
+       }
+       return changed;
+}
+
+static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = rt->digital_thru_switch;
+       return 0;
+}
+
 static struct __devinitdata snd_kcontrol_new elements[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = {
                .get = usb6fire_control_opt_coax_get,
                .put = usb6fire_control_opt_coax_put
        },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Digital Thru Playback Route",
+               .index = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = snd_ctl_boolean_mono_info,
+               .get = usb6fire_control_digital_thru_get,
+               .put = usb6fire_control_digital_thru_put
+       },
        {}
 };
 
@@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
                return -ENOMEM;
 
        rt->chip = chip;
+       rt->update_streaming = usb6fire_control_streaming_update;
+       rt->set_rate = usb6fire_control_set_rate;
+       rt->set_channels = usb6fire_control_set_channels;
 
        i = 0;
        while (init_data[i].type) {
@@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
        usb6fire_control_opt_coax_update(rt);
        usb6fire_control_line_phono_update(rt);
        usb6fire_control_master_vol_update(rt);
+       usb6fire_control_streaming_update(rt);
 
        i = 0;
        while (elements[i].name) {
index b534c777ab02ea9624c80887902164fb401f77e3..8f5aeead2e3d931938f41e98deaf857b0194fa2c 100644 (file)
@@ -21,12 +21,29 @@ enum {
        CONTROL_MAX_ELEMENTS = 32
 };
 
+enum {
+       CONTROL_RATE_44KHZ,
+       CONTROL_RATE_48KHZ,
+       CONTROL_RATE_88KHZ,
+       CONTROL_RATE_96KHZ,
+       CONTROL_RATE_176KHZ,
+       CONTROL_RATE_192KHZ,
+       CONTROL_N_RATES
+};
+
 struct control_runtime {
+       int (*update_streaming)(struct control_runtime *rt);
+       int (*set_rate)(struct control_runtime *rt, int rate);
+       int (*set_channels)(struct control_runtime *rt, int n_analog_out,
+               int n_analog_in, bool spdif_out, bool spdif_in);
+
        struct sfire_chip *chip;
 
        struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
        bool opt_coax_switch;
        bool line_phono_switch;
+       bool digital_thru_switch;
+       bool usb_streaming;
        u8 master_vol;
 };
 
index 86c1a3103760eff82f3d8155f396611d9296a200..d47beffedb0ff5b4be36bab35a1014e5bd5aa22f 100644 (file)
@@ -3,12 +3,6 @@
  *
  * Firmware loader
  *
- * Currently not working for all devices. To be able to use the device
- * in linux, it is also possible to let the windows driver upload the firmware.
- * For that, start the computer in windows and reboot.
- * As long as the device is connected to the power supply, no firmware reload
- * needs to be performed.
- *
  * Author:     Torsten Schenk <torsten.schenk@zoho.com>
  * Created:    Jan 01, 2011
  * Version:    0.3.0
@@ -21,6 +15,7 @@
  */
 
 #include <linux/firmware.h>
+#include <linux/bitrev.h>
 
 #include "firmware.h"
 #include "chip.h"
@@ -33,32 +28,6 @@ enum {
        FPGA_BUFSIZE = 512, FPGA_EP = 2
 };
 
-static const u8 BIT_REVERSE_TABLE[256] = {
-       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50,
-       0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8,
-       0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04,
-       0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4,
-       0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c,
-       0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82,
-       0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32,
-       0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46,
-       0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6,
-       0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e,
-       0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
-       0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
-       0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99,
-       0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25,
-       0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d,
-       0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3,
-       0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b,
-       0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb,
-       0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67,
-       0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f,
-       0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f,
-       0xbf, 0x7f, 0xff };
-
 /*
  * wMaxPacketSize of pcm endpoints.
  * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
@@ -72,6 +41,10 @@ static const u8 ep_w_max_packet_size[] = {
        0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
 };
 
+static const u8 known_fw_versions[][4] = {
+       { 0x03, 0x01, 0x0b, 0x00 }
+};
+
 struct ihex_record {
        u16 address;
        u8 len;
@@ -340,7 +313,7 @@ static int usb6fire_fw_fpga_upload(
 
        while (c != end) {
                for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
-                       buffer[i] = BIT_REVERSE_TABLE[(u8) *c];
+                       buffer[i] = byte_rev_table[(u8) *c];
 
                ret = usb6fire_fw_fpga_write(device, buffer, i);
                if (ret < 0) {
@@ -363,6 +336,25 @@ static int usb6fire_fw_fpga_upload(
        return 0;
 }
 
+/* check, if the firmware version the devices has currently loaded
+ * is known by this driver. 'version' needs to have 4 bytes version
+ * info data. */
+static int usb6fire_fw_check(u8 *version)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
+               if (!memcmp(version, known_fw_versions + i, 4))
+                       return 0;
+
+       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
+                       "%02x %02x %02x %02x. "
+                       "please reconnect to power. if this failure "
+                       "still happens, check your firmware installation.",
+                       version[0], version[1], version[2], version[3]);
+       return -EINVAL;
+}
+
 int usb6fire_fw_init(struct usb_interface *intf)
 {
        int i;
@@ -378,9 +370,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
                                "firmware state.\n");
                return ret;
        }
-       if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
-                       || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
-                       != 0x00) {
+       if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
                snd_printk(KERN_ERR PREFIX "unknown device firmware state "
                                "received from device: ");
                for (i = 0; i < 8; i++)
@@ -389,7 +379,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
                return -EIO;
        }
        /* do we need fpga loader ezusb firmware? */
-       if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+       if (buffer[3] == 0x01) {
                ret = usb6fire_fw_ezusb_upload(intf,
                                "6fire/dmx6firel2.ihx", 0, NULL, 0);
                if (ret < 0)
@@ -397,7 +387,10 @@ int usb6fire_fw_init(struct usb_interface *intf)
                return FW_NOT_READY;
        }
        /* do we need fpga firmware and application ezusb firmware? */
-       else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+       else if (buffer[3] == 0x02) {
+               ret = usb6fire_fw_check(buffer + 4);
+               if (ret < 0)
+                       return ret;
                ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
                if (ret < 0)
                        return ret;
@@ -410,8 +403,8 @@ int usb6fire_fw_init(struct usb_interface *intf)
                return FW_NOT_READY;
        }
        /* all fw loaded? */
-       else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
-               return 0;
+       else if (buffer[3] == 0x03)
+               return usb6fire_fw_check(buffer + 4);
        /* unknown data? */
        else {
                snd_printk(KERN_ERR PREFIX "unknown device firmware state "
index ba62c7468ba8d928a800617ffb26c4a7bed22b33..b137b25865cc986cc8f6bc8d21ca482e34b987cd 100644 (file)
 #include "pcm.h"
 #include "chip.h"
 #include "comm.h"
+#include "control.h"
 
 enum {
        OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
 };
 
 /* keep next two synced with
- * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
+ * and CONTROL_RATE_XXX in control.h */
 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
-static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 static const int rates_alsaid[] = {
        SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
        SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
        SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
 
-/* values to write to soundcard register for all samplerates */
-static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
-static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
-
 enum { /* settings for pcm */
        OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
 };
@@ -48,15 +45,6 @@ enum { /* pcm streaming states */
        STREAM_STOPPING
 };
 
-enum { /* pcm sample rates (also index into RATES_XXX[]) */
-       RATE_44KHZ,
-       RATE_48KHZ,
-       RATE_88KHZ,
-       RATE_96KHZ,
-       RATE_176KHZ,
-       RATE_192KHZ
-};
-
 static const struct snd_pcm_hardware pcm_hw = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
@@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = {
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_BATCH,
 
-       .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
        .rates = SNDRV_PCM_RATE_44100 |
                SNDRV_PCM_RATE_48000 |
@@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = {
 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
 {
        int ret;
-       struct usb_device *device = rt->chip->dev;
-       struct comm_runtime *comm_rt = rt->chip->comm;
+       struct control_runtime *ctrl_rt = rt->chip->control;
 
-       if (rt->rate >= ARRAY_SIZE(rates))
-               return -EINVAL;
-       /* disable streaming */
-       ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+       ctrl_rt->usb_streaming = false;
+       ret = ctrl_rt->update_streaming(ctrl_rt);
        if (ret < 0) {
                snd_printk(KERN_ERR PREFIX "error stopping streaming while "
                                "setting samplerate %d.\n", rates[rt->rate]);
                return ret;
        }
 
-       ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
-       if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error setting interface "
-                               "altsetting %d for samplerate %d.\n",
-                               rates_altsetting[rt->rate], rates[rt->rate]);
-               return ret;
-       }
-
-       /* set soundcard clock */
-       ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
-                       rates_6fire_vh[rt->rate]);
+       ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
        if (ret < 0) {
                snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
                                rates[rt->rate]);
                return ret;
        }
 
-       /* enable analog inputs and outputs
-        * (one bit per stereo-channel) */
-       ret = comm_rt->write16(comm_rt, 0x02, 0x02,
-                       (1 << (OUT_N_CHANNELS / 2)) - 1,
-                       (1 << (IN_N_CHANNELS / 2)) - 1);
+       ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
+                       false, false);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error initializing analog channels "
+               snd_printk(KERN_ERR PREFIX "error initializing channels "
                                "while setting samplerate %d.\n",
                                rates[rt->rate]);
                return ret;
        }
-       /* disable digital inputs and outputs */
-       ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
-       if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error initializing digital "
-                               "channels while setting samplerate %d.\n",
-                               rates[rt->rate]);
-               return ret;
-       }
 
-       ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+       ctrl_rt->usb_streaming = true;
+       ret = ctrl_rt->update_streaming(ctrl_rt);
        if (ret < 0) {
                snd_printk(KERN_ERR PREFIX "error starting streaming while "
                                "setting samplerate %d.\n", rates[rt->rate]);
@@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream(
 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
 {
        int i;
+       struct control_runtime *ctrl_rt = rt->chip->control;
 
        if (rt->stream_state != STREAM_DISABLED) {
                for (i = 0; i < PCM_N_URBS; i++) {
                        usb_kill_urb(&rt->in_urbs[i].instance);
                        usb_kill_urb(&rt->out_urbs[i].instance);
                }
+               ctrl_rt->usb_streaming = false;
+               ctrl_rt->update_streaming(ctrl_rt);
                rt->stream_state = STREAM_DISABLED;
        }
 }
@@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
        unsigned int total_length = 0;
        struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
        struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
-       u32 *src = (u32 *) urb->buffer;
+       u32 *src = NULL;
        u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
                        * (alsa_rt->frame_bits >> 3));
        u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
                else
                        frame_count = 0;
 
-               src = (u32 *) (urb->buffer + total_length);
+               if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+                       src = (u32 *) (urb->buffer + total_length);
+               else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+                       src = (u32 *) (urb->buffer - 1 + total_length);
+               else
+                       return;
                src++; /* skip leading 4 bytes of every packet */
                total_length += urb->packets[i].length;
                for (frame = 0; frame < frame_count; frame++) {
@@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
                        * (alsa_rt->frame_bits >> 3));
        u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
                        * (alsa_rt->frame_bits >> 3));
-       u32 *dest = (u32 *) urb->buffer;
+       u32 *dest;
        int bytes_per_frame = alsa_rt->channels << 2;
 
+       if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+               dest = (u32 *) (urb->buffer - 1);
+       else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+               dest = (u32 *) (urb->buffer);
+       else {
+               snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+               return;
+       }
+
        for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
                /* at least 4 header bytes for valid packet.
                 * after that: 32 bits per sample for analog channels */
@@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
                /* all substreams closed? if so, stop streaming */
                if (!rt->playback.instance && !rt->capture.instance) {
                        usb6fire_pcm_stream_stop(rt);
-                       rt->rate = -1;
+                       rt->rate = ARRAY_SIZE(rates);
                }
        }
        mutex_unlock(&rt->stream_mutex);
@@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
        struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
        struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
        struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
-       int i;
        int ret;
 
        if (rt->panic)
@@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
        sub->period_off = 0;
 
        if (rt->stream_state == STREAM_DISABLED) {
-               for (i = 0; i < ARRAY_SIZE(rates); i++)
-                       if (alsa_rt->rate == rates[i]) {
-                               rt->rate = i;
+               for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)
+                       if (alsa_rt->rate == rates[rt->rate])
                                break;
-                       }
-               if (i == ARRAY_SIZE(rates)) {
+               if (rt->rate == ARRAY_SIZE(rates)) {
                        mutex_unlock(&rt->stream_mutex);
                        snd_printk("invalid rate %d in prepare.\n",
                                        alsa_rt->rate);
@@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
 
        rt->chip = chip;
        rt->stream_state = STREAM_DISABLED;
-       rt->rate = -1;
+       rt->rate = ARRAY_SIZE(rates);
        init_waitqueue_head(&rt->stream_wait_queue);
        mutex_init(&rt->stream_mutex);
 
index 97724d8fa9f689fd5cc863cef980b97cdd8de4a5..8beb77563da25298c547c07636a494cca2f679dd 100644 (file)
@@ -100,19 +100,17 @@ config SND_USB_US122L
 
 config SND_USB_6FIRE
         tristate "TerraTec DMX 6Fire USB"
-        depends on EXPERIMENTAL
         select FW_LOADER
+        select BITREVERSE
         select SND_RAWMIDI
         select SND_PCM
         help
           Say Y here to include support for TerraTec 6fire DMX USB interface.
 
           You will need firmware files in order to be able to use the device
-          after it has been coldstarted. This driver currently does not support
-          firmware loading for all devices. If you own such a device,
-          you could start windows and let the windows driver upload
-          the firmware. As long as you do not unplug your device from power,
-          it should be usable.
+          after it has been coldstarted. An install script for the firmware
+          and further help can be found at
+          http://sixfireusb.sourceforge.net
 
 endif  # SND_USB
 
index 7754a10345451109a9ff9bd03d271148160861b9..075195e8661a0f538343bc482db9e721b51dda18 100644 (file)
@@ -104,6 +104,15 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
        int err;
        unsigned char data;
        struct usb_device *dev = chip->dev;
+       struct uac_clock_source_descriptor *cs_desc =
+               snd_usb_find_clock_source(chip->ctrl_intf, source_id);
+
+       if (!cs_desc)
+               return 0;
+
+       /* If a clock source can't tell us whether it's valid, we assume it is */
+       if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID))
+               return 1;
 
        err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
@@ -114,7 +123,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
        if (err < 0) {
                snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
                           __func__, source_id);
-               return err;
+               return 0;
        }
 
        return !!data;
index 343ec2d9ee6675ff2bea1016188a840418f4aadc..58030176f0083deef38d3d37b2ea46775cce58a0 100644 (file)
@@ -8,7 +8,7 @@
 #ifdef HW_CONST_DEBUG
 #define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args)
 #else
-#define hwc_debug(fmt, args...) /**/
+#define hwc_debug(fmt, args...) do { } while(0)
 #endif
 
 #endif /* __USBAUDIO_DEBUG_H */
index f079b5e2ab287cd0d726216bd6b656fd15c2e6d6..8d042dce0d16a0a2d26efffe2cceb9279f0300f9 100644 (file)
@@ -30,6 +30,7 @@
 #include "helper.h"
 #include "debug.h"
 #include "clock.h"
+#include "format.h"
 
 /*
  * parse the audio format type I descriptor
index 6ec33b62e6cf255b712c4ca5e470ffcd224e7379..eab06edcc9b73f8a56f0ec2bac616f3a8d535073 100644 (file)
@@ -1097,11 +1097,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                append_ctl_name(kctl, control == UAC_FU_MUTE ?
                                " Switch" : " Volume");
                if (control == UAC_FU_VOLUME) {
-                       kctl->tlv.c = mixer_vol_tlv;
-                       kctl->vd[0].access |= 
-                               SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-                               SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
                        check_mapped_dB(map, cval);
+                       if (cval->dBmin < cval->dBmax) {
+                               kctl->tlv.c = mixer_vol_tlv;
+                               kctl->vd[0].access |= 
+                                       SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+                       }
                }
                break;
 
index 73dcc8256bc0abbeeb2ebed24957e5ae7912b31d..9146cffa6ede3096b24eae718935226880530a25 100644 (file)
@@ -61,6 +61,7 @@ static const struct rc_config {
        { 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, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
+       { USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
@@ -188,6 +189,12 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              !value, 0, NULL, 0, 100);
+       /* USB X-Fi S51 Pro */
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
+               err = snd_usb_ctl_msg(mixer->chip->dev,
+                             usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             !value, 0, NULL, 0, 100);
        else
                err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
@@ -234,9 +241,13 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
                /* USB X-Fi S51 doesn't have a CMSS LED */
                if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
                        continue;
+               /* USB X-Fi S51 Pro doesn't have one either */
+               if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0)
+                       continue;
                if (i > 1 && /* Live24ext has 2 LEDs only */
                        (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
                         mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
                         mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
@@ -512,6 +523,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
        case USB_ID(0x041e, 0x3020):
        case USB_ID(0x041e, 0x3040):
        case USB_ID(0x041e, 0x3042):
+       case USB_ID(0x041e, 0x30df):
        case USB_ID(0x041e, 0x3048):
                err = snd_audigy2nx_controls_create(mixer);
                if (err < 0)
index c66d3f64dcf89f6b5f0f59dea6cdbfd2b412bbb9..78792a8900c3c575904f9d712e0bb96b224ac2a1 100644 (file)
@@ -1651,6 +1651,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0127),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "GR-55", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
@@ -1953,7 +1979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       USB_DEVICE(0x0763, 0x2080),
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "M-Audio", */
                /* .product_name = "Fast Track Ultra", */
@@ -2020,7 +2046,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       USB_DEVICE(0x0763, 0x2081),
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "M-Audio", */
                /* .product_name = "Fast Track Ultra 8R", */
@@ -2179,6 +2205,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* KORG devices */
+{
+       USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "KORG, Inc.",
+               /* .product_name = "PANDORA PX5D", */
+               .ifnum = 3,
+               .type = QUIRK_MIDI_STANDARD_INTERFACE,
+       }
+},
+
 /* AKAI devices */
 {
        USB_DEVICE(0x09e8, 0x0062),
@@ -2331,6 +2368,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 },
 
 /* Native Instruments MK2 series */
+{
+       /* Komplete Audio 6 */
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor = 0x17cc,
+       .idProduct = 0x1000,
+},
 {
        /* Traktor Audio 6 */
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
index 1b94ec3a3368bd01c622f686edc74957cee4d36d..bd13d7257240528f97cc2a0caf5b134a0b9d58ac 100644 (file)
@@ -540,6 +540,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
                /* Access Music VirusTI Desktop */
                return snd_usb_accessmusic_boot_quirk(dev);
 
+       case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */
        case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
        case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
                return snd_usb_nativeinstruments_boot_quirk(dev);
index 207dee5c5b163fd51ceafbb6b171df9c0708893f..0c542563ea6c2206aecc883c0be8a70dfad74919 100644 (file)
@@ -35,15 +35,21 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
                                  -e s/sh[234].*/sh/ )
 
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
+
 # Additional ARCH settings for x86
 ifeq ($(ARCH),i386)
         ARCH := x86
 endif
 ifeq ($(ARCH),x86_64)
-       RAW_ARCH := x86_64
-        ARCH := x86
-       ARCH_CFLAGS := -DARCH_X86_64
-       ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
+       ARCH := x86
+       IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
+       ifeq (${IS_X86_64}, 1)
+               RAW_ARCH := x86_64
+               ARCH_CFLAGS := -DARCH_X86_64
+               ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
+       endif
 endif
 
 #
@@ -119,8 +125,6 @@ lib = lib
 
 export prefix bindir sharedir sysconfdir
 
-CC = $(CROSS_COMPILE)gcc
-AR = $(CROSS_COMPILE)ar
 RM = rm -f
 MKDIR = mkdir
 FIND = find
index 17d1dcb3c66771cb1d7603cff6a5ed981d44ca69..416538248a4bb04eaf2e28a1a2f58f062e6372fc 100644 (file)
@@ -163,6 +163,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
        struct perf_event_attr *attr = &evsel->attr;
        int track = !evsel->idx; /* only the first counter needs these */
 
+       attr->inherit           = !no_inherit;
        attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
                                  PERF_FORMAT_TOTAL_TIME_RUNNING |
                                  PERF_FORMAT_ID;
@@ -251,6 +252,9 @@ static void open_counters(struct perf_evlist *evlist)
 {
        struct perf_evsel *pos;
 
+       if (evlist->cpus->map[0] < 0)
+               no_inherit = true;
+
        list_for_each_entry(pos, &evlist->entries, node) {
                struct perf_event_attr *attr = &pos->attr;
                /*
@@ -271,8 +275,7 @@ static void open_counters(struct perf_evlist *evlist)
 retry_sample_id:
                attr->sample_id_all = sample_id_all_avail ? 1 : 0;
 try_again:
-               if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
-                                    !no_inherit) < 0) {
+               if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES) {
index e2109f9b43eb3ed99a5239805087277b229739d3..03f0e45f1479c2fab31de2624d69d95458886157 100644 (file)
@@ -167,16 +167,17 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
                attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
                                    PERF_FORMAT_TOTAL_TIME_RUNNING;
 
+       attr->inherit = !no_inherit;
+
        if (system_wide)
-               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false);
+               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
 
-       attr->inherit = !no_inherit;
        if (target_pid == -1 && target_tid == -1) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
 
-       return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false);
+       return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
 }
 
 /*
index 1b2106c58f660c83a858636df0862c458d127eb8..11e3c84583622bac20ed799cfab29e7066c6d6eb 100644 (file)
@@ -290,7 +290,7 @@ static int test__open_syscall_event(void)
                goto out_thread_map_delete;
        }
 
-       if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) {
+       if (perf_evsel__open_per_thread(evsel, threads, false) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
                         strerror(errno));
@@ -303,7 +303,7 @@ static int test__open_syscall_event(void)
        }
 
        if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
-               pr_debug("perf_evsel__open_read_on_cpu\n");
+               pr_debug("perf_evsel__read_on_cpu\n");
                goto out_close_fd;
        }
 
@@ -365,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void)
                goto out_thread_map_delete;
        }
 
-       if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) {
+       if (perf_evsel__open(evsel, cpus, threads, false) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
                         strerror(errno));
@@ -418,7 +418,7 @@ static int test__open_syscall_event_on_all_cpus(void)
                        continue;
 
                if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
-                       pr_debug("perf_evsel__open_read_on_cpu\n");
+                       pr_debug("perf_evsel__read_on_cpu\n");
                        err = -1;
                        break;
                }
@@ -529,7 +529,7 @@ static int test__basic_mmap(void)
 
                perf_evlist__add(evlist, evsels[i]);
 
-               if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) {
+               if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
                        pr_debug("failed to open counter: %s, "
                                 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
                                 strerror(errno));
index fc1273e976c58f4c25d6321abf578392ba1126ad..7e3d6e310bf839f09e5d6afed39c8c1530a13807 100644 (file)
@@ -845,9 +845,10 @@ static void start_counters(struct perf_evlist *evlist)
                }
 
                attr->mmap = 1;
+               attr->inherit = inherit;
 try_again:
                if (perf_evsel__open(counter, top.evlist->cpus,
-                                    top.evlist->threads, group, inherit) < 0) {
+                                    top.evlist->threads, group) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES) {
index 9fea75535221a256aea8dcd344f85e463779a80f..96bee5c46008450519a67785c21e4f0481d1e6c4 100644 (file)
@@ -13,7 +13,7 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 {
        FILE *fp;
        char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
-       char *token, *saved_ptr;
+       char *token, *saved_ptr = NULL;
        int found = 0;
 
        fp = fopen("/proc/mounts", "r");
index d852cefa20def5ff48665e7ef44bc842093f6f49..45da8d186b492d4f82512862aef867acd4649f09 100644 (file)
@@ -12,6 +12,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "util.h"
+#include "debug.h"
 
 #include <sys/mman.h>
 
@@ -250,15 +251,19 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
        return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
-static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot,
-                              int mask, int fd)
+static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel,
+                              int cpu, int prot, int mask, int fd)
 {
        evlist->mmap[cpu].prev = 0;
        evlist->mmap[cpu].mask = mask;
        evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
                                      MAP_SHARED, fd, 0);
-       if (evlist->mmap[cpu].base == MAP_FAILED)
+       if (evlist->mmap[cpu].base == MAP_FAILED) {
+               if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit)
+                       ui__warning("Inherit is not allowed on per-task "
+                                   "events using mmap.\n");
                return -1;
+       }
 
        perf_evlist__add_pollfd(evlist, fd);
        return 0;
@@ -312,7 +317,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
                                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
                                                  FD(first_evsel, cpu, 0)) != 0)
                                                goto out_unmap;
-                               } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0)
+                               } else if (__perf_evlist__mmap(evlist, evsel, cpu,
+                                                              prot, mask, fd) < 0)
                                        goto out_unmap;
 
                                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
index 662596afd7f1d49fccaeb8c95ee7c8c64748b8c9..d6fd59beb860739aea40e1b4052f6eda1a741996 100644 (file)
@@ -175,7 +175,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 }
 
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                             struct thread_map *threads, bool group, bool inherit)
+                             struct thread_map *threads, bool group)
 {
        int cpu, thread;
        unsigned long flags = 0;
@@ -192,19 +192,6 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 
        for (cpu = 0; cpu < cpus->nr; cpu++) {
                int group_fd = -1;
-               /*
-                * Don't allow mmap() of inherited per-task counters. This
-                * would create a performance issue due to all children writing
-                * to the same buffer.
-                *
-                * FIXME:
-                * Proper fix is not to pass 'inherit' to perf_evsel__open*,
-                * but a 'flags' parameter, with 'group' folded there as well,
-                * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if
-                * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is
-                * set. Lets go for the minimal fix first tho.
-                */
-               evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit;
 
                for (thread = 0; thread < threads->nr; thread++) {
 
@@ -253,7 +240,7 @@ static struct {
 };
 
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                    struct thread_map *threads, bool group, bool inherit)
+                    struct thread_map *threads, bool group)
 {
        if (cpus == NULL) {
                /* Work around old compiler warnings about strict aliasing */
@@ -263,19 +250,19 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
        if (threads == NULL)
                threads = &empty_thread_map.map;
 
-       return __perf_evsel__open(evsel, cpus, threads, group, inherit);
+       return __perf_evsel__open(evsel, cpus, threads, group);
 }
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-                            struct cpu_map *cpus, bool group, bool inherit)
+                            struct cpu_map *cpus, bool group)
 {
-       return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
+       return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
 }
 
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-                               struct thread_map *threads, bool group, bool inherit)
+                               struct thread_map *threads, bool group)
 {
-       return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
+       return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
 }
 
 static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
index 6710ab538342fe1d5970c812423908ddec3ee5a7..f79bb2c09a6cbea510e31d260a1fabb778e13950 100644 (file)
@@ -81,11 +81,11 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
-                            struct cpu_map *cpus, bool group, bool inherit);
+                            struct cpu_map *cpus, bool group);
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
-                               struct thread_map *threads, bool group, bool inherit);
+                               struct thread_map *threads, bool group);
 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                    struct thread_map *threads, bool group, bool inherit);
+                    struct thread_map *threads, bool group);
 
 #define perf_evsel__match(evsel, t, c)         \
        (evsel->attr.type == PERF_TYPE_##t &&   \
index a9f2d7e1204d1655b14b99cafb06d08d5046d8a6..f5e38451fdc505e329ac77415e9e8aba5fbe7ebb 100644 (file)
@@ -498,11 +498,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
        struct cpu_map *cpus = NULL;
        struct thread_map *threads = NULL;
        PyObject *pcpus = NULL, *pthreads = NULL;
-       int group = 0, overwrite = 0;
-       static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL};
+       int group = 0, inherit = 0;
+       static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL};
 
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
-                                        &pcpus, &pthreads, &group, &overwrite))
+                                        &pcpus, &pthreads, &group, &inherit))
                return NULL;
 
        if (pthreads != NULL)
@@ -511,7 +511,8 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
        if (pcpus != NULL)
                cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
 
-       if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) {
+       evsel->attr.inherit = inherit;
+       if (perf_evsel__open(evsel, cpus, threads, group) < 0) {
                PyErr_SetFromErrno(PyExc_OSError);
                return NULL;
        }
index 8c17a8730e4a36a9923537f79466c3793fd06559..15633d6081332f0204acc978974ff6deec8d2375 100644 (file)
@@ -256,10 +256,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
                         int refresh)
 {
        struct objdump_line *pos, *n;
-       struct annotation *notes = symbol__annotation(sym);
+       struct annotation *notes;
        struct annotate_browser browser = {
                .b = {
-                       .entries = &notes->src->source,
                        .refresh = ui_browser__list_head_refresh,
                        .seek    = ui_browser__list_head_seek,
                        .write   = annotate_browser__write,
@@ -281,6 +280,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
 
        ui_helpline__push("Press <- or ESC to exit");
 
+       notes = symbol__annotation(sym);
+
        list_for_each_entry(pos, &notes->src->source, node) {
                struct objdump_line_rb_node *rbpos;
                size_t line_len = strlen(pos->line);
@@ -291,6 +292,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
                rbpos->idx = browser.b.nr_entries++;
        }
 
+       browser.b.entries = &notes->src->source,
        browser.b.width += 18; /* Percentage */
        ret = annotate_browser__run(&browser, evidx, refresh);
        list_for_each_entry_safe(pos, n, &notes->src->source, node) {
index 798efdca3eadd9fe89b84157ceba5c56a8d5dcb2..5d767c622dfc1f862fb747ababa610e9031944c8 100644 (file)
@@ -851,7 +851,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
                        goto out_free_stack;
                case 'a':
                        if (browser->selection == NULL ||
-                           browser->selection->map == NULL ||
+                           browser->selection->sym == NULL ||
                            browser->selection->map->dso->annotate_warned)
                                continue;
                        goto do_annotate;